GH GambleHub

Technologie et infrastructure → Elasticsearch et recherche en texte intégral

Elasticsearch et recherche en texte intégral

1) Le rôle d'Elasticsearch

Elasticsearch (ES) est un système de recherche et d'analyse distribué basé sur des index inversés et des structures de colonne pour les agrégations. Elle donne :
  • Texte intégral : pertinence (BM25), morphologie, fuzzy/typo tolérant.
  • Facettes et agrégations : tranches rapides par attributs.
  • Recherche hybride : BM25 + vecteurs kNN (sémantique).
  • Vitesse de développement : Query DSL, ingest pipelines, un écosystème riche.

Pour iGaming/fintech : recherche de jeux/fournisseurs, promos et règles, facettes réactives (fournisseur, volatilité, RTP, langage), recherche par KYC/AML, analyse des logs et alertes.


2) Modèle de données et mappings

2. 1 Index et types de champs

'text' (champ analysé) - pour le texte intégral.
'keyword 'est la valeur exacte/agrégation/tri.
`date`, `long/double`, `boolean`, `ip`, `geo_point`.
'nested'est un tableau d'objets avec une corrélation correcte des champs.
« dense _ vector » est une représentation vectorielle (embeddings).

2. 2 Stratégie multisectorielle

Stockez le champ dans plusieurs vues : 'name. text' (analysé), 'name. raw` (keyword), `name. ngram '(pour le remplissage automatique).

json
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ru_morph",
"fields": {
"raw": { "type": "keyword", "ignore_above": 256 },
"ngram": { "type": "text", "analyzer": "edge_ngram_2_20" }
}
},
"provider": { "type": "keyword" },
"tags":   { "type": "keyword" },
"rtp":   { "type": "float" },
"released_at": { "type": "date" },
"lang":   { "type": "keyword" },
"embedding": { "type": "dense_vector", "dims": 384, "index": true, "similarity": "cosine" }
}
},
"settings": {
"analysis": {
"filter": {
"ru_stop": { "type": "stop", "stopwords": "_russian_" },
"ru_stemmer": { "type": "stemmer", "language": "russian" },
"syn_ru": { "type": "synonym", "lenient": true, "synonyms": [
"слот,игровой автомат => слот",
"джекпот,суперприз => джекпот"
] }
},
"analyzer": {
"ru_morph": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "ru_stop", "ru_stemmer", "syn_ru"]
},
"edge_ngram_2_20": {
"type": "custom",
"tokenizer": "edge_ngram",
"filter": ["lowercase"],
"char_filter": [],
"tokenizer": "edge_ngram"
}
},
"tokenizer": {
"edge_ngram": { "type": "edge_ngram", "min_gram": 2, "max_gram": 20 }
}
}
}
}

2. 3 Nestées pour facettes

Attributs de la vue 'features : [{name, value}]' formatez 'nested', sinon les facettes donneront de fausses correspondances.


3) Pertinence : BM25, brousse et hybride

3. 1 Classique (BM25)

Combiner les champs avec les échelles (titre ^ 4, tags ^ 2, description).
Utilisez 'minimum _ should _ match' pour contrôler les correspondances « bruyantes ».

3. 2 Vecteurs (kNN) + BM25 (rerank)

Embeddings (par exemple 384-768) dans « dense _ vector ».
D'abord kNN par vecteur (top 200-500), puis rescore BM25 + boosts d'affaires (nouveauté, RTP, licence de la région).

Exemple de requête hybride :
json
{
"knn": {
"field": "embedding",
"query_vector": [/... /],
"k": 400, "num_candidates": 2000
},
"query": {
"bool": {
"should": [
{ "multi_match": {
"query": "египетские слоты джекпот",
"fields": ["title^4","tags^2","description"],
"type": "best_fields",
"minimum_should_match": "60%"
}}
],
"filter": [
{ "term": { "region": "TR" }},
{ "range": { "rtp": { "gte": 94.0 }}}
]
}
},
"rescore": {
"window_size": 400,
"query": {
"rescore_query": {
"function_score": {
"query": { "match_all": {} },
"boost_mode": "sum",
"functions": [
{ "gauss": { "released_at": { "scale": "180d", "offset": "30d", "decay": 0.5 } } },
{ "field_value_factor": { "field": "popularity", "factor": 0.2, "modifier": "log1p" } }
]
}
}
}
},
"highlight": { "fields": { "title": {}, "description": {} } }
}

4) Remplissage automatique et conseils

Approches :
  • Edge N-gram sur le sous-champ 'title. ngram '(rapide, simple).
  • Completion suggesters (champ 'completion') - indices rapides, mais un chemin d'indexation distinct.
  • Search-as-you-type - combine la tokenisation pour commencer le mot et les mots.
Exemple d'indices :
json
{ "suggest": { "game-suggest": { "prefix": "book o", "completion": { "field": "title_suggest", "fuzzy": { "fuzziness": 1 }}}}}

5) Synonymes, erreurs typographiques et multilinguisme

Synonymes : téléchargez le fichier/la liste via le filtre 'synonym' ; divisez les domaines (casino/sport).
Erreurs typographiques : 'fuzz....: AUTO' dans 'multi _ match', limiter par la longueur et les champs. Pour les indices - 'fuzzy' mode complet.

Multilinguisme :
  • Index-per-local (ru/en/tr/pt-BR) ou schéma multidépandeur : « title _ ru », « title _ en ».
  • Разные analyzers: `russian`, `english`, `turkish`, `portuguese`.
  • Transférez la langue dans la clé de routage (routing) pour garder les localités « chaudes » plus proches de l'utilisateur.

6) Filtres, facettes et agrégations

Pour les facettes, utilisez 'keyword' et 'nested' agrégation.
Évitez les champs cardinaux (identifiants uniques) dans les agrégations - sortez dans 'runtime fields' ou les vitrines préliminaires.

Exemple de facettes :
json
{
"size": 20,
"aggs": {
"by_provider": { "terms": { "field": "provider", "size": 20 } },
"by_volatility": { "terms": { "field": "volatility" } },
"rtp_hist": { "histogram": { "field": "rtp", "interval": 1 } }
}
}

7) Saisie de données et nettoyage de texte

Ingest pipelines : normalisation, extraction de champs, géo-encodage, suppression de HTML.
Attachment/ingest-ocr (si nécessaire) : indexation PDF/images (avec attention à PII).
Lemmatisation : via des analyseurs ou des piplines externes (tokens de pré-compute).


8) Chardes, répliques et ILM

8. 1 Dimensions et sharding

Moins de chardes, c'est mieux. Objectif : 10-50 Go par shard pour les charges mixtes.
Commencez par 'number _ of _ shards : 1-3', mettez à l'échelle en fait. Les répliques sont au moins 1 en vente.

8. 2 ILM (Lifecycle)

hot → warm → cold → delete pour les logs/historique promo.
Compression (force merge) pour les segments « froids ».
Pour les catalogues et la recherche par produit - « indéfiniment » hot avec optimisation périodique.

8. 3 Algorithme de migration sans downtime

Le nouvel index 'games _ v2' → alias 'games' passe après 'reindex' et backfill. Champs deprecated - supprimer progressivement.


9) Snapshots, DR et mises à jour

Snapshots vers le stockage objet (S3/GCS), la planification et la vérification de la restauration.
Mise à jour des noeuds, vérification de shard allocation awareness (par zone).
Plans RD : Réplication croisée des régions (RCC) pour les indices critiques (annuaires, catalogues).


10) Sécurité et PII

TLS/mTLS entre le client et le cluster.
RBAC : rôles sur l'indice/les opérations ; Dev/Stage/Prod - séparé.
PII/PCI : ne pas indexer inutilement les champs avec les données personnelles ; utilisez le masquage ingest.
Right to be forgotten : conservez les liens vers les documents à supprimer par user_id ; soft-delete + reindex/annonce.


11) Observation et recherche SLO

Métriques :
  • P50/P95/P99 latency sur query, erreurs 4xx/5xx.
  • Cache hit (query cache / shard request cache).
  • Heap usage, GC паузы, segment merges, threadpools (search/write).
  • Hot shards/hot nodes, rejections.
  • KNN: `graph_hits`, `search_k`, latency, recall@k.
Exemples de SLO :
  • Recherche de jeux : P95 ≤ 200 ms, erreurs <0. 5 % dans la fenêtre de 30 min.
  • Indices : P95 ≤ 80 ms.
  • KNN hybride : P95 ≤ 350 ms pour les résultats top-20.

12) FinOps : coût et performance

Taille de l'index : économisez par tokenization, désactivez les 'fielddata' inutiles, utilisez 'doc _ values' seulement là où vous voulez.
Segments : planifiez une politique merge, ne laissez pas le « broyage ».
KNN est plus cher par RAM/CPU : limitez les dims, 'num _ candidates', pré-filtre par BM25.
Champs chauds dans le RAM : surveiller le champ data/heap ; emmener les agrégations « lourdes » dans des indices distincts.


13) Exemples de demandes

13. 1 Plein texte multi-champ avec boost

json
{
"query": {
"multi_match": {
"query": "book of",
"fields": ["title^4","title.ngram^2","tags^2","description"]
}
},
"sort": ["_score", { "released_at": "desc" }]
}

13. 2 Filtres + facettes

json
{
"query": {
"bool": {
"must": [{ "match": { "title": "египет" }}],
"filter": [
{ "terms": { "provider": ["Novomatic","PragmaticPlay"]}},
{ "range": { "rtp": { "gte": 95 }}}
]
}
},
"aggs": {
"by_provider": { "terms": { "field": "provider" } },
"by_year": { "date_histogram": { "field": "released_at", "calendar_interval": "year" } }
}
}

13. 3 Filtrage des attributs Nested

json
{
"query": {
"nested": {
"path": "features",
"query": { "bool": {
"must": [
{ "term": { "features.name": "volatility" }},
{ "term": { "features.value": "high" }}
]
}}
}
}
}

13. 4 Recherche par logs (ECS) avec highlight

json
{
"query": {
"bool": {
"must": [{ "match_phrase": { "message": "payment declined" }}],
"filter": [
{ "term": { "service.name": "payments" }},
{ "range": { "@timestamp": { "gte": "now-1h" }}}
]
}
},
"highlight": { "fields": { "message": { "number_of_fragments": 0 } } }
}

14) Multi-tenant et isolant

Index par tenant (mieux) ou champ 'tenant _ id' + filtre ACL (plus cher sur les agrégations).
Routing par 'tenant _ id'pour localiser les chardes.
Limitez les requêtes tenantes aux limites/temporisations, 'query. phase` guard-rails.


15) Chèque de mise en œuvre

1. Schéma : 'text/keyword/nested' + multipole,' dense _ vector 'si nécessaire.
2. Analyseurs per-language, synonymes, edge-ngram pour l'auto-remplissage.
3. Pertinence : Boost BM25 + hybride kNN→rescore.
4. Facettes : keyword/nested, agrégations uniquement par champs « sains ».
5. Indexation : ingest pipelines (normalisation), téléchargement.
6. Chardonnages : commencez petit, alias pour les déménagements, ILM pour les loges « longues ».
7. DR : planning snapshots, vérification de récupération, CCR pour les indices critiques.
8. Sécurité : TLS, RBAC, masque PII, politique de suppression.
9. Observabilité : latinité, heap/GC, cache hit, hot shards, réactions.
10. FinOps : taille d'index, paramétrage kNN, désactivation des superflus 'doc _ values/fielddata'.


16) Anti-modèles

Un index « par tous » : différents domaines (catalogue, logs, transactions) nécessitent des paramètres différents.
Irréfléchie 'fuzz....: AUTO' dans tous les champs → lent et bruyant.
Les synonymes « mangent le sens » : ne pas séparer les domaines des dictionnaires.
Sans nested là où il faut des ligaments de champs → de fausses facettes.
Trop de chardons (un par document) - frais généraux pour l'état du cluster.
Ne pas utiliser alias lors des migrations - Temps d'arrêt et liens « battus ».
L'indexation du PII « tel quel » - les risques réglementaires et les réindex coûteux.


17) Contexte iGaming/fintech : recettes rapides

Recherche de jeux : 'multi _ match'avec le boost 'title ^ 4', 'tags ^ 2', facettes par fournisseur/volatilité, filtres par région/devise, hybride avec des vecteurs pour « thème » (par exemple « egypte », « fruit classic »).
Promo/bonus : synonymes (« frispins », « free spins »), filtres de données 'active _ from/active _ to', indices via completion.
KYC/AML journaux : schéma ECS, texte intégral par 'message', agrégation par 'rule _ name', 'country', anomalie par '@ timestamp'histogramme.
Référence des fournisseurs : keyword champs pour facettes et triage ; les descriptions textuelles sont 'text' avec la morphologie.
Pages de régulation : champs multi-langues, 'search _ as _ you _ type' pour les indices souples.


Total

Une recherche efficace sur Elasticsearch n'est pas seulement « allumer BM25 » : ce sont les bons analyseurs et mappings, multipole et nested, vecteurs VM25 + hybride, facettes et agrégations soignées, discipline de chardage et ILM, SLO et observabilité claires, et sécurité et FinOps. Avec ces principes, votre recherche sera rapide, pertinente et prévisible - et résistera aux pics de trafic de la plate-forme alimentaire.

Contact

Prendre contact

Contactez-nous pour toute question ou demande d’assistance.Nous sommes toujours prêts à vous aider !

Commencer l’intégration

L’Email est obligatoire. Telegram ou WhatsApp — optionnels.

Votre nom optionnel
Email optionnel
Objet optionnel
Message optionnel
Telegram optionnel
@
Si vous indiquez Telegram — nous vous répondrons aussi là-bas.
WhatsApp optionnel
Format : +code pays et numéro (ex. +33XXXXXXXXX).

En cliquant sur ce bouton, vous acceptez le traitement de vos données.