从Apache Spark Streaming更新MongoDB中的数据

时间:2018-03-14 16:17:33

标签: mongodb scala apache-spark spark-streaming

我正在使用Apache Spark Streaming的scala Api在一分钟大小和一分钟幻灯片间隔的窗口中读取Kafka Server。 来自Kafka的消息包含从发送时刻开始的时间戳和任意值。每个值都应该是reducedByKeyAndWindow并保存到Mongo。

val messages = stream.map(record => (record.key, record.value.toDouble))

val reduced = messages.reduceByKeyAndWindow((x: Double , y: Double) => (x + y),
  Seconds(60), Seconds(60))


reduced.foreachRDD({ rdd =>
  import spark.implicits._
  val aggregatedPower = rdd.map({x => MyJsonObj(x._2, x._1)}).toDF()
  aggregatedPower.write.mode("append").mongo()
})

到目前为止,这是有效的,但有可能是某些消息带有延迟,一分钟,这导致在dataBase中有两个具有相同时间戳的json对象。

{"_id":"5aa93a7e9c6e8d1b5c486fef","power":6.146849997,"timestamp":"2018-03-14 15:00"}
{"_id":"5aa941df9c6e8d11845844ae","power":5.0,"timestamp":"2018-03-14 15:00"}

mongo-spark-connector的文档没有帮助我找到解决方案。 是否有一种智能方法来查询当前窗口中的时间戳是否已存在于数据库中,如果是,则更新此值?

1 个答案:

答案 0 :(得分:0)

  

是否有一种智能方法可以查询当前窗口中的时间戳是否已存在于数据库中,如果是,则更新此值?

您正在寻找的是名为upsert的MongoDB操作。如果条件不匹配,更新操作将插入新文档,如果匹配则更新字段。

如果您使用的是MongoDB Connector for Spark v2.2 +,则只要Spark数据帧包含_id字段,数据就会为upserted。这意味着将更新具有相同_id值的任何现有文档,并且将插入集合中不存在_id值的新文档。

现在您可以尝试使用MongoDB Spark Aggregation创建RDD,指定$match过滤器来查询timestamp与当前窗口匹配的位置:

val aggregatedRdd = rdd.withPipeline(Seq(
                        Document.parse(
                                "{ $match: { timestamp : '2018-03-14 15:00' } }"
)))

修改power字段的值,然后修改write.mode('append')

您也可能会发现blog: Data Streaming MongoDB/Kafka也很有用。如果您想编写Kafka消费者并使用MongoDB Java Driver

直接插入MongoDB应用您的逻辑