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可以消除重复工作,虽然强大,也不要过度滥用。