clickhouse函数介绍

clickhouse官方提供了许多的函数,包括常规的数学函数,聚合函数,时间函数,逻辑函数,比较函数等等,关于官方的函数可以在官方文档中查看:

官方文档

当然随着clickhouse的流行,国内也有不少的博主已经开始介绍函数的使用:

clickhouse function

clickhouse高阶函数

clickhouse详细函数介绍

clickhouse还支持一些自定义的逻辑函数:

例如:

select arrayFilter(x -> x = 10,[1,2,3,4,5,10]);

返回的结果为:

[10]

类似的函数还有多个,可以传入lambda表达式,上述的函数为过滤数组中等于10的数。

clickhouse自定义函数

clickhouse除了上述的函数外,修改源码可以编写自己需要的函数,首先来看源码中一个简单的函数的实现过程。注:源码基于19.5.3.1版本。

  • 源码分析sleep()函数:

自定义函数存在于src文件夹下的Functions文件夹中。

sleep.h文件:

#include <unistd.h>
#include <Functions/IFunction.h>
#include <Functions/FunctionHelpers.h>
#include <Columns/ColumnConst.h>
#include <DataTypes/DataTypesNumber.h>
#include <Common/FieldVisitors.h>
#include <IO/WriteHelpers.h>namespace DB
{namespace ErrorCodes
{extern const int TOO_SLOW;extern const int ILLEGAL_COLUMN;extern const int BAD_ARGUMENTS;
}/** sleep(seconds) - the specified number of seconds sleeps each block.*/enum class FunctionSleepVariant
{PerBlock,PerRow
};template <FunctionSleepVariant variant>
class FunctionSleep : public IFunction
{
public:static constexpr auto name = variant == FunctionSleepVariant::PerBlock ? "sleep" : "sleepEachRow";static FunctionPtr create(const Context &){return std::make_shared<FunctionSleep<variant>>();}/// Get the name of the function.String getName() const override{return name;}/// Do not sleep during query analysis.bool isSuitableForConstantFolding() const override{return false;}size_t getNumberOfArguments() const override{return 1;}DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override{WhichDataType which(arguments[0]);if (!which.isFloat()&& !which.isNativeUInt())throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName() + ", expected Float64",ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);return std::make_shared<DataTypeUInt8>();}void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override{const IColumn * col = block.getByPosition(arguments[0]).column.get();if (!col->isColumnConst())throw Exception("The argument of function " + getName() + " must be constant.", ErrorCodes::ILLEGAL_COLUMN);Float64 seconds = applyVisitor(FieldVisitorConvertToNumber<Float64>(), static_cast<const ColumnConst &>(*col).getField());if (seconds < 0)throw Exception("Cannot sleep negative amount of time (not implemented)", ErrorCodes::BAD_ARGUMENTS);size_t size = col->size();/// We do not sleep if the block is empty.if (size > 0){/// When sleeping, the query cannot be cancelled. For abitily to cancel query, we limit sleep time.if (seconds > 3.0)   /// The choice is arbitrarythrow Exception("The maximum sleep time is 3 seconds. Requested: " + toString(seconds), ErrorCodes::TOO_SLOW);UInt64 useconds = seconds * (variant == FunctionSleepVariant::PerBlock ? 1 : size) * 1e6;::usleep(useconds);}/// convertToFullColumn needed, because otherwise (constant expression case) function will not get called on each block.block.getByPosition(result).column = block.getByPosition(result).type->createColumnConst(size, 0u)->convertToFullColumnIfConst();}
};}

sleep.cpp文件:

#include <Functions/sleep.h>
#include <Functions/FunctionFactory.h>namespace DB
{void registerFunctionSleep(FunctionFactory & factory)
{factory.registerFunction<FunctionSleep<FunctionSleepVariant::PerBlock>>();
}}

分析:

cpp文件中需要将函数注册即registerFunctionSleep函数。h文件中需要实现IFunction中的一些方法,主要有getName函数名,getNumberOfArguments传入参数,getReturnTypeImpl返回的类型,executeImpl为具体的执行过程,官方的sleep函数的实现还是比较简单明了的,主要部分函数的类型,在自定义中需要一一对应。

关于isSuitableForConstantFolding,sleep函数调用时是个反例,返回为false,类似于分析时是否应该评估该函数,具体的还需要再研究,以下是官方的解析,在IFunction.h中:

/** Should we evaluate this function while constant folding, if arguments are constants?* Usually this is true. Notable counterexample is function 'sleep'.* If we will call it during query analysis, we will sleep extra amount of time.*/
virtual bool isSuitableForConstantFolding() const { return true; }
  • 简单的无参数自定义函数sayHello():

先看执行效果:

select sayHello();

返回结果为:

hello clickhouse by iceyung test!

具体的实现代码:

sayHello.h:

#include <Functions/IFunction.h>
#include <Functions/FunctionHelpers.h>
#include <DataTypes/DataTypeString.h>
#include <DataTypes/DataTypesNumber.h>namespace DB
{class FunctionSayHello : public IFunction{public:static constexpr auto name = "sayHello";static FunctionPtr create(const Context &){return std::make_shared<FunctionSayHello>();}/// Get the name of the function.String getName() const override{return name;}size_t getNumberOfArguments() const override{return 0;}DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override{return std::make_shared<DataTypeString>();}void executeImpl(Block & block, const ColumnNumbers & /*arguments*/, size_t result, size_t /*input_rows_count*/) override{block.getByPosition(result).column = DataTypeString().createColumnConst(1, "hello clickhouse by iceyung test!");}};}

sayHello.cpp:

#include <Functions/sayHello.h>
#include <Functions/FunctionFactory.h>namespace DB
{
void registerFunctionSayHello(FunctionFactory & factory)
{factory.registerFunction<FunctionSayHello>(FunctionFactory::CaseInsensitive);
}}

简单分析:

cpp中registerFunctionSayHello注册函数,registerFunctionsString.cpp中注册该函数,当然你也可以在其它的文件中注册,注册比较简单,直接仿照正常的进行注册即可,此处不再赘述。

注意返回参数和返回类型的问题,返回的类型可在src的DataTypes中找到,最终executeImpl返回的类型为ColumnPtr类型,不能简单的输出,具体也可以看目前已有的函数的样例,找到符合自己的参数。

  • 有参数自定义函数sayHello(String str):

分析同上,将传入的参数打印出,效果如下:

select sayHello('clickhouse args');

返回:

hello clickhouse args by iceyung test!

主要为sayHello.h修改,如下:

#include <Functions/IFunction.h>
#include <Functions/FunctionHelpers.h>
#include <DataTypes/DataTypeString.h>
#include <DataTypes/DataTypesNumber.h>namespace DB
{class FunctionSayHello : public IFunction{public:static constexpr auto name = "sayHello";static FunctionPtr create(const Context &){return std::make_shared<FunctionSayHello>();}/// Get the name of the function.String getName() const override{return name;}size_t getNumberOfArguments() const override{return 1;}DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override{WhichDataType which(arguments[0]);if (!which.isString())throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName() + ", expected String",ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);return std::make_shared<DataTypeString>();}void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override{const auto & col = static_cast<const ColumnConst *>(block.getByPosition(arguments[0]).column.get())->getValue<String>();block.getByPosition(result).column = DataTypeString().createColumnConst(input_rows_count, "hello " + col  + " by iceyung test!");}};}

当出错了或者参数类型不对时,可提示错误:

sql> select sayHello()
[2020-03-01 23:47:56] Code: 42, e.displayText() = DB::Exception: Number of arguments for function sayHello doesn't match: passed 0, should be 1 (version 19.5.3.1)
sql> select sayHello(1)
[2020-03-01 23:48:04] Code: 43, e.displayText() = DB::Exception: Illegal type UInt8 of argument of function sayHello, expected String (version 19.5.3.1)

注意:添加新的文件后需要重新Cmake编译才能正常获取编译的内容。

clickhouse源码:函数分析和自定义函数UDF相关推荐

  1. 2022-10-24 ClickHouse 源码解析-查询引擎经典理论

    ClickHouse 源码解析: 综述 ClickHouse 源码解析: MergeTree Write-Path ClickHouse 源码解析: MergeTree Read-Path Click ...

  2. boost源码剖析之:泛型函数指针类boost::function(rev#3)

    boost源码剖析之:泛型函数指针类boost::function(rev#3) 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba)   Note: 并非新作,03年曾放 ...

  3. 阅读react-redux源码(二) - createConnect、match函数的实现

    阅读react-redux源码 - 零 阅读react-redux源码 - 一 阅读react-redux源码(二) - createConnect.match函数的实现 上一节看了Provider组 ...

  4. VB 源码 删除重复行程序 函数

    代码如下: '通过VB脚本改写而成,可以直接使用  放入程序中可以直接使用 '删除重复行程序 ' 'foutPathName  为待删除的文本文件.注:输入文件不能有空行,别外扩展名必需为.TXT ' ...

  5. ❤️缓存集合(一级缓存、二级缓存、缓存原理以及自定义缓存—源码+图文分析,建议收藏) ❤️

    ❤️缓存集合(一级缓存.二级缓存.缓存原理以及自定义缓存-源码+图文分析,建议收藏) ❤️ 查询 : 连接数据库 ,耗资源!一次查询的结果,给他暂存在一个可以直接取到的地方!--> 内存 : 缓 ...

  6. php nl2p,PHP函数nl2br()与自定义函数nl2p()换行用法分析,nl2brnl2p_PHP教程

    PHP函数nl2br()与自定义函数nl2p()换行用法分析,nl2brnl2p 本文实例讲述了PHP函数nl2br()与自定义函数nl2p()换行用法.分享给大家供大家参考,具体如下: 使用情景 很 ...

  7. php wrappers,浅谈PHP源码六:关于stream_get_wrappers函数

    这篇文章主要介绍了关于浅谈PHP源码六:关于stream_get_wrappers函数,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 stream_get_wrappers (PHP ...

  8. Toast源码深度分析

    目录介绍 1.最简单的创建方法 1.1 Toast构造方法 1.2 最简单的创建 1.3 简单改造避免重复创建 1.4 为何会出现内存泄漏 1.5 吐司是系统级别的 2.源码分析 2.1 Toast( ...

  9. Map和Set,简单模拟实现哈希表以及哈希表部分底层源码的分析

    目录 Map和Set的简单介绍 降低哈希冲突发生的概率以及当冲突发生时如何解决哈希冲突 简单模拟实现哈希表--1.key为整形:2.key为引用类型 哈希表部分底层源码的分析 1.Map和Set的简单 ...

最新文章

  1. 一段使用cURL实现的网页抓取源码,支持POST,Cookies,代理,自定义头.
  2. 【鸿蒙 HarmonyOS】UI 组件 ( 进度条 ProgressBar 和 RoundProgressBar 组件 )
  3. Jzoj3162 旋转
  4. 面试官系统精讲Java源码及大厂真题 - 43 ThreadLocal 源码解析
  5. 【OOAD】OOAD概述
  6. 安卓反编译揭秘,伪加密APK文件如何被破坏
  7. Lync2010标准版部署
  8. jquery中filter(fn)的使用研究
  9. iOS 动态添加属性方法
  10. spring事务传播特性_关于spring的事务的传播propagation特性
  11. Php clearstatcache() 函数详解
  12. Graphical Model(概率图模型)的浅见
  13. java项目汇率管理模板_项目管理文件夹模板
  14. 安全测试工具APPScan下载安装及简单使用
  15. ARP协议,ARP攻击的原理,网络执法官的具体实现
  16. 服务器数字显示器,数字显示器
  17. go语言基础(一)之文件读写
  18. layer UI学习
  19. R forcast auto arima用法
  20. Numpy:随机抽样

热门文章

  1. swagger在VS2019 .net core2.2中的使用,及报错undefined /swagger/v1/swagger.json的解决办法
  2. 【ida】IDA工具常见利用
  3. 工具使用 - IDA使用
  4. vue简易微前端项目搭建(一):项目背景及简介
  5. 一分钟了解矩阵、方阵、对角矩阵、单位矩阵之间的关系
  6. android选择头像弹窗,仿QQ的头像选择弹出的对话框
  7. python怎样分析文献综述怎么写_本科毕业论文如何撰写文献综述
  8. Stm32f407zgt6 143引脚PDR_ON 的注意事项
  9. python tk Lable
  10. 如何优雅的生活 --工作后