共计 990 个字符,预计需要花费 3 分钟才能阅读完成。
这篇文章的由来是最近在做数据负采样方面的工作,看了些论文准备自己着手对样本直接操作,常规的使用工具就是Spark,日常工作中现在使用Spark的概率很高,做数据分析工作很有帮助。
以下描述涉及到Spark 默认版本 2.4 Scala 版本 2.11.8,可能有Java,如果有的话就是1.8
UDF 使用的场景都是在DataFrame 里面使用,日常都是基于Hive Hadoop文件或者Tfrecord 读取数据出来就是DataSet或者DataFrame。
先简单描述一下UDF的使用方法,在引出我想要说的问题。
使用UDF主要经历两个步骤
注册 ——–> 使用
1、注册
注册常用的有两个方法:
(1)基于匿名函数
(2)基于事先定义好的函数
两种方法的操作实例如下所示
spark.udf.register("test1", (str: String) => str.length())
事先定义好的函数
def test1(data: String) = {
data.length
}
spark.udf.register("test1", test1 _)
Emmm 还是漏掉一种方案,直接操作的
val toUpperCase = functions.udf((str: String) => str.length())
使用
spark.sql("select name,
test1
(name) as name_len from user").show
或者在DataFrame中
userDF.withColumn("name_len",
test1
(col("name"))).show
以上就是展示了UDF的注册与使用了,OK 问题来了,注册的UDF 要么在SQL的字符串语法里或者对COL列操作,我们给的DEMO 只有一个参数,我现在需要加入第二个参数,而且是外部传参,不是对DataFrame列处理。
我自己实际传的是Map ,Scala Map放到sql字符串里就会出现解析失败的情况,因为Map的形式如下所示
Map(a->2,b->3)
这里面会有 -> 这个是sql无法解析的,所以在开始执行的时候就会包parse失败的错误。
还有一种直接是哟经UDF操作,但是它需要传入的其实是Col列,我试着使用lit对其转化,其实都会报错。
So 最后的办法我是把要传的变量当做全局传到函数里去,然后在使用上述描述的方法实现,感觉还是不够优雅,但是能解决眼前的问题。