从运行时代表scala代码的字符串中Spark SQL UDF

时间:2018-05-08 13:40:27

标签: scala apache-spark apache-spark-sql user-defined-functions scala-reflect

我需要能够从一个字符串中注册一个udf,我将从Web服务中获取该字符串,即在运行时我调用一个Web服务来获取构成udf的scala代码,编译它并将其注册为在火花环境中的udf。举个例子,假设我的web服务在json响应中返回以下scala代码 -

(row: Row, field:String) => {
import scala.util.{Try, Success, Failure}
val index: Int = Try(row.fieldIndex(field)) match {
    case Success(_) => 1
    case Failure(_) => 0
}
index
})

我想动态编译此代码,然后将其注册为udf。我已经有多个选项,比如使用工具箱,twitter eval util等,但发现我需要明确指定方法的参数类型,同时为ex创建一个实例 -

val code =
  q"""
   (a:String, b:String) => {
      a+b
   }
 """
val compiledCode = toolBox.compile(code)
val compiledFunc = compiledCode().asInstanceOf[(String, String) => Option[Any]]

这个udf需要两个字符串作为参数,因此我需要在创建对象时指定类型,如

compiledCode().asInstanceOf[(String, String) => Option[Any]]

我探讨的另一个选择是 https://stackoverflow.com/a/34371343/1218856

在这两种情况下,我必须先知道参数,参数类型和返回类型的数量,然后将代码实例化为方法。但是在我的情况下,因为udfs是我的用户创建的,我无法控制参数和类型的数量,所以我想知道是否有任何方法可以通过编译scala代码注册UDF而不知道参数编号和类型信息。

在一个坚果shell中,我将代码作为字符串,编译并将其注册为udf而不知道类型信息。

1 个答案:

答案 0 :(得分:1)

我认为,如果不尝试直接生成/执行代码,而是定义不同类型的表达式语言并执行它,那么你会好得多。像ANTLR这样的东西可以帮助你编写该表达式语言的语法并生成解析器和抽象语法树。甚至是scala的解析器组合器。它当然是更多的工作,但也是一种风险较小且容易出错的方式,允许自定义函数执行。