一、Presto函数注册
Presto function通过FunctionRegistry注册,FunctionRegistry在MetadataManager中初始化
1.1 MetadataManager
@Inject
public MetadataManager(FeaturesConfig featuresConfig,
TypeManager typeManager,
JsonCodec<ViewDefinition> viewCodec,
BlockEncodingSerde blockEncodingSerde,
SessionPropertyManager sessionPropertyManager,
SchemaPropertyManager schemaPropertyManager,
TablePropertyManager tablePropertyManager,
ColumnPropertyManager columnPropertyManager,
TransactionManager transactionManager)
{
functions = new FunctionRegistry(typeManager, blockEncodingSerde, featuresConfig);
......
}
1.2 FunctionRegistry
函数注册的两种方式:
- FunctionRegistry的构造中对不同类型的函数进行注册和签名管理
- PluginManager的installPlugin中调用FunctionRegistry追加插件中的函数
方式一:FunctionRegistry构造函数注册函数
FunctionRegistry的构造中对不同类型的函数进行注册和签名管理
FunctionListBuilder builder = new FunctionListBuilder()
.window(RowNumberFunction.class)
.aggregate(DefaultApproximateCountDistinctAggregation.class)
.scalar(RepeatFunction.class)
.functions(DECIMAL_TO_INTEGER_SATURATED_FLOOR_CAST)
......
}
方式二:PluginManager的installPlugin加载插件中的函数
public void installPlugin(Plugin plugin)
{
....
for (Class<?> functionClass : plugin.getFunctions()) {
log.info("Registering functions from %s", functionClass.getName());
metadata.addFunctions(extractFunctions(functionClass));
}
.....
}
二、Presto UDF开发
如上文一、Presto函数注册 1.2
所述原理,即presto udf开发也分别对应有两类方法
2.1 Presto UDF开发方式一(FunctionRegistry内置方式)
类似内置函数如LongSumAggregation
等,在presto-main模块下的com.facebook.presto.operator
中根据函数的性质,在对应的子包中实现函数体,然后在FunctionRegistry
中注入,具体可参考LongSumAggregation
。
2.2 Presto UDF开发方式二(Plugin插件方式)
插件开发方式也是官方文档中给出的推荐方式,具体文档见Function.
第三方github分享了一些hive udf的实现:
Plugin插件方式的udf开发,根据注入的时机,可分为两种方式
2.2.1 手动上传jar方式
手动上传jar方式,即:
- 将实现Plugin接口,开发好的udf独立工程打包生成xxx.jar
- 根目录plugin目录下新建udfs文件夹,将打包好的jar包复制过来
- 重启机器(因为PluginManager的installPlugin,只在presto启动时执行。可自行扩展开发定时扫描plugin目录的功能,实现动态注入)
Demo:Presto UDFs开发
2.2.2 安装包方式
安装包方式,即在presto源代码中添加一个module,然后修改presto-server下的maven配置,在打包时将udf打包至plugin目录
如,在presto目录下新增presto-udf模块.
(1) pom中指定parent和packaging方式
<parent>
<groupId>com.facebook.presto</groupId>
<artifactId>presto-root</artifactId>
<version>0.212</version>
</parent>
<artifactId>presto-udf</artifactId>
<description>Presto - User Defined Function</description>
<packaging>presto-plugin</packaging>
(2) 实现Plugin
public class UdfPlugin
implements Plugin
{
@Override
public Set<Class<?>> getFunctions()
{
return ImmutableSet.<Class<?>>builder()
.add(YourFunction_01.class)
.add(YourFunction_02.class)
.build();
}
}
YourFunction_xx.class 中实现函数体
(3) 指定打包至plugin目录
修改presto-server/src/main/provisio下的presto.xml,在最后添加
<artifactSet to="plugin/presto-udf">
<artifact id="${project.groupId}:presto-udf:zip:${project.version}">
<unpack />
</artifact>
</artifactSet>
经过上面的配置,在源码根目录执行打包时(mvn intall -DskipTests
)会将我们源码插件方式实现的自定义函数打包放入根目录下plugin目录中,如:
如我们模块名为presto-udf,将源码打包后生成的tar包解压,在根目录plugin目录下存在presto-udf文件夹,其中为我们实现的插件函数所需的jar。
到根目录bin下执行启动命令,通过cli命名行连接presto后,执行:
SHOW FUNCTIONS
即可检测,是否成功注入
三、本地debug插件形式开发的udf
- 2.1 方式实现的函数因为本质是内置函数,正常启动源码即可debug
- 2.2.1 方式即独立工程,只能远端debug,remote debug这里不详述,具体参见
Java 远程调试
- 2.2.2 方式即源码模块,只需在本地调试的etc/config.properties文件中添加插件信息即可:
可参考:Running in IDEA
plugin.bundles=\
../presto-mysql/pom.xml,\
../presto-udf/pom.xml