背景
在vivo推荐算法业务中,需要使用SparkSql,对存储在hive的离线数据进行处理,制作用户特征,然后入库到redis,我们做了一套离线特征入库的sql化的系统,可以将用户需要入库的特征,通过sql提取出来,选取对应的入库特征类型、引擎即可入库特征,实现自动化入库离线特征的效果
但是业务往往需要一些个性化的数据处理,平台不能全部注册好用户需要的方法,所以我们做了一套udf、jar管理系统,用户启动任务后,动态的去加载用户jar来实现自定义UDF的逻辑,下面是具体做法
具体思路
通过调研之后,我决定使用spark的函数注册接口 spark.udf.register,分别构造函数名称、UDF1(这里目前只需要输入参数为一种的业务,所以不用去实现UDF2....等)、返回类型 returnType
具体方法参数 (name:String,f:UDF1[_,_],returnType:DataType),你可以自行查看
找到注册函数,一切都好办了,我只需要动态的加载用户的jar里面的udf,通过反射去构造UDF1即可实现函数注册,**这里需要注意的是UDF1实现的时候必须实现序列化,否则就会报序列化错误**
其中加载jar、识别输入、输出、方法体、构造UDF1使用如下代码
val url=newURL("file:xxx")
valurls=Array(url)
var myClassLoader:URLClassLoader=newURLClassLoader(urls,scala.reflect.runtime.universe.getClass.getClassLoader)
varIType=method.getParameterTypes.map(JavaTypeInference.inferDataType).map(_._1).head
valiputType=method.getParameterTypes.head.getName
varRtype=JavaTypeInference.inferDataType(method.getReturnType)._1
val zz = myClassLoader.loadClass(className)
case class TempUDF() extends UDF1[Object,Any] with Serializable{
override def call(v1: Object): Any = {
val m1 = zz.getDeclaredMethods.filter(_.getName.equals(methodName)).head
m1.invoke(zz.newInstance(), v1)
}
}
不知道是因为公司安全问题,还是csdn问题,全部的内容,我写到简书了,有需要的自行查看
简书地址(https://www.jianshu.com/p/efff975b714f)