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.

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
        }
    ]
}