2016-03-27 4 views
0

Ich habe eine Liste von Schlüsselwörtern:Wie Dokumente in Mongodb (Pymongo) abfragen, wo alle Schlüsselwörter in einem Feld vorhanden sind?

keywords = ['word1', 'word2', 'word3'] 

Vorerst Abfrage ich für nur 1 Schlüsselwort wie folgt aus:

collection.find({'documenttextfield': {'$regex': ' '+keyword+' '}}) 

ich in keiner Weise bin ein Guru in regex ich die Reggae so tun mit Leerzeichen auf der Seite des Keywords, um genau zu finden.

Aber was ich jetzt will, ist mit dieser keywords Liste, um die Dokumente abzufragen und diejenigen zu finden, die jedes der Schlüsselwörter aus der Liste in der documenttextfield haben.

Ich habe einige Ideen, wie dies zu tun, aber sie sind alle ein bisschen zu komplex und ich fühle ich etwas fehlt ...

+0

Ein einzelner regulärer Ausdruck hilft Ihnen nicht, wenn Sie nicht wissen, in welcher Reihenfolge die Schlüsselwörter angezeigt werden. Haben Sie einen [Textindex] (https://docs.mongodb.org/manual/core/index-text/) in Erwägung gezogen? – Philipp

Antwort

1

Betrachten wir ein text index mit einem $text search verwenden. Es könnte eine weitaus bessere Lösung als die Verwendung regulärer Ausdrücke sein. Die Textsuche gibt jedoch Dokumente basierend auf einem Bewertungsalgorithmus zurück, sodass Sie möglicherweise Ergebnisse erhalten, die nicht alle gesuchten Schlüsselwörter enthalten.

Wenn Sie diesem Feld keinen Textindex hinzufügen können oder wollen, wäre die Verwendung eines einzelnen regulären Ausdrucks ziemlich schmerzhaft, weil Sie die Reihenfolge nicht kennen, in der diese Wörter angezeigt werden. Ich behaupte nicht, dass es unmöglich ist, zu schreiben, aber Sie werden selbst für Regex-Standards mit einer schrecklichen Abscheulichkeit enden. Es wäre viel einfacher, den Regex-Operator mehrfach zu verwenden, indem der Operator $and verwendet wird.

Außerdem wird die Verwendung eines Leerzeichens als Delimeter fehlschlagen, wenn das Wort am Anfang oder Ende der Zeichenfolge steht oder auf einen Punkt oder ein Komma folgt. Verwenden Sie stattdessen das Wortgrenzen-Token (\b).

collection.find(
    { $and : [ 
       {'documenttextfield': {'$regex': '\b' +keyword1+'\b'}}, 
       {'documenttextfield': {'$regex': '\b' +keyword2+'\b'}}, 
       {'documenttextfield': {'$regex': '\b' +keyword3+'\b'}}, 
     ] 
    }); 

Denken Sie daran, dass dies eine wirklich langsamen Abfragen, weil es diese drei regulären Ausdrücke auf jedem einzelnen Dokument der Sammlung laufen. Wenn es sich um eine performance-kritische Abfrage handelt, sollten Sie ernsthaft überlegen, ob ein Textindex wirklich nicht funktioniert. Wenn dies nicht gelingt, wäre das letzte Strohhalm, um zu greifen, irgendwelche Schlüsselwörter aus dem Feld documenttextfield, nach dem jemand suchen könnte (was jedes eindeutige Wort darin sein könnte), in ein neues Array-Feld documenttextfield_keywords, einen normalen Index für dieses Feld zu erstellen und zu suchen auf diesem Feld mit der $all operator (kein regulärer Ausdruck in diesem Fall erforderlich).

+0

Danke! Ich werde versuchen, Stichwörter pro Textfeld zusammenzustellen und auf demselben Dokument zu speichern! es ist eigentlich sehr nett und schön. Ich habe die Mittel, das zu tun, und ich denke, das sollte viel besser funktionieren als 3 Regexs! – GeekSince1982

+1

@ GeekSince1982 Die Verwendung von '$ all' ist viel weniger stumpf' {"documenttextfield": {"$ all": [re.compile ('\ b' + Schlüsselwort + '\ b', re.IGNORECINE) für Schlüsselwort in Schlüsselwörtern]} } '. Aber wenn Sie keine "Stoppwörter" wie "" und "", "" oder "" benötigen, ist der '$ text' wahrscheinlich effizienter. Beachten Sie, dass ein wesentlich größerer Index erforderlich ist, um diese Effizienz zu erreichen, und dass er normalerweise für "größere" Textfelder in einem Dokument geeignet ist als für kleinere. –

+0

@ GeekSince1982 Die "andere" Auslassung hier ist, dass eine "Textsuche" nicht ** nur ** die Dokumente zurückgibt, die der Liste der Begriffe entsprachen. Die Dokumente mit ** all ** Übereinstimmungen werden die "am besten bewerteten" Ergebnisse sein, aber andere enthaltene Begriffe werden zurückgegeben, da die Textsuchbedingungen "ODER" Bedingungen sind. Es gibt keine Möglichkeit, "UND" ausschließlich zu schreiben. Auch mein Hauptpunkt oben ist, dass die Antwort fälschlicherweise "$ all" annimmt ** ** ein Array benötigt, um zu funktionieren.Es ist nicht, und ist eigentlich eine "Liste von Argumenten", die mit der Eigenschaft übereinstimmen müssen, und nicht umgekehrt. Die Leute verstehen das oft falsch. –

Verwandte Themen