我想知道Mongo-spark是否能够处理我将从流中导入json数据的情况,但是如果Mongo中已经存在相应的实体并且是否存在相应的实体,我想首先查找每个文件我想手动合并2个文件。
导入数据的方式如下
{orderId: 1290edoiadq, from: <Some_address_string>, to: <Some_address_string>, status: "Shipped"}.
我拥有的MongoDB具有相同的数据,但_id
字段包含orderId
。我正在寻找的是获取所有订单,然后检查它们是否需要更新或插入。
编辑让我澄清合并的含义。如果我的订单具有相同的ID,但它们的状态不同,那么我想将数据库中现有订单的状态更新为JSON数据中的内容。
答案 0 :(得分:1)
我想手动合并两份文件。
取决于您对merge
的定义。
如果它是单向导航,则从传入的json数据流更新存储在MongoDB中的文档,您可以使用upsert。
从MongoDB Connector for Spark版本1.1.0开始,如果数据框包含与MongoDB中的数据匹配的_id
,save()
将使用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-66和MongoSpark: 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尝试不同的配置,以根据数据库和集群处理负载的方式来控制数据流。