作者介绍: 李仕杨,SelectDB 生态研发工程师,Apache Doris Contributor。
我们在使用各个 SQL 引擎时,会遇到纷繁复杂的查询需求。一部分可以通过引擎自带的内置函数去解决,但内置函数往往具有一定通用性,在部分特殊场景下内置函数可能无法满足需求,所以一般 SQL 引擎会提供 UDF 功能,方便用户通过自己写逻辑来满足特定的需求,Apache Doris 也不例外。
在 Java UDF 之前,Apache Doris 提供了原生 UDF 。由于是使用 C++ 来编写的,执行效率高、速度更快,但是在实际使用中也会存在一些问题:
跟 Doris 代码耦合度高,需要自己打包编译 Doris 源码
只支持 C++ 语言并且 UDF 代码出错会影响 Doris 集群稳定性
对于只熟悉 Hive、Spark 等大数据组件的用户有一定使用门槛
由上可知,原生的 UDF 实现起来门槛较高且存在一定的不稳定性因素。那么是否有一种实现相对简单、使用门槛较低且与 Doris 代码耦合度低的 UDF 呢?
答案是有的。在 2022 年 12 月正式发布的 Apache Doris 1.2.0 版本中,我们推出了全新的 Java UDF 和 Remote UDF 功能,其中 Java UDF 不仅能满足以上要求,并且在方便和安全角度为用户带来了全新体验:
不熟悉 C++?Java 代码一样可以实现自己的 UDF
使用条件苛刻?只要有 Jar 包就能使用
担心稳定性?Java UDF 出错只影响自身,对 Doris 的稳定性几乎无影响
迁移旧大数据平台的数据和 UDF 费时费力?Java UDF 完全兼容 Hive UDF,轻松实现快速迁移
.......
设计思路
大体步骤
Apache Doris 的 BE 是由 C++ 代码编写,如果想在 Doris 中实现 Java UDF,不可避免需要调用 JNI,而不正确的 JNI 调用将导致严重的性能问题。那么该如何设计 Java UDF 以解决这个问题呢?
Doris Java UDF 针对向量化引擎,其设计思路大体如下:
首先,制定用户在创建 UDF 时必须遵循的一些规则。 例如,UDF 类必须具有 Evaluate 方法,并且必须是 Public 和 Non-Static 的。 这些规则确保我们可以正确调用 UDF。
其次,Doris 查询引擎会执行一个新的 Java 函数调用,BE 会创建或重用一个 JVM 来调用真正的 Java UDF。 为了隔离不同的 UDF 实例,选择使用不同的类加载器来加载 UDF。
最后,由于执行时是向量化的,因此可以实现一次执行多行数据只调用一次 JNI,原因是 JNI 开销被输入列中所有行分摊了[1], 这将给用户带来更好的性能体验。

ApacheDoris1.2.0版本新增了JavaUDF和RemoteUDF功能,降低了用户开发自定义函数的门槛,特别是对于熟悉Java的开发者。JavaUDF通过制定特定的规则,如使用特定的Evaluate方法,实现了与Doris代码的解耦,并通过JNI调用来实现向量化执行,提高了性能。此外,JavaUDF的错误不会影响Doris集群的稳定性,且与HiveUDF兼容,便于数据和UDF的迁移。设计上,JavaUDF利用堆外内存和ZeroCopy优化,减少了数据拷贝,提高了处理效率。
最低0.47元/天 解锁文章
8468

被折叠的 条评论
为什么被折叠?



