迭代pyspark Dataframe,然后每行与mongoDB交互

时间:2017-09-07 08:46:08

标签: python mongodb apache-spark pyspark pymongo-3.x

我有一个pyspark Dataframe,现在我想迭代每一行并插入/更新到mongoDB集合。

c.Validation.Required("addr").Ok

如果mongoDB集合'mycollection'中存在名称,则应更新该行/记录,否则插入该新记录。

我试图通过spark-dataframe

映射此函数时出现以下错误
 #Did every required imports 
 #dataframe
 +---+----+
 |age|name|
 +---+----+
 | 30|   c|
 |  5|   e|
 |  6|   f|
 +---+----+
  db = mongodbclient['mydatabase']
  collection = db['mycollection']
  #created below function to insert/update
  def customFunction(row):
      key = {'name':row.name}
      data = dict(zip(columns,[row.x for x in columns]))
      collection.update(key, data, {upsert:true})
      #return a_flag #commented it as of now, a_flag can be 0 or 1

任何人都可以在这个函数和/或其他任何地方找出'这里有什么问题',或者请建议是否有其他替代方案可用于此类任务。

基本上迭代每一行(没有收集调用甚至可能吗??)

并且,在每一行上都应用一个函数来运行外部火花工作。

请建议,在此先感谢.. :))

我在mongoDB中的数据

 result = my_dataframe.rdd.map(customFunction)
 #.....TypeError: can't pickle _thread.lock objects....
 #AttributeError: 'TypeError' object has no attribute 'message'

2 个答案:

答案 0 :(得分:1)

看起来连接对象无法被腌制。我使用foreachPartition

def customFunction(rows):
    db = mongodbclient['mydatabase']
    collection = db['mycollection']

    for row in rows:
        key = {'name':row.name}
        data = dict(zip(columns,[row.x for x in columns]))
        collection.update(key, data, {upsert:true})

my_dataframe.rdd.foreachPartition(customFunction)

但请记住,致命的失败可能会使数据库处于不一致状态。

答案 1 :(得分:1)

如果要在MongoDB中存储500k记录,则批量模式可能是处理此问题的更有效方法。与你在spark中实际执行的操作(仅创建请求)相比,执行mongoDB中的请求需要更多的功能,甚至并行执行此操作可能会导致mongo端的不稳定(并且比“迭代”方法慢)。

您可以尝试以下代码。它不使用collect(),因此它对驱动程序的内存有效:

bulk = collection.initialize_unordered_bulk_op()
for row in rdd.toLocalIterator():
    key = {'name':row.name}
    data = dict(zip(columns,[row.x for x in columns]))
    bulk.update(key, data, {upsert:true})

print(bulk.execute())