通过来自mongodb的id中的id聚合现有数据

时间:2016-11-02 00:41:53

标签: mongodb apache-spark

我想知道Mongo-spark是否能够处理我将从流中导入json数据的情况,但是如果Mongo中已经存在相应的实体并且是否存在相应的实体,我想首先查找每个文件我想手动合并2个文件。

导入数据的方式如下

{orderId: 1290edoiadq, from: <Some_address_string>, to: <Some_address_string>, status: "Shipped"}. 

我拥有的MongoDB具有相同的数据,但_id字段包含orderId。我正在寻找的是获取所有订单,然后检查它们是否需要更新或插入。

编辑让我澄清合并的含义。如果我的订单具有相同的ID,但它们的状态不同,那么我想将数据库中现有订单的状态更新为JSON数据中的内容。

2 个答案:

答案 0 :(得分:1)

  

我想手动合并两份文件。

取决于您对merge的定义。

如果它是单向导航,则从传入的json数据流更新存储在MongoDB中的文档,您可以使用upsert

MongoDB Connector for Spark版本1.1.0开始,如果数据框包含与MongoDB中的数据匹配的_idsave()将使用upsert。如果匹配_id,则会更新,否则插入。

例如,要更改为status=delivered

> df.schema
  org.apache.spark.sql.types.StructType = StructType(StructField(_id,StringType,true), StructField(from,StringType,true), StructField(status,StringType,true), StructField(to,StringType,true))

> df.first()
  org.apache.spark.sql.Row = [1290edoiadq,sender,delivered,receiver]

> MongoSpark.save(df.write.option("collection", "order").mode("append"))

在致电orderId之前,您只需将_id字段名称重命名为save()

有关详细信息,请参阅SPARK-66MongoSpark: save()

但是,如果merge表示双向更新(传入流和MongoDB),那么您必须首先在Spark中合并更改。解决代码中认为合适的任何冲突。

答案 1 :(得分:-1)

我没有使用MongoDB,但有类似的用例。 我的情景: 有一个从kafka主题读取的传入事件流。这些事件需要通过键映射和分组,对于每个键,数据存储中可能存在相应的条目(在我的情况下为HBase,在您的情况下为MongoDB)。如果有条目,则将键控事件合并到现有实体中(如果不创建新实体并将其保存到HBase)。在我的案例中还有其他复杂情况,例如查找多个表等,但问题的要点似乎与您的相似。

我的方法和我面临的挑战: 我使用了Kafka Direct Streaming方法,这给了我一个批处理(对于这个讨论可以与RDD互换)的数据,用于配置的持续时间。 Direct Streaming方法将从所有kafka分区读取,但您必须在流上下文中设置手动检查点以使程序可恢复。

现在,此RDD表示在配置的持续时间内读取的所有消息。您还可以配置此批次的最大大小。当您对此RDD执行任何处理时,RDD将分区为块,每个块由执行程序处理。 Spark通常会在群集中为每台计算机生成一个执行程序。我建议你配置你的火花工作的最大数量。您可以基于每个分区分摊对数据源(在我的情况下为HBase)的访问。因此,如果您有10个并行执行器,请注意您可以与数据并行打开10个I / O连接。由于您的阅读应该反映实体的最新写入,这可能是您设计中最关键的方面。您的数据源可以保证一致性吗?

在代码方面,您的程序看起来像这样

dataStream.foreachRDD(rdd -> {
 // for each incoming batch, do any shuffle operations like groupByKey   first
// This is because during shuffle data is exchanged between partitions
 rdd.groupByKey().mapPartitions(eventsInPartition -> {
  // this part of the code executes at each partition.
  Connection connection = createConnectionToDataSource()

  eventsInPartition.forEachRemaining(eventPair -> {

  Entity entity = connection.getStuffFromDB(eventPair._1)
  entity.addNewEvents(eventPair._2) // your merge step
  connection.writeStuffToDB(eventPair._1, entity)

   })
 })
})

您首先使用foreachRDD对每批传入的数据执行操作。首先可以并行地对每个单独的事件应用任何地图或转换。 groupByKey将在分区之间对数据进行洗牌,并且您将在同一分区中拥有具有相同键的所有事件。 mapPartitions接受在单个分区中执行的函数。在这里,您可以形成与数据库的连接。在这个例子中,因为我们按键进行分组,所以你有一个pairRDD,它是事件键元组+可迭代事件序列的RDD。您可以使用连接来查找,合并,做其他魔术,将实体写出到DB。为批处理持续时间,max cores,maxRatePerPartitions尝试不同的配置,以根据数据库和集群处理负载的方式来控制数据流。