mongodb mongodb-query aggregation-framework spring-data-mongodb full-text-indexing

Búsqueda de texto parcial y completo de MongoDB



mongodb-query aggregation-framework (3)

Env:

  • MongoDB (3.2.0) con MongoS

Colección:

  • los usuarios

Creación del índice de texto:

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

Documento:

  • {"nombre": "LEONEL"}

Consultas:

  • db.users.find( { "$text" : { "$search" : "LEONEL" } } ) => ENCONTRADO
  • db.users.find( { "$text" : { "$search" : "leonel" } } ) => ENCONTRADO (el caso de búsqueda Sensible es falso)
  • db.users.find( { "$text" : { "$search" : "LEONÉL" } } ) => ENCONTRADO (la búsqueda con diacriticSensitive es falsa)
  • db.users.find( { "$text" : { "$search" : "LEONE" } } ) => ENCONTRADO (búsqueda parcial)
  • db.users.find( { "$text" : { "$search" : "LEO" } } ) => NO ENCONTRADO (búsqueda parcial)
  • db.users.find( { "$text" : { "$search" : "L" } } ) => NO ENCONTRADO (búsqueda parcial)

¿Alguna idea de por qué obtengo 0 resultados usando como consulta "LEO" o "L"?

Regex con Text Index Search no está permitido.

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

Documentación de Mongo:


Al igual que en MongoDB 3.4, la función de búsqueda de texto está diseñada para admitir búsquedas que no distinguen entre mayúsculas y minúsculas en el contenido de texto con reglas específicas de idioma para palabras vacías y derivaciones. Las reglas de derivación para los lenguajes compatibles se basan en algoritmos estándar que generalmente manejan verbos y sustantivos comunes, pero desconocen los nombres propios.

No hay soporte explícito para coincidencias parciales o difusas, pero los términos que derivan de un resultado similar pueden parecer estar funcionando como tales. Por ejemplo: "gusto", "sabor" y buen gusto "todos provienen de" gusto ". Pruebe la página de demostración de Snowball Stemming para experimentar con más palabras y algoritmos de derivación.

Sus resultados que coinciden son todas variaciones en la misma palabra "LEONEL", y varían solo según el caso y el diacrítico. A menos que "LEONEL" pueda derivarse a algo más corto según las reglas del idioma seleccionado, estos son el único tipo de variaciones que coincidirán.

Si desea hacer coincidencias parciales eficientes, deberá adoptar un enfoque diferente. Para algunas ideas útiles ver:

Hay una solicitud de mejora relevante que puede ver / votar en el rastreador de problemas de MongoDB: https://jira.mongodb.org/browse/SERVER-15090 .


Como Mongo actualmente no admite la búsqueda parcial por defecto ...

Creé un método estático 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)

Cómo utilizar:

import Post from ''../models/post'' Post.search(''Firs'', function(err, data) { console.log(data); })


import re db.collection.find({"$or": [{"your field name": re.compile(text, re.IGNORECASE)},{"your field name": re.compile(text, re.IGNORECASE)}]})