4

_id 衝突が 10 未満の数百万のドキュメントがある DB を更新しています。

現在、PyMongo モジュールを使用して、insert_many を使用してバッチ挿入を行っています。

  1. _id が存在するかどうかを確認するためにデータベースを照会する
  2. 次に、_id が存在しない場合は、ドキュメントを配列に追加します
  3. 一度に 1000 個のドキュメントを insert_many を使用してデータベースに挿入します。

数百万のドキュメントのうち約 10 件の衝突しかありません。現在、各 _id についてデータベースにクエリを実行しています。クエリ プロセスを省略できれば、全体の挿入時間を 1 日か 2 日短縮できると思います。

おそらく、ドキュメントが存在しない場合にのみドキュメントを挿入する upsert に似たものはありますか?

4

2 に答える 2

9

これを処理し、効率的な方法で多くのドキュメントを「挿入/更新」するより良い方法は、一括操作 APIを使用してすべてを「バッチ」で送信し、すべてを効率的に送信し、確認で「単一の応答」を受信することです。

これは 2 つの方法で処理できます。

まず、主キーまたは他のインデックスの「重複エラー」を無視するには、「順序付けされていない」形式の操作を使用できます。

bulk = pymongo.bulk.BulkOperationBuilder(collection,ordered=False)
for doc in docs:
    bulk.insert(doc)

response = bulk.execute()

そこにある「UnOrdered」またはfalse引数は、操作が任意の順序で実行でき、「全体」のバッチが完了し、実際のエラーが単に応答で「報告」されることを意味します。したがって、これは基本的に重複を「無視」して先に進むための 1 つの方法です。

代替アプローチはほとんど同じですが、「アップサート」機能を次のように使用し$setOnInsertます。

bulk = pymongo.bulk.BulkOperationBuilder(collection,ordered=True)
for doc in docs:
    bulk.find({ "_id": doc["_id"] }).upsert().updateOne({
        "$setOnInsert": doc
    })

response = bulk.execute()

これにより、「クエリ」部分.find()は、ドキュメントの「主キー」または代わりに「一意のキー」を使用して、ドキュメントの存在をクエリするために使用されます。一致するものが見つからない場合は、新しいドキュメントが作成されて「アップサート」が発生します。すべての変更内容は内部$setOnInsertにあるため、"アップサート" が発生した場合、ドキュメント フィールドはここでのみ変更されます。それ以外の場合、ドキュメントが「一致」している間、この演算子の下に保持されているデータに関して実際には何も変更されません。

この場合の「順序付き」とは、すべてのステートメントが実際に作成された「同じ」順序でコミットされることを意味します。また、ここでの「エラー」は、(エラーが発生した時点で) 更新を停止し、それ以上の操作が行われないようにします。コミットします。これはオプションですが、後のステートメントが前のステートメントのデータを「複製」する通常の「複製」動作にはおそらくお勧めです。

したがって、より効率的な書き込みのために、一般的な考え方は、「バルク」API を使用し、それに応じてアクションを構築することです。ここでの選択は、ソースからの「挿入順序」が重要かどうかにかかっています。

もちろん、新しいドライバー リリースで実際に「一括」操作を使用する場合も、同じ"ordered"=False操作が適用されます。insert_manyしかし、単純な API と操作を「組み合わせる」ことができる一般的なインターフェースに固執することで、より柔軟になります。

于 2015-07-13T05:14:28.530 に答える