PySpark MongoDB从DataFrame追加数组的所有元素

时间:2017-11-15 19:17:32

标签: apache-spark pyspark spark-dataframe pymongo pyspark-sql

我有一个看起来像这样的MongoDB集合:

{
    "_id" : { "customerName" : "Bob",  "customerPhone" : "123-456-7890"},
    "purchases": ["A", "B", "C", "D"]
}

基本上,_id是一对关于客户的唯一密钥,而购买是客户购买的项目的数组。

我还有一个PySpark DataFrame,我想将其推入此集合,其中包含我想要更新此特定文档的信息。

df.write.format("com.mongodb.spark.sql.DefaultSource").mode("append") \
                .option("spark.mongodb.output.uri", "mongodb://localhost:27017/customer.purchases").save()

问题在于,如果我要更新此文档,我想为Bob添加新购买,则只会在purchases中附加不存在的商品,而不是追加所有商品。

因此,我现在最终做的就是我只需要调用rdd.collect()将整个事物转换为列表而不使用架构将其转换为DataFrame。然后在检查密钥是否存在的同时逐个插入所有内容;这使得这部分变得很慢,并且当RDD的查询变大时需要大量内存。

对于版本:

PySpark:2.2 MongoDB:3.0.15 Mongo Spark Connector:2.2.1

有没有人可以使用数据框将数组中的所有元素追加到MongoDB集合中? 此外,如果我有任何遗漏或其他我应该做的事情,请告诉我。 谢谢!

1 个答案:

答案 0 :(得分:0)

您需要更改文档的data models或架构。这里的重要部分是_id关键字段。字段名_id保留用作主键;它的值在集合中必须是唯一的,是不可变的,并且可以是除数组之外的任何类型。

在您的情况下,_id字段的值是可变的,实际上这是您尝试更新的内容。作为建议,您可能希望将其更改为:

{ "_id" : <unique identifier>
  "customerName" : "Bob",  
  "customerPhone" : "123-456-7890",
  "purchases": ["A", "B", "C", "D"]
}

您可以使用ObjectId的默认_id值作为唯一标识符。

_id字段上有唯一标识符之后,让我们谈谈更新操作。自MongoDB Spark Connector v1.1 +(当前版本为2.2)以来,如果数据帧在写入期间包含_id字段,则数据将为upsert-ed。这意味着将更新具有相同_id值的任何现有文档,并且将插入集合中没有现有_id值的新文档。

奖金回合:

  • 您还需要为purchases字段找到更好的架构。如果数组长度未定义,可能会在将来产生问题。即鲍勃一年内购买了1000件商品。

  • 请更新您的MongoDB服务器版本(版本3.0.x是2015年),目前的稳定版本是3.4,下个月将发布3.6版本。