https://www.bilibili.com/video/AV36166554/
日前,在更新UDF函数这块的一些功能时,发现一些较为细小但大家都会遇到的问题,作为趟过的坑发出来,希望大家能够避免。
1.注册UDF函数
1.1 注册相关方法 此处,我们使用的udf函数为标量函数,它继承的是ScalarFunction,该类在我们的使用中,发现它继承自UserDefinedFunction这个类,该处的udf函数由用户自己定义,而函数的注册此处我们自己实现; 函数注册时,使用flink的tableEnv上下文对象注册该函数,此处注册时使用的方法是TableEnvironment类里面的重载方法registerFunction,这个函数不涉及参数和泛型的问题,具体方法如下:
/** * Registers a [[ScalarFunction]] under a unique name. Replaces already existing
* user-defined functions under this name.
* /
def registerFunction(name: String, function: ScalarFunction): Unit = {
// check if class could be instantiated checkForInstantiation(function.getClass)
// register in Table API
functionCatalog.registerFunction(name, function.getClass)
// register in SQL API
functionCatalog.registerSqlFunction(
createScalarSqlFunction(name, name, function, typeFactory)
) }
通过上面得方法,发现在检查完类的实例化之后,便是对该类进行注册使用,分别针对Table API和SQL API两种不同形式去进行注册。
下面是我们注册的小案例:
日常模式
tableEnv.registerFunction("hashCode",new HashCode())
myTable.select("item,item.hashCode(),hashCode(item)")
val hcTest = tableEnv.sqlQuery("select item,hashCode(item) from myTable")
假日模式
ableEnv.registerFunction(m("name").toString,ReflectHelper.newInstanceByCl sName[ScalarFunction] (m("className").toString,this.getClass.getClassLoader))
1.2 函数示例
/** * Created by LX on 2018/11/15.
*/
class HashCode extends ScalarFunction {
var hashcode_factor = 12
override def open(context: FunctionContext): Unit = {
// access "hashcode_factor" parameter
// "12" would be the default value if parameter does not exist
hashcode_factor = context.getJobParameter("hashcode_factor", "12").toInt }
def eval(s: String): Int = {
s.hashCode()+hashcode_factor } }
2.注册UDTF函数
2.1 注册相关方法 在UDTF和UDAF中,我们发现,注册使用的具体函数是包含有一定的格式限制,比如此时我们需要注册的UDTF函数,Split类继承自TableFunction[(String,Int)],那么我们的函数注册中,在java程序编译时会去检查该泛型,后续实际运行时,解析我们的UDTF函数时,对泛型内的类型进行序列化和反序列化时会和我们规定的泛型进行对比,如果此时我们的数据schema或者说我们的数据本身格式不匹配抑或是我们给出了数据的泛型,编译过了擦除掉之后,在实际运行中却发现并没有该字段信息,那么同样也会出错,所以此时,我们更加要去注意产生该问题的根源,那么根源究竟是什么呢,话不多说,接着看代码。 我们需要注册函数的registerFunction方法,来自于StreamTableEnvironment中的registerFunction方法,此处的类请大家和之前区别一下,注意,此处这个类在后续我们使用UDAF时也会使用,那么原因在于这两个函数加入了泛型的约束,所以兜兜转转,会有中间的一个检查判断过程,接着,同样是在TableEnvironment这个类中的registerTableFunctionInternal方法,下来,我会分别给出两个方法,请看代码。
StreamTableEnvironment
/**
* Registers a [[TableFunction]] under a unique name in the TableEnvironment' s catalog.
* Registered functions can be referenced in SQL queries. * * @param name The name under which the function is registered.
* @param tf The TableFunction to register
* /
def registerFunction[T: TypeInformation](name: String, tf: TableFunction[T]): Unit = {
registerTableFunctionInternal(name, tf)