Ricerca di testo MongoDb con supporto linguistico

Nov 22 2020

Ho problemi con la ricerca del testo nella lingua di MongoDB. Per alcuni record la ricerca funziona alla grande e per alcuni record non funziona affatto.

Ho un elenco di ingredienti che vorrei cercare. Gli ingredienti sono in diverse lingue e mi piace curare il singolare e il plurale.

Ecco il mio esempio

Schema

{
  translation: [
    {
      language: {
        type: String,
        required: true
      },
      name: {
        type: String,
        required: true
      }
    }
  ],
  calories: {
    "type": Number
  },
  protein: {
    "type": Number
  },
  carbohydrate: {
    "type": Number
  },
  fat: {
    "type": Number
  }
}

Indice

foodSchema.index( { "translation.name": "text" }, { default_language: "german" } )

Leggi l'indice da DB

[
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_"
    },
    {
        "v" : 2,
        "key" : {
            "_fts" : "text",
            "_ftsx" : 1
        },
        "name" : "translation.name_text",
        "default_language" : "german",
        "background" : true,
        "weights" : {
            "translation.name" : 1
        },
        "language_override" : "language",
        "textIndexVersion" : 3
    }
]

Record

{
  calories: 1,
  protein: 2,
  carbohydrate: 3,
  fat: 4,
  translation: [
    {
      _id: ObjectId('5fba87d13ad6404108191670'),
      language: 'german',
      name: 'gurke'
    },
    {
      _id: ObjectId('5fba87d13ad6404108191671'),
      language: 'english',
      name: 'cucumber'
    },
    {
      _id: ObjectId('5fba87d13ad6404108191672'),
      language: 'spanish',
      name: 'pepino'
    }
  ]
}

// ----

{    
  calories: 4,
  protein: 3,
  carbohydrate: 2,
  fat: 1,
  translation: [
    {
      _id: ObjectId('5fba87d13ad6404108191674'),
      language: 'german',
      name: 'huhn'
    },
    {
      _id: ObjectId('5fba87d13ad6404108191675'),
      language: 'english',
      name: 'chicken'
    },
    {
      _id: ObjectId('5fba87d13ad6404108191676'),
      language: 'spanish',
      name: 'pollo'
    }
  ]
}

Ricerca di dati

db.getCollection('foods').find({$text: { $search: "gurke" }}) //works
db.getCollection('foods').find({$text: { $search: "gurken" }}) //works
db.getCollection('foods').find({$text: { $search: "cucumber" }}) //works
db.getCollection('foods').find({$text: { $search: "cucumbers" }}) //works
db.getCollection('foods').find({$text: { $search: "huhn" }}) //works
db.getCollection('foods').find({$text: { $search: "hühner" }}) //works
db.getCollection('foods').find({$text: { $search: "chicken" }}) // no result
db.getCollection('foods').find({$text: { $search: "chickens" }}) //no result
db.getCollection('foods').find({$text: { $search: "pepino" }}) //no result

La documentazione di MongoDb dice: https://docs.mongodb.com/manual/tutorial/specify-language-for-text-index/

La lingua predefinita associata ai dati indicizzati determina le regole per analizzare le radici delle parole (cioè lo stemming) e ignorare le parole di arresto.

  • Significa che è supportata solo la lingua predefinita?
  • Perché funziona per il cetriolo ma non per il pollo?

Stavo anche controllando le parole d'arresto per qualsiasi pollo. https://github.com/mongodb/mongo/blob/master/src/mongo/db/fts/stop_words_english.txt

Grazie per l'aiuto!

Risposte

1 Minsky Nov 22 2020 at 17:06

Il problema non è l'indice, è corretto, ma è necessario aggiungere $languageo utilizzare la lingua predefinita (almeno quando si utilizza $text). Provare

 db.collection.find({$text:{$search:"pollo", $language:"spanish"}})

$language Docs

Se non specificato, la ricerca utilizza la lingua predefinita dell'indice.

Inoltre, se corri

 db.collection.find({$text:{$search:"pollo"}}).explain()

Scoprirai che la query utilizza la lingua predefinita.