ASCII Folding dans Elasticsearch et appel de _analyze

Dans Elasticsearch, pour une faire une recherche sur un mot contenant un caractère unicode non présent dans la table ASCII (un accent par exemple) sans avoir à rechercher spécifiquement le mot avec ce caractère, une phase d’ASCII folding est nécessaire pour convertir ces caractères unicodes en leurs équivalents ASCII (si possible). Par exemple « ê » devient « e ».

Pour réaliser cette étape, le mapping du champ contenant ces caractères doit spécifier le filtre « asciifolding » fourni nativement par le moteur Elasticsearch.

Exemple de création d’index avec déclaration de notre analyzer avec asciifolding :

PUT /my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "standard",
          "filter":  [ "standard", "asciifolding" ]
        }
      }
    }
  }
}

On créé ensuite le type en indiquant que notre champ utilisera notre nouvel analyzer :

PUT /my_index/_mapping/fruit
{
  "properties": {
    "name": {
      "type": "string",
      "fields": {
        "asciifolding": {
          "type": "string",
          "analyzer": "my_analyzer"
        }
      }
    }
  }
}

Enfin, on ajoute un document contenant une valeur accentuée dans le champ « name » :

POST my_index/fruit 
{
  "name": "pêche"
}

Les exemples de recherche suivants illustrent l’utilité de notre analyzer.

Requête Réponses
GET my_index/fruit/_search
{
  "query": {
    "match": {
      "name": "peche"
    }
  }
}
{
   "took": 1,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 0,
      "max_score": null,
      "hits": []
   }
}

GET my_index/fruit/_search
{
  "query": {
    "match": {
      "name.asciifolding": "peche"
    }
  }
}

{
   "took": 1,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 1,
      "hits": [
         {
            "_index": "my_index",
            "_type": "fruit",
            "_id": "AVR4VgBfRZI8D8Bc982h",
            "_score": 1,
            "_source": {
               "name": "pêche"
            }
         }
      ]
   }
}

A noter que si on est en présence de mots français, il est plus intéressant d’utiliser l’analyzer « french » fourni dans Elasticsearch qui procède aussi à cette étape d’asciifolding mais ajoute également le stemming, les stopwords, etc. (analyzers de langues).

Pour tester un analyzer (ou un tokenizer ou un filtre), il est possible d’appeler « _analyze » sur un index via une requête HTTP GET.

Par exemple :

http://localhost:9200/my_index/_analyze?analyzer=my_analyzer&text=pêche

va renvoyer

{
  "tokens": [
    {
      "token": "peche",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 1
    }
  ]
}

Alors que

http://localhost:9200/my_index/_analyze?analyzer=standard&text=pêche

va renvoyer

{
  "tokens": [
    {
      "token": "pêche",
      "start_offset": 0,
      "end_offset": 5,
      "type": "<ALPHANUM>",
      "position": 1
    }
  ]
}

Attention, n’exécutez pas la requête « _analyze » dans Sense. L’encodage ne sera pas correct lors de la requête et la réponse sera fausse.

Requête :

GET /my_index/_analyze?analyzer=my_analyzer&text=pêche

Réponse :
{
   "tokens": [
      {
         "token": "p",
         "start_offset": 0,
         "end_offset": 1,
         "type": "<ALPHANUM>",
         "position": 1
      },
      {
         "token": "che",
         "start_offset": 2,
         "end_offset": 5,
         "type": "<ALPHANUM>",
         "position": 2
      }
   ]