it-swarm.com.de

MongoDB Voll- und Teiltextsuche

Env:

  • MongoDB (3.2.0) mit MongoS

Sammlung:

  • benutzer

Textindexerstellung:

  BasicDBObject keys = new BasicDBObject();
  keys.put("name","text");

  BasicDBObject options = new BasicDBObject();
  options.put("name", "userTextSearch");
  options.put("unique", Boolean.FALSE);
  options.put("background", Boolean.TRUE);

  userCollection.createIndex(keys, options); // using MongoTemplate

Dokumentieren:

  • {"name": "LEONEL"}

Anfragen:

  • db.users.find( { "$text" : { "$search" : "LEONEL" } } ) => GEFUNDEN
  • db.users.find( { "$text" : { "$search" : "leonel" } } ) => GEFUNDEN (search caseSensitive ist false)
  • db.users.find( { "$text" : { "$search" : "LEONÉL" } } ) => FOUND (Suche mit diakritischemSensitiv ist falsch)
  • db.users.find( { "$text" : { "$search" : "LEONE" } } ) => GEFUNDEN (Teilsuche)
  • db.users.find( { "$text" : { "$search" : "LEO" } } ) => NICHT GEFUNDEN (Teilsuche)
  • db.users.find( { "$text" : { "$search" : "L" } } ) => NICHT GEFUNDEN (Teilsuche)

Gibt es eine Idee, warum ich 0 Ergebnisse mit der Abfrage "LEO" oder "L" bekomme?

Die Regex-Suche mit Textindex ist nicht zulässig.

db.getCollection('users')
     .find( { "$text" : { "$search" : "/LEO/i", 
                          "$caseSensitive": false, 
                          "$diacriticSensitive": false }} )
     .count() // 0 results

db.getCollection('users')
     .find( { "$text" : { "$search" : "LEO", 
                          "$caseSensitive": false, 
                          "$diacriticSensitive": false }} )
.count() // 0 results

Mongo-Dokumentation:

19
Leonel

Wie in MongoDB 3.4 unterstützt die Funktion text search die Suche nach Text ohne Berücksichtigung der Groß- und Kleinschreibung, wobei sprachspezifische Regeln für Stoppwörter und Stemming verwendet werden. Stemming-Regeln für unterstützte Sprachen basieren auf Standardalgorithmen, die im Allgemeinen mit gängigen Verben und Nomen umgehen, aber keine Eigennamen kennen.

Es gibt keine explizite Unterstützung für partielle oder unscharfe Übereinstimmungen, aber Begriffe, die zu einem ähnlichen Ergebnis führen, scheinen als solche zu funktionieren. Zum Beispiel: "Schmecken", "Schmecken" und "Geschmackvoll" "Alles schmeckt". Versuchen Sie es mit der Snowball Stemming Demo - Seite, um mit mehr Wörtern und Algorithmen zu experimentieren.

Ihre Ergebnisse sind alle Variationen desselben Wortes "LEONEL" und variieren nur von Fall zu Fall und von Diakritik. Wenn "LEONEL" nicht durch die Regeln Ihrer ausgewählten Sprache auf etwas kürzer gehalten werden kann, sind dies die einzigen Variationsarten, die passen.

Wenn Sie effiziente partielle Übereinstimmungen durchführen möchten, müssen Sie einen anderen Ansatz wählen. Einige hilfreiche Ideen finden Sie unter:

Es gibt eine relevante Verbesserungsanfrage, die Sie im MongoDB-Ausgaben-Tracker beobachten/aktualisieren können: SERVER-15090: Verbessern Sie Textindizes, um eine teilweise Word-Übereinstimmung zu unterstützen .

36
Stennie

Da Mongo derzeit keine Teilsuche standardmäßig unterstützt ... 

Ich habe eine einfache statische Methode erstellt.

import mongoose from 'mongoose'

const PostSchema = new mongoose.Schema({
    title: { type: String, default: '', trim: true },
    body: { type: String, default: '', trim: true },
});

PostSchema.index({ title: "text", body: "text",},
    { weights: { title: 5, body: 3, } })

PostSchema.statics = {
    searchPartial: function(q, callback) {
        return this.find({
            $or: [
                { "title": new RegExp(q, "gi") },
                { "body": new RegExp(q, "gi") },
            ]
        }, callback);
    },

    searchFull: function (q, callback) {
        return this.find({
            $text: { $search: q, $caseSensitive: false }
        }, callback)
    },

    search: function(q, callback) {
        this.searchFull(q, (err, data) => {
            if (err) return callback(err, data);
            if (!err && data.length) return callback(err, data);
            if (!err && data.length === 0) return this.searchPartial(q, callback);
        });
    },
}

export default mongoose.models.Post || mongoose.model('Post', PostSchema)

Wie benutzt man:

import Post from '../models/post'

Post.search('Firs', function(err, data) {
   console.log(data);
})
1
Ricardo Canelas

Ohne einen Index zu erstellen, können wir einfach Folgendes verwenden:

db.users.find({ name: /<full_or_partial_text>/i}) (Groß-/Kleinschreibung wird nicht berücksichtigt)

0
nurealam siddiq