我正在研究一个带有spark和scala的项目,我是两个新手,但是在stackoverflow的帮助下我完成了所有数据处理并将处理后的数据存储在mysql中。现在终于我遇到了一个问题,我不明白如何解决它。第一次处理数据时,我使用此方法存储数据帧,第一次表为空。
df.write.mode("append").jdbc("dburl", "tablename", "dbproperties");
假设我的处理数据在数据库中看起来像这样。
id name eid number_of_visitis last_visit_date
1 John C110 12 2016-01-13 00:00:00
2 Root C111 24 2016-04-27 00:00:00
3 Michel C112 8 2016-07-123 00:00:00
4 Jonny C113 45 2016-06-10 00:00:00
现在名为' Root'与eid' C111'访问办公室2次' 2016-08-30 00:00:00'现在处理完这个新数据后,我只需要在数据库中更新这个人的记录。我将如何做到这一点。现在更新的表应该是这样的。
id name eid number_of_visitis last_visit_date
1 John C110 12 2016-01-13 00:00:00
2 Root C111 26 2016-08-30 00:00:00
3 Michel C112 8 2016-07-123 00:00:00
4 Jonny C113 45 2016-06-10 00:00:00
我在这个表中有数百万的数据,如果我在spark数据帧中加载完整的表并更新所需的记录,那么它将花费更多的时间而且它没有意义,因为为什么我在我想要时加载完整的表只更新了一行。我尝试了这段代码,但它将新行添加到表而不是更新行。
df.write.mode("append").jdbc("dburl", "tablename", "dbproperties");
有没有办法在火花中做到这一点?
我在互联网上看过这个,我可以这样做更新。
val numParallelInserts = 10
val batchSize = 1000
new CoalescedRDD(sessions, numParallelInserts) mapPartitionsWithSplit { (split, iter) => Iterator((split, iter)) } foreach { case (split, iter) =>
val db = connect()
val sql = "INSERT INTO sessions (id, ts) VALUES (?, ?)"
val stmt = db.prepareStatement(sql)
iter.grouped(batchSize).zipWithIndex foreach { case (batch, batchIndex) =>
batch foreach { session =>
stmt.setString(1, session.id)
stmt.setString(2, TimestampFormat.print(session.ts))
stmt.addBatch()
}
stmt.executeBatch()
db.commit();
logInfo("Split " + (split+1) + "/" + numParallelInserts + " inserted batch " + batchIndex + " with " + batch.size + " elements")
}
db.close();
答案 0 :(得分:0)
你可以尝试使用sql来做到这一点。将更新的(甚至是新的)数据存储在新的临时表中,然后将临时表合并到主表中。
一种方法是 -
使用临时表
更新主表中的所有记录 update main_table
set visits = main_table.visits + temp_table.visits
from temp_table
where main_table.eid = temp_table.eid;
从临时表中删除所有重复记录(仅在临时表中留下新记录)
delete from temp_table where main_table.eid = temp_table.eid;
将临时表中的所有记录插入主表
insert into main_table select * from temp_table;
删除临时表
drop table temp_table;