web-dev-qa-db-fra.com

Recherche de texte intégral et partiel MongoDB

Env:

  • MongoDB (3.2.0) avec MongoS

Collection:

  • utilisateurs

Création d'index de texte:

  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

Document:

  • {"nom": "LEONEL"}

Requêtes:

  • db.users.find( { "$text" : { "$search" : "LEONEL" } } ) => FOUND
  • db.users.find( { "$text" : { "$search" : "leonel" } } ) => FOUND (la recherche casse sensible est fausse)
  • db.users.find( { "$text" : { "$search" : "LEONÉL" } } ) => FOUND (la recherche avec diacriticSensitive est false)
  • db.users.find( { "$text" : { "$search" : "LEONE" } } ) => FOUND (recherche partielle)
  • db.users.find( { "$text" : { "$search" : "LEO" } } ) => NOT FOUND (recherche partielle)
  • db.users.find( { "$text" : { "$search" : "L" } } ) => NOT FOUND (recherche partielle)

Aucune idée pourquoi je reçois 0 résultats en utilisant comme requête "LEO" ou "L"?

La regex avec recherche d'index de texte n'est pas autorisée.

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

Documentation Mongo:

19
Leonel

Comme dans MongoDB 3.4, la fonctionnalité text search est conçue pour prendre en charge les recherches insensibles à la casse sur le contenu textuel avec des règles spécifiques à la langue pour les mots vides et les mots-clés. Les règles de radicalisation pour les langues supportées sont basées sur des algorithmes standard qui gèrent généralement les verbes et les noms communs, mais ne connaissent pas les noms propres.

Il n'y a pas de support explicite pour les correspondances partielles ou floues, mais les termes ayant un résultat similaire peuvent sembler fonctionner comme tels. Par exemple: "goût", "goûts" et goûteux "vont de" goûter ". Essayez la page Snowball Stemming Demo pour expérimenter plus de mots et d’algorithmes d’essaimage.

Vos résultats correspondent aux variantes du même mot "LEONEL" et ne varient que par cas et par diacritique. À moins que "LEONEL" ne puisse être raccourci par les règles de la langue sélectionnée, ce sont les seuls types de variations qui correspondent.

Si vous voulez faire des correspondances partielles efficaces, vous devrez adopter une approche différente. Pour des idées utiles, voir:

Il existe une demande d’amélioration pertinente que vous pouvez suivre/voter dans le suivi des problèmes de MongoDB: SERVEUR 15090: Améliorer les index de texte pour prendre en charge la correspondance partielle de Word .

36
Stennie

Comme Mongo ne prend actuellement pas en charge la recherche partielle par défaut ... 

J'ai créé une méthode statique simple.

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)

Comment utiliser:

import Post from '../models/post'

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