ClickHouse自定义函数实例教程

ClickHouse v21.10 版本开始支持期待已久的特性————UDF(User defined function)。UDF通常通过SQL扩展数据库的能力,大多数采用SQL语句,但有些数据库还支持UDAF(user-defined aggregate function) 和UDTF(user defined table-generating function)。ClickHouse UDF通过lambda表达式定义,有参数、常量、操作符或其他函数调用组成。首先我们了解其语法,然后通过示例进行学习。

语法

CREATE FUNCTION name [ON CLUSTER cluster] AS (parameter0, ...) -> expression
  • 函数名称必须唯一,不能和系统函数冲突
  • 不支持递归调用
  • 所有函数使用的变量必须在参数列表中指定

简单示例:

CREATE FUNCTION linear_equation AS (x, k, b) -> k*x + b;
SELECT number, linear_equation(number, 2, 1) FROM numbers(3);

返回结果:

┌─number─┬─plus(multiply(2, number), 1)─┐
│      0 │                            1 │
│      1 │                            3 │
│      2 │                            5 │
└────────┴──────────────────────────────┘

上面示例来自官方文档,比较简单。下面的示例稍微复杂点,实用性更强。

实战案例

首先基于GenerateRandom Table Engine定义表,产生演示数据,后面自定义函数该表测试进行验证。

CREATE TABLE udf_rand
(
 `id` UInt32,
 `a` String,
 `b` String
) ENGINE = GenerateRandom(1, 15, 5);

定义表udf_rand,包括三个字段。随机表引擎的语法:

ENGINE = GenerateRandom([random_seed [,max_string_length [,max_array_length]]])

执行下面语句进行验证:


SELECT *
FROM udf_rand
LIMIT 10

Query id: 9b9139d7-c306-4f56-a071-54833370dd38

┌─────────id─┬─a───────────────┬─b──────────────┐
│ 4107652264 │ =@ep]Vw~        │ TlL#0FWJUeS}   │
│  652895061 │ b'zQI ,~6xGwg|  │                │
│ 2319105779 │ "M2e^ipx|,=a5N  │ 0Z3|ht_E8Ct    │
│ 1835960063 │                 │ A]BT&b!M-      │
│  730412674 │ 'l`*f{adU64F    │ Dj7peUH{TT2#sl │
│ 1014544494 │ '%Y~t99x]lB}    │ `K8P_@}a `kWg  │
│ 2554847195 │                 │ dof*O          │
│ 1382038526 │ wkDK            │ r;5qbK&t+      │
│  153951766 │ `xbguF(N3^n2?/; │ 4?a]2          │
│   85697048 │ 3&}|k3Igp@s=f,w │ _Kxs~%         │
└────────────┴─────────────────┴────────────────┘

下面基于uniq函数,定义两列唯一值数量之和的函数:

CREATE FUNCTION uniqTotal as (a, b) -> uniq(a) + uniq(b)

调用函数进行测试:


SELECT uniqTotal(a, b) AS total
FROM
(
    SELECT *
    FROM udf_rand
    LIMIT 10000
)

Query id: 5489d766-1b8c-42e7-9ded-acf11a125517

┌─total─┐
│ 17671 │
└───────┘

函数通过更简洁的方式实现了 SELECT uniq(x) + uniq(y)。下面再看一个示例,如何通过UDF简化复杂查询。

下面函数返回数组中最大元素,数据来自上面定义的测试表udf_rand,数据量有参数指定:

CREATE FUNCTION reduce_array_max AS size -> (
SELECT arrayReduce('max', grouped_ids)
FROM
(
SELECT arrayMap(x -> x, groupArray(id)) AS grouped_ids
FROM (SELECT id FROM udf_rand LIMIT size))
);

通过调用reduce_array_max函数,通过参数指定测试数据量。注意,函数定义包括了子查询,函数返回值也是子查询,因此select函数子句增加别名,否则返回列为:subquery1。


SELECT reduce_array_max(10000) AS reduced

Query id: fe927d4c-4431-4269-a3f8-13ff1eb1923b

┌────reduced─┐
│ 4294530630 │
└────────────┘

总结

定义UDF有下列优势:

  • 通过函数封装复杂代码,可以在多个应用场景中复用
  • 通过给定输入参数,可以简化测试
  • 修改函数定义自动反应至所有函数调用,避免重复维护

UDF可以消除重复工作,虽然强大,也不要过度滥用。

### ClickHouse 数组聚合函数 #### 语法说明 在 ClickHouse 中,数组聚合函数用于处理数组类型的列。常见的数组聚合函数有 `groupArray`、`arrayReduce` 和其他特定于数组的操作。这些函数能够有效地收集和转换数据。 对于 `groupArray` 函数而言,该函数会将一组值聚合成一个数组[^1]: ```sql SELECT groupArray(column_name) FROM table_name; ``` 此语句将会创建一个新的数组,其中包含了来自指定列的所有非重复项。 另一个重要的函数是 `arrayReduce`,它可以应用各种内置或自定义的聚合逻辑到输入数组上: ```sql SELECT arrayReduce('aggFunction', arr_column) AS result FROM table_name; ``` 这里 `'aggFunction'` 是指具体的聚合操作名称,比如求和 (`sum`) 或者平均数 (`avg`) 等;而 `arr_column` 则是要被聚合处理的数组型态字段。 #### 使用实例 下面给出几个具体的应用场景来展示如何利用上述提到的一些功能特性: ##### 场景一:获取每类商品销售记录中的价格列表 假设有一个电商数据库表 `sales_records` 记录着每次交易的商品 ID 及对应的价格,则可以通过如下 SQL 查询获得按类别分组后的各条目售价集合: ```sql SELECT product_id, groupArray(price) as prices FROM sales_records GROUP BY product_id; ``` 这将返回每一类产品所涉及的不同售卖金额组成的序列。 ##### 场景二:统计某段时间内每天访问网站用户的唯一 IP 地址数目变化趋势图 给定一张日志表 `web_visits_log` ,里面存有关于访客IP地址的信息以及他们浏览网页的时间戳。为了绘制每日独立访客增长曲线,可采用下述方式提取所需统计数据: ```sql WITH daily_unique_ips AS ( SELECT toStartOfDay(timestamp) date, uniqExact(ip_address) count_of_uniq_ip_per_day FROM web_visits_log GROUP BY timestamp::date ) SELECT date, sum(count_of_uniq_ip_per_day) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) cumulative_sum FROM daily_unique_ips; ``` 注意,在这个例子中虽然没有直接调用数组聚合函数,但是通过与其他标准聚合函数配合使用实现了类似的效果——累积计数器反映了随着时间推移累计了多少不同的 IP 进行过页面请求。 #### 性能优化建议 当涉及到大量数据时,合理设置参数可以帮助提高效率。例如调整 `max_rows_to_group_by` 参数以控制内存占用量,防止因过度消耗资源而导致性能下降。另外,尽可能早地过滤掉不必要的行也能显著减少后续阶段的工作负担。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值