clickhouse自定义函数的困惑

        近期遇到一个困惑的问题,自定义函数中,如果出现查询语句,则传递的参数,不能传递字段名,只能传递常量或者表达式,文档中也没有找到对应的解决办法。

        需求其实比较简单,查询的时候,要做一个“少数服从多数”的决定,在一行记录中,存在多个字段值是String类型,使用哪个字段值,取决于字段内容出现的频率次数最高的字符串,注意,这里是一行记录,可以理解成,一个数组字段类型,常规想法就是 select group by ,但是,就出现了开头说的问题,不能传递字段名称作为参数。

CREATE function my_count as (str1 ,str2 ,str3 )-> (
	SELECT max(element)
	from
	( 
	    SELECT
	    arrayJoin(array) AS element,
	    count(*) AS count
		FROM (
		    SELECT [str1,str2,str] AS array
		)
		where LENGTH(element)>0
		GROUP BY element
		ORDER BY count DESC
		limit 1
	) t	
)

        上述代码,传递常量是没有问题的,但是:

        select my_count(field1,field2,field3) as a from my_table

        就会报错,提示不支持字段作为参数

        后来,只能从文档的方法来入手,找内置的arry相关函数

        CREATE FUNCTION my_test as (arr) ->arrayReverseSort((m,n)->n, arrayMap(x->(x,countEqual(arr,x)),arrayDistinct(arr)))

        这里就很好解决了需求,不过,性能可能会低一点,起码先凑合着用着。

        arrayDistinct        表示数组的元素取唯一,去重。

        countEqual        表示计算元素在数组中出现的次数

        arrayMap        把统计元素个数映射成 (key,count)的格式,其中count就是计数

        arrayReverseSort        就是倒序,根据第2个参数(count)进行排序

在使用中 SELECT uniqTotal(['a','b','b','a','a'])[1].1 AS ele

其中[1]表示取数组的第一个元素,.1表示取key值,就是需求目标

完美解决,如果有更好的办法,麻烦留言告知,谢谢!

ClickHouse 支持自定义函数,可以通过以下步骤实现自定义函数: 1. 编写 C++ 或者其他语言的 UDF(User-Defined Function)代码,实现自定义函数的逻辑。 2. 将编写好的代码编译成动态链接库(.so文件),并将其上传到 ClickHouse 的服务器上。 3. 在 ClickHouse 中注册自定义函数,使其能够被查询语句调用。 以下是一个简单的例子,展示如何在 ClickHouse 中创建一个自定义函数: 1. 编写 C++ 代码: ```c++ #include <string> #include <cmath> #include <DB/Functions/IFunction.h> #include <DB/Functions/FunctionFactory.h> #include <DB/DataTypes/DataTypesNumber.h> namespace DB { class MySqrtFunction : public IFunction { public: static constexpr auto name = "mysqrt"; static FunctionPtr create(const Context & context) { return std::make_shared<MySqrtFunction>(); } String getName() const override { return name; } size_t getNumberOfArguments() const override { return 1; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { return std::make_shared<DataTypeFloat64>(); } void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) override { const auto & col = block.getByPosition(arguments[0]).column; auto & res = block.getByPosition(result).column; if (const auto * col_float = checkAndGetColumn<ColumnFloat64>(col.get())) { auto col_res = std::make_shared<ColumnFloat64>(); const auto & data = col_float->getData(); for (size_t i = 0, size = data.size(); i < size; ++i) { col_res->getData().push_back(std::sqrt(data[i])); } res = std::move(col_res); } else { throw Exception(name + " argument must be float64", ErrorCodes::LOGICAL_ERROR); } } }; void registerFunctionMySqrt(FunctionFactory & factory) { factory.registerFunction<MySqrtFunction>(); } } ``` 2. 将代码编译成动态链接库,例如: ``` g++ -std=c++17 -fPIC -shared my_sqrt.cpp -o my_sqrt.so ``` 3. 在 ClickHouse 中注册自定义函数,例如: ```sql CREATE FUNCTION mysqrt(x Float64) RETURNS Float64 SONAME 'my_sqrt.so'; ``` 现在,你就可以在查询语句中使用 `mysqrt` 函数了: ```sql SELECT mysqrt(4.0) ``` 输出结果为 2.0。 需要注意的是,自定义函数的性能可能会受到 ClickHouse 的限制,例如数据类型转换、内存分配等问题。因此,在实现自定义函数时,需要考虑这些限制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值