代码如下:
package xxx
...
import UDF_FUNCTION // udf1
...
object MyObject {
case class RecordClass(filed1: String, field2: String) // table1
def main(args: Array[String]): Unit = {
...
val hiveContext = new HiveContext(sc)
hiveContext.udf.register( "UDF_NAME", INPUT => UDF_FUNCTION(INPUT) ) // udf2
val sql = "select ...UDF_NAME(xxx) from ... where ..." // udf3
val recordsToHive = hiveContext.sql(sql).map(...)... // udf4
import hiveContext.implicits._ // table2
recordsToHive
.map( r => RecordClass(...) ) // table3
.toDF()
.registerTempTable("MY_TABLE_NAME") //table4
hiveContext.sql("INSERT INTO TABLE hive_table ... SELECT * FROM MY_TABLE_NAME") //table5
...
}
}
解释如下:该程序使用spark1.5.0版本,其他版本可能会有不同,请查询官网。
1、在Saprk中使用UDF对HIVE表进行查询
(a)由于自己编写的udf包不在maven库中,所以需进行合并打包:
使用sbt管理项目,在项目顶层目录下建立lib文件夹,将自己的udf包拷贝到该文件夹下:
[myname@mycomputer /home/myname/myproject/lib]
$ ls
my-udf.jar
然后在顶层目录进行合并打包
[myname@mycomputer /home/myname/myproject]
$ sbt compile package assembly
之后,udf包就会被合并到项目jar包中
(b)在代码中首先导入需要使用的udf:
import UDF_FUNCTION // udf1
(c)在代码中对udf进行注册:
hiveContext.udf.register( "UDF_NAME", INPUT => UDF_FUNCTION(INPUT) ) // udf2
其中,"UDF_NAME"为在程序中注册的udf名字,INPUT => UDF_FUNCTION(INPUT) 为该"UDF_NAME"使用的形式。
这里需要稍微留意的一点是:程序中注册的名字"UDF_NAME"不是必须和被导入的udf函数名相同,事实上程序中注册的udf和导入的udf 函数没有必然联系,"UDF_NAME"只是在程序中注册了一个udf,该udf会按照INPUT => UDF_FUNCTION(INPUT)说明的形式进行处理,之后在hive sql的时候直接使用这个UDF_NAME即可。只不过在实际中使用时,UDF_NAME会调用导入的udf函数,并且注册为相同的名字,以便使用。
(d)在hive sql时使用注册的udf函数:
val sql = "select ...UDF_NAME(xxx) from ... where ..." // udf3
val recordsToHive = hiveContext.sql(sql).map(...)... // udf4
(e)如果出现UDF_FUNCTION未定义的错误,尝试修改spark配置spark-env.sh,增加udf函数jar包的路径:
export SPARK_CLASSPATH=...:$path_to/my-udf.jar、
(f)如果有其他错误,请进行google。
2、将查询结果RDD写入另一个HIVE表:
(a)编写case class,该class用于表示RDD转化成的hive表的记录格式:
case class RecordClass(field1: String, field2: String) // table1
(b)导入HiveContext对象的隐式转换
import hiveContext.implicits._ // table2
(c)将RDD进行转换,并注册成hive表
recordsToHive
.map( r => RecordClass(...) ) // table3,转换
.toDF()
.registerTempTable("MY_TABLE_NAME") //table4,注册成表"MY_TABLE_NAME"
(d)之后,就可以从RDD注册的表中提取数据,插入另一个表:
hiveContext.sql("INSERT INTO TABLE hive_table ... SELECT * FROM MY_TABLE_NAME") //table5
(e)在插入过程中,如果被插入的表字段不允许为空,则需要在程序中对RDD进行额外处理。若仍有其他问题,请google。