Trouver mongoDB dossiers de lots (à l'aide de mongoid ruby adaptateur)
À l'aide de rails 3 et mongoDB avec le mongoid adaptateur, comment puis-je lot trouve à l'mongo DB? J'ai besoin de saisir tous les enregistrements dans une particulier de mongo DB collecte et l'index dans solr (index initial de données pour la recherche).
Le problème, je vais avoir, c'est que faire du Modèle.toutes les attrape tous les documents et les stocke dans la mémoire. Puis, lorsque j'ai procédé sur eux et de l'index solr, ma mémoire se mange et le processus meurt.
Ce que je suis en train de faire est de le lot le trouver dans mongo afin que je puisse effectuer une itération de plus de 1 000 enregistrements à la fois, de les transmettre à solr à l'index, puis de traiter les 1000 prochaines, etc...
Le code que j'ai actuellement ont fait ceci:
Model.all.each do |r|
Sunspot.index(r)
end
Pour une collection qui a environ 1,5 millions de disques, ce mange jusqu'à 8 GO de mémoire et tue le processus. Dans ActiveRecord, il y a un find_in_batches méthode qui me permet de segmenter les requêtes en plusieurs lots qui garde la mémoire de devenir hors de contrôle. Cependant, je n'arrive pas à trouver quelque chose comme cela pour mongoDB/mongoid.
Je voudrais être en mesure de faire quelque chose comme ceci:
Model.all.in_batches_of(1000) do |batch|
Sunpot.index(batch)
end
Qui permettrait d'alléger mes problèmes de mémoire et de requête de difficultés que de faire un simple problème de jeu à chaque fois. La documentation est rare, cependant, faire des lots trouve dans mongoDB. Je vois beaucoup de documentation sur lot semelles, mais pas de lot de découvertes.
- Êtes-vous sûr que vous avez vu des problèmes de mémoire avec cela? Mongoid et le sous-jacent Mongo pilote déjà lot de requêtes avec un curseur. Cela permet de maintenir le faible empreinte mémoire.
- Par le chemin, vous devriez changer la accepté de répondre à @RyanMcGeary un puis tous les futurs visitos de votre question sera de voir le bon et personne n'a gagné pas mettre en œuvre le manuel de l'optimisation qui est déjà fait par le pilote .
Vous devez vous connecter pour publier un commentaire.
Avec Mongoid, vous n'avez pas besoin d'manuellement lot de la requête.
Dans Mongoid,
Model.all
renvoie uneMongoid::Criteria
instance. Sur appel de#each
sur ce critère, une Mongo pilote curseur est instancié et utilisé pour parcourir les dossiers. Cette sous-jacent Mongo pilote curseur déjà lots tous les records. Par défaut, lebatch_size
est de 100.Pour plus d'informations sur ce sujet, lire ce commentaire du Mongoid auteur et mainteneur.
En résumé, il vous suffit de faire ceci:
batch_size
par requête. Qui pourrait être digne d'un patch si elle n'est pas encore une option.Enumerable
méthodes commemap
oucollect
?n / 100
fois à chaque fois?Si vous êtes une itération sur une collection où chaque enregistrement nécessite beaucoup de traitement (j'.e l'interrogation d'une API externe pour chaque élément), il est possible pour le curseur de délai d'attente. Dans ce cas, vous devez effectuer plusieurs requêtes afin de ne pas laisser le curseur ouvert.
Ici est une méthode d'assistance que vous pouvez utiliser pour ajouter le dosage de la fonctionnalité. Il peut être utilisé comme:
Assurez-vous de TOUJOURS avoir un order_by sur votre requête. Sinon, la pagination ne pourrait pas faire ce que vous voulez. Aussi je m'en tiendrais à des lots de 100 ou moins. Comme dit dans la accepté de répondre à Mongoid requêtes par lots de 100, de sorte que vous ne voulez jamais laisser le curseur ouvert tout en faisant de la transformation.
.no_timeout
méthode sur des critères qui vous évite d'avoir à se reconnecter manuellement:Post.all.order_by(:id => 1).batch_size(7).no_timeout.each_with_index do ...
Il est plus rapide d'envoyer des lots de taches solaires ainsi.
C'est comment je le fais:
no_timeout
: empêche le curseur pour déconnecter (au bout de 10 min, par défaut)only
: sélectionne uniquement les id et les champs, qui sont en fait indexésbatch_size
: extraction de 1000 entrées au lieu de 100Je ne suis pas sûr que le traitement par lots, mais vous pouvez le faire de cette façon
Mais si vous êtes à la recherche pour une parfaite longtemps solution, je ne recommanderais pas cela. Laissez-moi vous expliquer comment j'ai manipulé le même scénario dans mon application. Au lieu de faire les travaux par lots,
j'ai créé un resque travail qui met à jour l'index solr
fin
Après l'ajout de l'article, je viens de mettre une entrée à la resque file d'attente
La suite va travailler pour vous , il suffit de l'essayer
Comme @RyanMcGeary dit, vous n'avez pas besoin de vous soucier de dosage de la requête. Cependant, l'indexation des objets un à un moment est d'autant plus faible que le dosage entre eux.
Model.all.to_a
charge l'ensemble de la collection dans la mémoire.Model.find_each
ou le lot, mais en aucune façon jamaisModel.all.to_a