presto自定义函数
presto在0.251版本加入了自定义函数的能力,到了0.272版本有了一定的可用性,如果你在用的版本比我用的0.272高,最好是仔细看一下官方文档,因为0.272的文档中提到目前这个能力不完善,未来的配置和使用方式可能会发生改变
相关资料:
自定义函数catalog配置文档:https://prestodb.io/docs/0.272/admin/function-namespace-managers.html
自定义函数使用语法:https://prestodb.io/docs/0.272/sql/create-function.html
需要注意的是,presto的自定义函数和hive、spark的自定义函数在立意上不一样,非要找相同点的话,只能说presto的自定义函数类似于一进一出函数,但是出来的结果类型由于presto本身支持很多类型,所以结果可以是多元化的
presto的内建函数存储在presto.default
这个默认的存储空间中,比如当你调用最大值时,全链路为presto.default.max()
,可以简写为max()
,presto执行时自动补全存储空间,而其他的用户自定义函数需要自己准备存储空间也就是catalog,和其他大多数配置一样,目前只支持mysql的catalog
使用前需要做一个单独的配置,在presto的部署路径下新增etc/function-namespace/example.properties
文件,并写入如下内容,指向一个单独准备好的mysql
function-namespace-manager.name=mysql
database-url=jdbc:mysql://example.net:3306/database?user=root&password=password
function-namespaces-table-name=example_function_namespaces
functions-table-name=example_sql_functions
最后两个参数是两个数据表,如果不存在会自动创建
example_function_namespaces:用来存储自定义函数的命名空间,也就是就那些存储函数的库
example_sql_functions:用来存储自定义函数的功能消息
你可以在etc/function-namespace
文件夹下创建多个存储自定义函数用的catalog,并指向同一个mysql数据库,presto会自己处理对应的关系,保障每个catalog只会绑定自己的函数,不过新的命名空间需要你在mysql里面手动新增
INSERT INTO example_function_namespaces (catalog_name, schema_name) VALUES('example', 'test');
随后你就可以在presto中使用下面的语法创建自定义函数
CREATE [ OR REPLACE ] [TEMPORARY] FUNCTION
qualified_function_name (
parameter_name parameter_type
[, ...]
)
RETURNS return_type
[ COMMENT function_description ]
[ LANGUAGE [ SQL | identifier] ]
[ DETERMINISTIC | NOT DETERMINISTIC ]
[ RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
[ RETURN expression | EXTERNAL [ NAME identifier ] ]
REPLACE
:如果函数存在,则替换为当前设置的最新状态
TEMPORARY
:和hive语法一样是否临时函数
qualified_function_name
:函数名。如果建立的是一个永久函数,函数名称就必须写成catalog.命名空间.函数名
的格式,永久函数通过函数名称和参数类型列表进行唯一标识。临时函数都由函数名称唯一标识,不可与已有的函数名重复
RETURNS
:这个函数的返回值类型
COMMENT
:函数说明
LANGUAGE
:这个函数执行体类型,默认是SQL,其他可选的有Java等可被识别的标识符,非SQL时需要另行制定 RETURN 为 EXTERNAL 并制定对应代码类的全限定名称,一般不使用非SQL之外的,因为设计到的代码开发有其他相关的操作,成本较大
DETERMINISTIC | NOT DETERMINISTIC
:指这个函数在运行计划和结果是否是可观测的,如果是可观测的,presto会自动加入一些优化,但可能会导致影响函数的结果,比如击中缓冲等。如果不是意味着每次运行都视为一个从无到有的计算体,运行的资源消耗presto只会在具体调度时根据已有的集群配置做优化,一般使用默认的不可观测
RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT
:这两个是指函数传入参数有Null时的处理行为,默认的CALLED ON NULL INPUT
是指只要有Null,这个函数会直接返回Null,不会发生实际的计算。反之RETURNS NULL ON NULL INPUT
会直接计算函数体,一般RETURNS NULL ON NULL INPUT
用的多一些,当然这意味着通常会在函数中处理Null值入参
RETURN
:函数的返回体,执行体非SQL时需要写为EXTERNAL NAME 'com.example.security.CryptoUtils.encrypt'
这个格式
案例sql:
CREATE FUNCTION example.default.tan(x double)
RETURNS double
DETERMINISTIC
RETURNS NULL ON NULL INPUT
RETURN sin(x) / cos(x)
CREATE OR REPLACE FUNCTION example.default.tan(x double)
RETURNS double
COMMENT 'tangent trigonometric function'
LANGUAGE SQL
DETERMINISTIC
RETURNS NULL ON NULL INPUT
RETURN sin(x) / cos(x)
CREATE TEMPORARY FUNCTION square(x int)
RETURNS int
RETURN x * x
通过上面的案例,大家可以发现,SQL类型的执行体,其实能够完成的能力是有限的,因为它现在只支持一行内的返回提,无法写多行,一般用在一个很复杂的字段逻辑封装中,如果你有多行就需要写代码解决了
写代码的方式,比较麻烦,成本较大,可以参考资料如下
prestodb函数开发:https://www.cnblogs.com/liminghuang/p/13364757.html
函数的注册:https://www.cnblogs.com/liminghuang/p/13745565.html