Item manquant dans le résultat de la recherche


#1

Bonjour,

j'ai index contenant plusieurs formations, quand je fais une recherche sur le titre de la formation: une formation n'est pas présente dans le résultat de recherche.

Création de l'index:

DELETE formation

PUT formation
{
  "settings": {
    "analysis": {
      "analyzer": {
        "word": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "asciifolding"
          ],
          "char_filter": []
        },
        "prefix": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "asciifolding",
            "prefix_filter"
          ],
          "char_filter": []
        }
      },
      "filter": {
        "prefix_filter": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 25
        }
      }
    }
  },
  "mappings": {
    "formation": {
      "properties": {
        "label": {
          "type": "text",
          "analyzer": "word",
          "fields": {
            "prefix": {
              "type": "text",
              "analyzer": "prefix",
              "search_analyzer": "word",
              "norms": false
            }
          },
          "norms": false
        }
      }
    }
  }
}

Ajout des données:


POST _bulk
{ "index":{ "_id": "1", "_index": "formation", "_type": "formation" } }
{ "label":"Cybersécurité" }
{ "index":{ "_id": "2", "_index": "formation", "_type": "formation" } }
{ "label":"Cyber sécurité" }
{ "index":{ "_id": "3", "_index": "formation", "_type": "formation" } }
{ "label":"Agent de sécurité" }
{ "index":{ "_id": "4", "_index": "formation", "_type": "formation" } }
{ "label":"Agent de formation" }

Ma requête:

GET formation/formation/_search
{
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "should": [
            {
              "multi_match": {
                "query": "cybersecurite",
                "fields": [
                  "label.prefix"
                ]
              }
            }
          ]
        }
      },
      "functions": [
        {
          "filter": {
            "multi_match": {
              "query": "cybersecurite",
              "fields": [
                "label"
              ]
            }
          },
          "weight": 10
        }
      ],
      "score_mode": "multiply"
    }
  }
}

Resultat de la recherche:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 2.8768208,
    "hits": [
      {
        "_index": "formation",
        "_type": "formation",
        "_id": "1",
        "_score": 2.8768208,
        "_source": {
          "label": "Cybersécurité"
        }
      }
    ]
  }
}

Ma question: pourquoi la formation avec le label "Cyber sécurité" n'est pas dans le résultat de recherche ?
est-ce que je doit définir des synonymes ?
Merci

Remarque: la requête de recherche me permet de faire une priorisation des résultats par rapport à la présenece de mot rechercher dans plusieurs champs, c'est pour cette raison que j'utilise function_score


(David Pilato) #2

Cela s'explique ainsi:

Lors de la recherche, voici l'analyseur que tu as décidé d'appliquer aux termes cherchés:

GET formation/_analyze
{
  "text": ["cybersecurite"],
  "analyzer": "word"
}

Ca donne:

{
  "tokens": [
    {
      "token": "cybersecurite",
      "start_offset": 0,
      "end_offset": 13,
      "type": "<ALPHANUM>",
      "position": 0
    }
  ]
}

Mais à l'indexation le terme Cyber sécurité a été indexé ainsi:

GET formation/_analyze
{
  "text": ["Cyber sécurité"],
  "analyzer": "prefix"
}

Donne:

{
  "tokens": [
    {
      "token": "c",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "cy",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "cyb",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "cybe",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "cyber",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "s",
      "start_offset": 6,
      "end_offset": 14,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "se",
      "start_offset": 6,
      "end_offset": 14,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "sec",
      "start_offset": 6,
      "end_offset": 14,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "secu",
      "start_offset": 6,
      "end_offset": 14,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "secur",
      "start_offset": 6,
      "end_offset": 14,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "securi",
      "start_offset": 6,
      "end_offset": 14,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "securit",
      "start_offset": 6,
      "end_offset": 14,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "securite",
      "start_offset": 6,
      "end_offset": 14,
      "type": "<ALPHANUM>",
      "position": 1
    }
  ]
}

Comme tu peux voir dans cette liste, le terme cybersecurite n'existe pas dans cette dernière liste. Donc ça ne matche pas.
Il faut que tu trouves l'analyseur qui marche pour ton cas.

D'ailleurs, si tu veux faire des combinaisons de termes à l'indexation, tu peux regarder du côté des shingles éventuellement: https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-shingle-tokenfilter.html

Tu peux également utiliser l'analyseur prefix lors de la recherche mais attention aux faux positifs que ça va donner.


#3

Merci @dadoonet pour la réponse et la réactivité.
Pour le moment je reste sur ma solution en ajoutant le synonyme et ça fonctionne.

par contre j'ai une autre question qui concerne les filtres, je fais une recherche semblable à ce qui est mentionné avant en y ajoutant les activités et je veux faire un filtre sur une activité sauf que le résultat n'est pas celle que je m'attends, peut-être que j'ai mal construit ma requête :frowning:

création de l'index avec le nouveau champ:

DELETE formation
PUT formation
{
  "settings": {
    "analysis": {
      "analyzer": {
        "word": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "asciifolding"
          ],
          "char_filter": []
        },
        "prefix": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "asciifolding",
            "prefix_filter"
          ],
          "char_filter": []
        }
      },
      "filter": {
        "prefix_filter": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 25
        }
      }
    }
  },
  "mappings": {
    "formation": {
      "properties": {
        "label": {
          "type": "text",
          "analyzer": "word",
          "fields": {
            "prefix": {
              "type": "text",
              "analyzer": "prefix",
              "search_analyzer": "word",
              "norms": false
            }
          },
          "norms": false
        },
        "activities": {
          "properties": {
            "id": {
              "type": "text",
              "analyzer": "keyword"
            },
            "label": {
              "type": "text",
              "analyzer": "word",
              "fields": {
                "prefix": {
                  "type": "text",
                  "analyzer": "prefix",
                  "search_analyzer": "word"
                }
              },
              "norms": false
            }
          }
        }
      }
    }
  }
}

Ajout des données:

POST _bulk
{ "index":{ "_id": "1", "_index": "formation", "_type": "formation" } }
{ "label":"Opérateur / Opératrice en cybersécurité", "activities": [{"id": "1", "label": "domaine cybersécurité"}] }
{ "index":{ "_id": "2", "_index": "formation", "_type": "formation" } }
{ "label":"Spécialiste en gestion de crise cyber", "activities": [{"id": "1", "label": "domaine cybersécurité"}] }
{ "index":{ "_id": "3", "_index": "formation", "_type": "formation" } }
{ "label":"Cyber documentaliste" }
{ "index":{ "_id": "4", "_index": "formation", "_type": "formation" } }
{ "label":"Animateur / Animatrice de cyberespace" }
{ "index":{ "_id": "5", "_index": "formation", "_type": "formation" } }
{ "label":"Cyber-journaliste" }
{ "index":{ "_id": "6", "_index": "formation", "_type": "formation" } }
{ "label":"Expert / Experte en cybersécurité", "activities": [{"id": "1", "label": "domaine cybersécurité"}] }
{ "index":{ "_id": "7", "_index": "formation", "_type": "formation" } }
{ "label":"Analyste en cybersécurité", "activities": [{"id": "2", "label": "un autre domaine"}] }
{ "index":{ "_id": "8", "_index": "formation", "_type": "formation" } }
{ "label":"Chef d'équipe de sécurité incendie" }
{ "index":{ "_id": "9", "_index": "formation", "_type": "formation" } }
{ "label":"abcd", "activities": [{"id": "2", "label": "un autre domaine"}] }

Ma recherche:

GET formation/_search
{
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "filter": [
            {
              "term": {
                "activities.id": "2"
              }
            }
          ],
          "should": [
            {
              "multi_match": {
                "query": "cybersecurite",
                "fields": [
                  "label.prefix",
                  "activities.label.prefix"
                ]
              }
            }
          ]
        }
      },
      "functions": [
        {
          "filter": {
            "multi_match": {
              "query": "cybersecurite",
              "fields": [
                "label"
              ]
            }
          },
          "weight": 10
        },
        {
          "filter": {
            "multi_match": {
              "query": "cybersecurite",
              "fields": [
                "activities.label"
              ]
            }
          },
          "weight": 3
        }
      ]
    }
  }
}

le résultat:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 1.8232156,
    "hits": [
      {
        "_index": "formation",
        "_type": "formation",
        "_id": "7",
        "_score": 1.8232156,
        "_source": {
          "label": "Analyste en cybersécurité",
          "activities": [
            {
              "id": "2",
              "label": "un autre domaine"
            }
          ]
        }
      },
      {
        "_index": "formation",
        "_type": "formation",
        "_id": "9",
        "_score": 0,
        "_source": {
          "label": "abcd",
          "activities": [
            {
              "id": "2",
              "label": "un autre domaine"
            }
          ]
        }
      }
    ]
  }
}

je ne m'attendais pas a avoir la formation "abcd" dans le résultat.

Merci de votre aide.


(David Pilato) #4

Pourquoi tu ne t'y attendais pas ?

Le seul filtre obligatoire est sur "activities.id": "2".