一. 需求描述
现有表a,要求通过每条数据中的三个字段计算hashcode值更新到原表做为shopid.
二. 第一种做法
最好的方式是通过spark sql计算出来更新,但是spark sql不能update,要想update要设计到改源码。
所以就退而求其次选择用JDBC更新,缺点是慢。
把主要代码贴一下:
result.foreachPartition(
it => {
var url = "jdbc:mysql://localhost/test?characterEncoding=utf8"
val conn = DriverManager.getConnection(url, "root", "1234")
val pstat = conn.prepareStatement("update t_test set shop_id=? where id=?")
for (obj <- it) {
pstat.setString(1, obj._2)
pstat.setInt(2, obj._1)
pstat.addBatch
}
try {
pstat.executeBatch
} finally {
pstat.close
conn.close
}
}
)
三.第二种方法是用到spark和MySQL结合。这种虽然看着麻烦,但是超级快!!!
思路如下:
1.首先用spark读出表的信息,计算hashcode,得到id和hashcode。(id用作更新表时的判断条件)
val conf = new SparkConf()
.setMaster("local[*]")
.setAppName("用户标签")
val sc = new SparkContext(conf)
val sqlC = new SQLContext(sc)
val url = "jdbc:mysql://localhost:3306/test"
val tableName = "t_test"
// 设置连接用户&密码
val prop = new java.util.Properties
prop.setProperty("user", "root")
prop.setProperty("password", "123")
prop.setProperty("driver", "com.mysql.jdbc.Driver")
val json: DataFrame = sqlC.read.jdbc(url, tableName, prop)
val data = json.rdd.map(row => {
val id = row.getAs[Int]("id")
val update_count = row.getAs[Int]("update_count")
val client_name = row.getAs[String]("client_name")
val latitude = row.getAs[String]("latitude")
val longitude = row.getAs[String]("longitude")
val call_center = row.getAs[String]("call_center")
(client_name,latitude,longitude,call_center,id,update_count)
})
val hashString: RDD[UpdateShopId] = data.map(x=>{
val hashString = x._1 + x._2 + x._3 + x._4
val shop_id: Int = hashString.hashCode
UpdateShopId(x._5,shop_id)
})
2.把计算好的(id,hashcode)导出到本地为.csv文件。
// 注意要导入隐式转换,不然不能注册表
import sqlC.implicits._
val mapDF: DataFrame = hashString.toDF()
mapDF.createOrReplaceTempView("hash")
val resultDF: DataFrame = sqlC.sql("select * from hash")
resultDF.write.mode("Append").csv("C:\\Users\\Desktop\\test\\a")
3.用navicat把.csv文件导入到数据库中。
4.通过sql完成最后一步,更新!
UPDATE t_test a,
update_shop_id b
SET a.shop_id = b.shop_id
WHERE
a.id = b.id
注:在MySQL两张表关联更新的时候,如果表的数据多,会非常非常慢,这里进行一些优化
1、不要直接去关联表名查询,在关联表外加个select查询。
UPDATE t_test a,
( select * from update_shop_id) b
SET a.shop_id = b.shop_id
WHERE
a.id = b.id
2、主表有条件先select一遍主表,关联表有条件最好放最后where后。
四. 最后一种,在MySQL中创建函数,直接调用函数就行更新
DELIMITER $$
CREATE
PROCEDURE `test`.`HashValue`(IN str CHAR(32))
BEGIN
SET @pos = 1;
SET @hashValue = 0;
SET @szHex = HEX(str);
SET @size = LENGTH(@szHex);
WHILE @pos<@size+1 DO
SET @cCh = SUBSTRING(@szHex,@pos,2);
SET @nCh =CAST(ASCII(UNHEX(@cCh)) AS UNSIGNED);
SET @hashValue = @hashValue + @nCh;
SET @pos = @pos + 2;
END WHILE;
SELECT @hashValue;
END$$
DELIMITER ;