2015-07-13 2 views
3

Je suis en train de mettre à jour une base de données contenant plusieurs millions de documents avec moins de 10 collisions _id.Existe-t-il un moyen d'ignorer les _id existants pour insert_many dans Pymongo 3.0?

J'utilise actuellement le module PyMongo pour effectuer des insertions de traitement par lots à l'aide insert_many par:

  1. Interrogation db pour voir si le _id existe
  2. en ajoutant ensuite le document à un tableau si _id ne le fait pas existant
  3. Insérez dans la base de données en utilisant insert_many, 1000 documents à la fois.

Il y a seulement environ 10 collisions sur plusieurs millions de documents et j'interroge actuellement la base de données pour chaque _id. Je pense que je pourrais réduire le temps d'insertion global d'un jour ou deux si je pouvais couper le processus de requête.

Y at-il quelque chose de similaire à upsert peut-être que seulement insère un document s'il n'existe pas?

Répondre

6

La meilleure façon de gérer cela et aussi « l'insertion/mise à jour » de nombreux documents de manière efficace est d'utiliser le Bulk Operations API de soumettre tout en « lots » avec effecient envoi de tous et recevoir une « réponse singulière » dans confirmation.

Cela peut être géré de deux façons.

Tout d'abord d'ignorer les « erreurs en double » sur la clé primaire ou d'autres indices, vous pouvez utiliser une forme d'opération « UNORDERED »:

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

response = bulk.execute() 

Le « UNORDERED » ou un argument false il signifie que les opérations Les deux peuvent être exécutés dans n'importe quel ordre et le lot «entier» sera complété, les erreurs réelles étant simplement «signalées» dans la réponse. C'est donc une façon d'ignorer les doublons et de progresser.

L'autre approche est la même, mais en utilisant la « upsert » fonctionnalité avec $setOnInsert:

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

response = bulk.execute() 

bien que la partie « requête » dans .find() est utilisé pour interroger la présence d'un document à l'aide du " clé primaire "ou alternativement les" clés uniques "du document. Si aucune correspondance n'est trouvée, un "upsert" se produit avec un nouveau document créé. Comme tout le contenu de la modification est compris entre $setOnInsert, les champs de document ne sont modifiés ici que lorsqu'un "upsert" se produit. Sinon, pendant que le document est "apparié", rien n'est changé en ce qui concerne les données conservées sous cet opérateur. Le terme "classées" signifie dans ce cas que chaque instruction est réellement validée dans le "même" ordre dans lequel elle a été créée. De même, toute "erreur" ici arrêtera la mise à jour (au point où l'erreur est survenue). plus d'opérations seront engagées. C'est facultatif, mais probablement conseillé pour un comportement "dupliate" normal où les instructions ultérieures "dupliquent" les données d'une précédente. Pour des écritures plus efficaces, l'idée générale est d'utiliser l'API "Bulk" et de construire vos actions en conséquence. Le choix ici se résume à savoir si «l'ordre d'insertion» de la source est important pour vous ou non.

Bien sûr, la même opération "ordered"=False s'applique à insert_many qui utilise en fait les opérations «en masse» dans les nouvelles versions de pilotes. Mais vous aurez plus de flexibilité à coller avec l'interface générale qui peut "mixer" les opérations avec une API simple.

+0

Gotcha. Donc, en utilisant l'insert_many avec "ordered" = False continuera à parcourir tous les inserts tout en ignorant les erreurs qui peuvent apparaître? – SLee

+1

@SLee Il devrait. Certaines API ont été "altérées" donc le résultat renvoie une exception (ce qui n'était pas le cas auparavant) mais le batch "entier" devrait quand même s'exécuter. L'option "upsert" d'autre part ne peut pas lancer une exception (à partir d'une clé dupliquée) car elle n'implique aucune erreur dans son fonctionnement. Comme je l'ai dit, «Tout dépend de savoir si l'ordre des opérations est important pour vous. –