Comportement étrange sur une recherche full text

#1

Bonjour,

Je fais face à un comportement qui m'échappe lors d'une requête de recherche full text. Je suis sur la version 6.6

Le contexte tout d'abord: Je cherche à faire un mappage de catégories entre les catégories produit d'un client et celles de google shopping (disponibles ici https://www.google.com/basepages/producttype/taxonomy-with-ids.fr-FR.txt).

Pour cela, j'ai importé toutes les catégories google dans un index elasticsearch, et fait un analyser custom pour gérer des synonymes.

Voici un exemple du mapping de l'index (seul le fr a un analyser custom "google_fr" pour l'instant)

{
  "google_categories" : {
    "aliases" : { },
    "mappings" : {
      "categories" : {
        "dynamic_date_formats" : [ ],
        "properties" : {
          "de" : {
            "type" : "text",
            "analyzer" : "german"
          },
          "en" : {
            "type" : "text",
            "analyzer" : "english"
          },
          "es" : {
            "type" : "text",
            "analyzer" : "spanish"
          },
          "fr" : {
            "type" : "text",
            "analyzer" : "google_fr"
          },
          "it" : {
            "type" : "text",
            "analyzer" : "italian"
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "number_of_shards" : "4",
        "provided_name" : "google_categories",
        "creation_date" : "1552466977378",
        "analysis" : {
          "filter" : {
            "fr_syn" : {
              "ignore_case" : "true",
              "expand" : "true",
              "type" : "synonym",
              "synonyms" : [
                "boites sachet chien => nourriture pour chien",
                "boites sachet chat => nourriture pour chat"
              ]
            },
            "fr_elision" : {
              "type" : "elision",
              "articles" : [
                "l",
                "m",
                "t",
                "qu",
                "n",
                "s",
                "j",
                "d",
                "c",
                "jusqu",
                "quoiqu",
                "lorsqu",
                "puisqu"
              ],
              "articles_case" : "true"
            },
            "fr_stemmer" : {
              "type" : "stemmer",
              "language" : "light_french"
            }
          },
          "analyzer" : {
            "google_fr" : {
              "filter" : [
                "lowercase",
                "fr_elision",
                "fr_syn",
                "fr_stemmer"
              ],
              "tokenizer" : "standard"
            }
          }
        },
        "number_of_replicas" : "0",
        "uuid" : "pG5J_n9DQ0Oe16S4jlijdA",
        "version" : {
          "created" : "6060199"
        }
      }
    }
  }
}

Chaque propriété correspond à un tableau contenant la hiérarchie de la catégorie pour chaque langue. Par exemple, la catégorie

"Animaux et articles pour animaux de compagnie > Articles pour animaux de compagnie > Accessoires pour chiens > Nourriture pour chiens"

est stockée sous cette forme:

        "_id" : "3530",
        "_source" : {
          "fr" : [
            "Animaux et articles pour animaux de compagnie",
            "Articles pour animaux de compagnie",
            "Accessoires pour chiens",
            "Nourriture pour chiens"
          ],
        }

C'est lorsque je fais une recherche sur une chaîne qui matche un synonyme que j'obtiens un résultat curieux. Par exemple, j'ai la catégorie client "boites sachet chien opti life (versele laga) besoins spécifiques" que je cherche à matcher. J'ai un synonyme qui remplace "boite sachet chien" par "nourriture pour chien" (catégorie google).

Si je fais une recherche explicite sur le champ fr (car je connais la langue lorsque je fais la recherche)
/google_categories/_search?pretty&q=fr:boites+sachet+chien+opti+life+(versele+laga)+besoins+spécifiques

J'obtiens comme résultat le plus pertinent:

{
  "took" : 18,
  "timed_out" : false,
  "_shards" : {
    "total" : 4,
    "successful" : 4,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 53,
    "max_score" : 7.734096,
    "hits" : [
      {
        "_index" : "google_categories",
        "_type" : "categories",
        "_id" : "5010",
        "_score" : 7.734096,
        "_source" : {
          "fr" : [
            "Animaux et articles pour animaux de compagnie",
            "Articles pour animaux de compagnie",
            "Accessoires pour chiens",
            "Jouets pour chiens"
          ],

          ...
          
      {
        "_index" : "google_categories",
        "_type" : "categories",
        "_id" : "5011",
        "_score" : 7.3680334,
        "_source" : {
          "fr" : [
            "Animaux et articles pour animaux de compagnie",
            "Articles pour animaux de compagnie",
            "Accessoires pour chiens",
            "Friandises pour chiens",
            
            ...

      {
        "_index" : "google_categories",
        "_type" : "categories",
        "_id" : "4434",
        "_score" : 7.3680334,
        "_source" : {
          "fr" : [
            "Animaux et articles pour animaux de compagnie",
            "Articles pour animaux de compagnie",
            "Accessoires pour chiens",
            "Paniers pour chiens"
          ],            

"Nourriture pour chien n'arrivant" qu'en 5ème position

Si je fais une recherche globale, "nourriture pour chien" arrive cette fois en première position

/google_categories/_search?pretty&q=boites+sachet+chien+opti+life+(versele+laga)+besoins+spécifiques

{
  "took" : 17,
  "timed_out" : false,
  "_shards" : {
    "total" : 4,
    "successful" : 4,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2000,
    "max_score" : 13.622583,
    "hits" : [
      {
        "_index" : "google_categories",
        "_type" : "categories",
        "_id" : "3530",
        "_score" : 13.622583,
        "_source" : {
          "fr" : [
            "Animaux et articles pour animaux de compagnie",
            "Articles pour animaux de compagnie",
            "Accessoires pour chiens",
            "Nourriture pour chiens"
          ],

Quelle est la raison pour laquelle la recherche globale est plus précise que la recherche sur le champ de la langue correspondante ?

(Gabriel Tessier) #2

Bonjour,

Si ça peux aider tu peux essayer de debugger tes requêtes avec ce plugin:

Ca t'aidera a y voir plus claire.... j'avais utilisé un plugin similaire a l’époque ou j'avais rajouter des synonymes pour mon contenu.

#3

Merci pour ton aide, mais c'est juste en fait une interface graphique pour une requete de type _analyze ?

En faisant un _analyze justement, j'ai aussi remarqué un comportement bizarre avec l'analyzer french de base:

curl -X POST -H "Content-type: application/json" http://mon-serveur:9200/mon-index/_analyze?pretty -d '{"text": "vêtements rôles contrôle enrôler", "analyzer": "french"}'

La réponse:

{
  "tokens" : [
    {
      "token" : "vête",
      "start_offset" : 0,
      "end_offset" : 9,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "rôle",
      "start_offset" : 10,
      "end_offset" : 15,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "control",
      "start_offset" : 16,
      "end_offset" : 24,
      "type" : "<ALPHANUM>",
      "position" : 2
    },
    {
      "token" : "enrol",
      "start_offset" : 25,
      "end_offset" : 32,
      "type" : "<ALPHANUM>",
      "position" : 3
    }
  ]
}

Comment se fait il que l'accent circonflexe dans vêtements et rôle est conservé alors que pour contrôle et enrôler il est bien supprimé ?

(David Pilato) #4

Tu peux éventuellement changer ce comportement en ajoutant un asciifolding filter à l'analyzer par défaut.

PUT /french_example
{
  "settings": {
    "analysis": {
      "filter": {
        "french_elision": {
          "type":         "elision",
          "articles_case": true,
          "articles": [
              "l", "m", "t", "qu", "n", "s",
              "j", "d", "c", "jusqu", "quoiqu",
              "lorsqu", "puisqu"
            ]
        },
        "french_stop": {
          "type":       "stop",
          "stopwords":  "_french_" 
        },
        "french_keywords": {
          "type":       "keyword_marker",
          "keywords":   ["Exemple"] 
        },
        "french_stemmer": {
          "type":       "stemmer",
          "language":   "light_french"
        }
      },
      "analyzer": {
        "rebuilt_french": {
          "tokenizer":  "standard",
          "filter": [
            "french_elision",
            "lowercase",
            "asciifolding",
            "french_stop",
            "french_keywords",
            "french_stemmer"
          ]
        }
      }
    }
  }
}
1 Like
#5

Hello @dadoonet,

Ca marche effectivement avec le asciifolding, mais, juste pour comprendre, est-ce un comportement normal et voulu de l'analyzer french par défaut et dans ce cas, quelle est la raison/rêgle pour laquelle la tokenisation n'enlève pas les accents suivant les mots (vêtement, rôle alors que contrôle c'est ok) ?

Merci pour ton aide :slight_smile:

(David Pilato) #6

Je ne sais pas pourquoi.
L'essentiel est que ce soit consistent. Que la recherche et l'indexation donnent la même chose.

Néanmoins, si tu penses que c'est un problème, il faudrait ouvrir je pense une issue côté Lucene. Car Elasticsearch ne fait que utiliser org.apache.lucene.analysis.fr.FrenchAnalyzer.

#7

OK, je voulais être sûr qu'il n'y avait pas une particularité côté Elasticsearch que je n'avais pas saisie.

Je testerai lucene en local dans un projet pour voir

Merci pour ton aide

(system) closed #8

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.