Moteur de recherche ElasticSearch Gaïa

Raya Berova

6 janvier 2026

Plan de la présentation

1️⃣ Contexte

2️⃣ Moteur de recherche - Théorie

3️⃣ Moteur de recherche ElasticSearch - Pratique

1️⃣ Introduction

Objectif

Ensemble de données avec des champs textes → Besoin de recherches textuelles rapides et efficaces

Solution : un moteur de recherche basé sur des index

C’est quoi concrètement ElasticSearch ?

  • ElasticSearch : logiciel pour l’indexation et la recherche de données.

  • Fait pour chercher des mots-clés dans des textes.

  • Utilisation en pratique avec Python : packages elasticsearch et elasticsearch-dsl.

  • Mais également utilisable avec Java.

Plan de la présentation

1️⃣ Contexte

2️⃣ Moteur de recherche - Théorie

3️⃣ Moteur de recherche ElasticSearch - Pratique

2️⃣ Moteur de recherche - Théorie

Étape 1 : pouvoir comparer l’adresse recherchée avec les données Gaïa.

Filtres

  • Normaliser le texte pour la comparaison.
  • Pour les données du référentiel ET pour les adresses recherchées.

Filtres implémentés

  • Lowercase
  • Asciifolding
  • Ponctuation
  • Séparation des nombres et lettres (ex : 1er → 1 er)
  • Suppression des “0” devant les nombres (ex : 0033 → 33)
  • Prise en compte des synonymes (ex : ave = avenue, st = saint)

Étape 2 : définir un score pour évaluer la pertinence.

Base de données classique

Exemple

idVoie nom de voie
A du general leclerc
B du general charles de gaulle
C du point du jour
D verdier
E des cours

Recherche par mot

Pour chaque nom de voie du référentiel, compter le nombre de mots qui sont retrouvés dans l’adresse recherchée : les matchs 🎯.

Exemple : score avec tokenizer “mot” de “45 avenue du general charles de gaulle”

idVoie nom de voie score
A du general leclerc 2
B du general charles de gaulle 5
C du point du jour 2
D verdier 0
E des cours 0

Score avec tokenizer “mot”

Tokenizer = façon de découper le texte recherché et ciblé.


Pour retourner la voie la plus pertinente, on construit un score pour chaque voie : \[ score_{voie} = \sum_{\text{∀m} \in \text{M}} {nb\_occurrence}_m \]

m = mot.
M = ensemble des mots de l’adresse recherchée.

Dans une grande base de données, c’est extrêmement long.

Étape 3 : utiliser un index inversé. Mais qu’est ce donc ?

Index inversé mot

Exemple

idVoie nom de voie
A du general leclerc
B du general charles de gaulle
C du point du jour
D verdier
E des cours
mot occurrences
general {“A”: 1, “B”: 1}
jour {“C”: 1}
du {“A”: 1, “B”: 1, “C”: 2}
cours {“E”: 1}

Comptage direct ⚡ des occurrences de chaque mot de la base par idVoie.

Étape 4 : prendre en compte les variations textuelles.

Fuzziness

Contourner les petites fautes d’orthographes : fuzziness.

Pour matcher 🎯 deux mots avec une fuzziness de niveau 1 = corriger l’un des mots :

  • Ajout d’une lettre. Ex: “verdiier”
  • Suppression d’une lettre. Ex: “verdie”
  • Remplacement d’une lettre. Ex: “verfier”
  • Échanger deux lettres de place. Ex: “evrdier”

Il est possible de comparer deux textes, deux n-grams ou n’importe quel autre groupe de caractères.

Une autre façon de découper : les n-grams

Prendre en compte les correspondances partielles : chaque mot est découpé en sous-chaînes de n caractères consécutifs.


Exemple de découpage en 3-grams de caractères du texte “avenue verdier” :
ave, ven, enu, nue, ver, erd, rdi, die, ier


Si un mot est inférieur à la taille n, il n’aura pas de découpage en n-grams → pas présent dans l’index inversé n-gram.

Index inversé 3-grams

Exemple

idVoie nom de voie
A du general leclerc
B du general charles de gaulle
C du point du jour
D verdier
E des cours
3-gram occurrences
gen {“A”: 1, “B”: 1}
cha {“B”: 1}
our {“C”: 1, “E”: 1}
oin {“C”: 1}

Score avec tokenizer “n-grams”

Score pour chaque voie : \[ score_{voie} = \sum_{\text{∀ngram} \in \text{N}} {nb\_occurrence}_{ngram} \]

N = ensemble des n-grams de l’adresse recherchée.

Limites des n-grams

\[ \downarrow \text{taille n-grams} \Rightarrow \text{taille index inversé} \uparrow \Rightarrow \text{temps de recherche} \uparrow \]

  • Limitation à n∈{3,4,5} pour notre cas.
  • Tests effectués pour choisir ces valeurs, en fonction de la précision et la rapidité des requêtes.

Score global

Le score global va donc combiner la somme des matchs 🎯 au niveau :

  • mot avec fuzziness.
  • n-grams.


Il est possible de donner plus ou moins d’importance à ces différents niveaux de matchs 🎯.

Boost 🚀

  • Chaque occurrence est multipliée par un facteur, appelé boost 🚀, qui dépend du niveau de match 🎯.
  • Personnalisation des boosts 🚀 pour être adapté aux données recherchées.

Faire des recherches 🔍

Requête 🔍 pour retrouver la voie :

À chaque match 🎯, le score va ⇡ en fonction du boost 🚀 associé.

Variable Tokenizer Fuzzi 1 Boost 🚀
Nom de voie Mot 15
Type de voie Mot 5
Nom de voie 3 à 5-grams 1

Ex boost 200 : “3 rue du genral de gaulle” ⊃ “du general de gaulle”

Retour sur le score global

\[ score_{voie} = \sum_{\text{∀n} \in \text{N}} \sum_{\text{∀t} \in \text{n}} boost_{n}*{nb\_occurrence}_{t} \]

N = ensemble des niveaux (niveau chaîne complète fuzzi, niveau mot fuzzi…).
n = niveau.
t = token, sous-chaîne (un mot, un 3-grams…).

Plan de la présentation

1️⃣ Contexte

2️⃣ Moteur de recherche - Théorie

3️⃣ Moteur de recherche ElasticSearch - Pratique

3️⃣ Moteur de recherche ElasticSearch - Pratique

Créer des index Elasticsearch

Trois éléments clés d’un index Elasticsearch :

  • Données à indexer
  • Settings → décrivent comment les données sont traitées
  • Mappings → décrivent ce que contiennent les données

Les mappings et les settings sont définis dans des fichiers JSON.

Les mappings

Les mappings décrivent :

  • la liste des variables
  • le type de chaque variable : texte, nombre, date, etc.
  • les traitements à appliquer à chaque variable

Il est possible d’appliquer plusieurs traitements à une même variable et de différencier les traitements appliqués :

  • aux données recherchées
  • aux données indexées

Exemple de mappings

Variable : nom de voie

Traitement de la variable Tokenizer Données recherchées Données indexées
Entier non analyze_entier_input analyze_entier_output
Mot mot analyze_mot_input analyze_mot_output
3-gram 3-gram analyze_3_gram_input analyze_3_gram_output

👉 Pour chaque type de traitement, un index spécifique est créé.

Les settings

Les settings définissent la manière dont les textes sont :

  • nettoyés et transformés → analyzers
  • découpés en unités de recherche → tokenizers

Effectuer une recherche : la requête

  • Les requêtes appellent différentes variables et leurs différentes versions
  • À chaque version de variable appelée, on peut appliquer :
    • un boost
    • une fuzziness

Différences entre moteur Java et Python

  • Les settings et mappings sont implémentés dans le code Java et servent à créer les index lors des déversements dans Elasticsearch
  • Une fois créés, les index sont interrogés via l’instance Elasticsearch de Gaïa
  • Les requêtes sont écrites :
    • en Java d’un côté
    • en Python de l’autre
      et reposent sur les mêmes index
  • La différence provient donc de l’écriture des requêtes :
    choix des versions de variables, valeurs de boost, niveau de fuzziness, ordre des clauses, etc.