Технології та Інфраструктура → Elasticsearch і повнотекстовий пошук
Elasticsearch і повнотекстовий пошук
1) Роль Elasticsearch
Elasticsearch (ES) - розподілена пошукова та аналітична система на базі інвертованих індексів і колонкових структур для агрегацій. Вона дає:- Повнотекст: релевантність (BM25), морфологія, fuzzy/typo tolerant.
- Фасети та агрегації: швидкі зрізи за атрибутами.
- Гібридний пошук: BM25 + векторні kNN (семантика).
- Швидкість розробки: Query DSL, ingest pipelines, багата екосистема.
Для iGaming/фінтех: пошук ігор/провайдерів, промо і правил, швидкореагуючі фасети (провайдер, волатильність, RTP, мова), пошук по KYC/AML журналам, розбір логів і алертів.
2) Модель даних і маппінги
2. 1 Індекс і типи полів
'text'( аналізоване поле) - для повнотексту.
'keyword'- точні значення/агрегації/сортування.
`date`, `long/double`, `boolean`, `ip`, `geo_point`.
«nested» - масиви об'єктів з коректною кореляцією полів.
'dense _ vector'- векторні уявлення (ембеддинги).
2. 2 Мультипольова стратегія
Зберігайте поле в декількох видах: `name. text'( аналізоване),'name. raw` (keyword), `name. ngram'( для автодоповнення).
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 Nested для фасетів
Атрибути вигляду'features: [{name, value}]'оформляйте'nested', інакше фасети дадуть помилкові збіги.
3) Релевантність: BM25, буст і гібрид
3. 1 Класика (BM25)
Комбінуйте поля з вагами (title ^ 4, tags ^ 2, description).
Використовуйте'minimum _ should _ match'для контролю «галасливих» збігів.
3. 2 Вектори (kNN) + BM25 (rerank)
Ембеддинги (наприклад, 384-768) в'dense _ vector'.
Спочатку kNN за вектором (top 200-500), потім rescore BM25 + бізнес-бусти (новизна, RTP, ліцензія регіону).
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) Автодоповнення та підказки
Підходи:- Edge N-gram на підполі'title. ngram'( швидко, просто).
- Completion suggesters ('completion'поле) - швидкі підказки, але окремий шлях індексації.
- Search-as-you-type - об'єднує токенізацію для початку слова і словосполучень.
json
{ "suggest": { "game-suggest": { "prefix": "book o", "completion": { "field": "title_suggest", "fuzzy": { "fuzziness": 1 }}}}}
5) Синоніми, помилки і багатомовність
Синоніми: завантажуйте файл/список через'synonym'фільтр; розділяйте домени (казино/спорт).
Помилки: `fuzziness: AUTO'в'multi _ match', обмежуйте довжиною і полями. Для підказок - «fuzzy» режимі completion.
- Індекс-per-локаль (ru/en/tr/pt-BR) або багатоаналізаторна схема: `title_ru`, `title_en`.
- Різні analyzers: `russian`, `english`, `turkish`, `portuguese`.
- Перекладайте мову в ключ маршрутизації (routing), щоб тримати «гарячі» локалі ближче до користувача.
6) Фільтри, фасети та агрегації
Для фасетів використовуйте'keyword'і'nested'агрегації.
Уникайте кардинальних полів (унікальні ID) в агрегаціях - винесіть в'runtime fields'або попередні вітрини.
json
{
"size": 20,
"aggs": {
"by_provider": { "terms": { "field": "provider", "size": 20 } },
"by_volatility": { "terms": { "field": "volatility" } },
"rtp_hist": { "histogram": { "field": "rtp", "interval": 1 } }
}
}
7) Введення даних і очищення тексту
Ingest pipelines: нормалізація, вилучення полів, гео-енкодинг, видалення HTML.
Attachment/ingest-ocr (за потребою): індексація PDF/зображень (уважно до PII).
Лемматизація: через аналізатори або зовнішні пайплайни (precompute токени).
8) Шарди, репліки та ILM
8. 1 Розміри і шардинг
Менше шардів - краще. Мета: 10-50 ГБ на шард для змішаних навантажень.
Почніть з'number _ of _ shards: 1-3', масштабуйте по факту. Репліки - мінімум 1 в проде.
8. 2 ILM (Lifecycle)
hot → warm → cold → delete для логів/історії промо.
Стиснення (force merge) для «холодних» сегментів.
Для каталогів і пошуку по продукту - «безстроковий» hot з періодичною оптимізацією.
8. 3 Алгоритм міграцій без даунтайму
Новий індекс'games _ v2'→ alias'games'перемикається після'reindex'і backfill. Deprecated поля - прибирайте поступово.
9) Снапшоти, DR та оновлення
Snapshots в об'єктне сховище (S3/GCS), розклад і перевірка відновлення.
Ролінг-оновлення нод, перевірка shard allocation awareness (за зонами).
Плани DR: крос-регіон реплікація (CCR) для критичних індексів (довідники, каталоги).
10) Безпека і PII
TLS/mTLS між клієнтом і кластером.
RBAC: ролі на індекс/операції; Dev/Stage/Prod - окремо.
PII/PCI: не індексуйте поля з персональними даними без необхідності; використовуйте ingest-маскування.
Right to be forgotten: зберігайте посилання на документи для видалення за user_id; soft-delete + reindex/аноналізація.
11) Спостережуваність і SLO пошуку
Метрики:- P50/P95/P99 latency на query, помилки 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.
- Пошук ігор: P95 ≤ 200 мс, помилок <0. 5% в 30-хв вікні.
- Підказки: P95 ≤ 80 мс.
- KNN гібрид: P95 ≤ 350 мс для top-20 результатів.
12) FinOps: вартість і продуктивність
Розмір індексу: економте токенізацією, відключайте непотрібні'fielddata', використовуйте'doc _ values'тільки там, де треба.
Сегменти: плануйте merge-політику, не допускайте «дроблення».
KNN дорожче по RAM/CPU: обмежте dims,'num _ candidates', pre-filter на BM25.
Гарячі поля в RAM: моніторьте field data/heap; відводьте «важкі» агрегації в окремі індекси.
13) Приклади запитів
13. 1 Мультипольова повнотекстова з бустом
json
{
"query": {
"multi_match": {
"query": "book of",
"fields": ["title^4","title.ngram^2","tags^2","description"]
}
},
"sort": ["_score", { "released_at": "desc" }]
}
13. 2 Фільтри + фасети
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 Nested фільтрація атрибутів
json
{
"query": {
"nested": {
"path": "features",
"query": { "bool": {
"must": [
{ "term": { "features.name": "volatility" }},
{ "term": { "features.value": "high" }}
]
}}
}
}
}
13. 4 Пошук по логах (ECS) з хайлайтом
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) Мульти-тенант та ізоляція
Індекс на тенанта (краще) або поле'tenant _ id'+ фільтр ACL (дорожче на агрегаціях).
Routing по'tenant _ id'для локалізації шардів.
Обмежуйте запити тенанта лімітами/таймаутами,'query. phase` guard-rails.
15) Чек-лист впровадження
1. Схема: 'text/keyword/nested'+ мультиполя,'dense _ vector'при необхідності.
2. Аналізатори per-мова, синоніми, edge-ngram для автодоповнення.
3. Релевантність: BM25 бусти + гібрид kNN→rescore.
4. Фасети: keyword/nested, агрегації тільки по «здоровим» полям.
5. Індексація: ingest pipelines (нормалізація), батч-завантаження.
6. Шардування: почніть з малого, alias для переїздів, ILM для «довгих» логів.
7. DR: snapshots розклад, перевірка відновлення, CCR для критичних індексів.
8. Безпека: TLS, RBAC, маскування PII, політика видалення.
9. Спостережуваність: latency, heap/GC, cache hit, hot shards, rejections.
10. FinOps: розмір індексу, kNN параметризація, відключення зайвих'doc _ values/fielddata'.
16) Анти-патерни
Один індекс «на все»: різні домени (каталог, логи, транзакції) вимагають різних налаштувань.
Бездумне'fuzziness: AUTO'на всіх полях → повільно і шумно.
Синоніми «з'їдають сенс»: не розділяти домени словників.
Без nested там, де потрібні зв'язки полів → помилкові фасети.
Занадто багато шардів (по одному на документ) - накладні витрати на cluster state.
Невикористання alias при міграціях - простої і «биті» посилання.
Індексація PII «як є» - регуляторні ризики і дорогі реіндекси.
17) Контекст iGaming/фінтех: Швидкі рецепти
Пошук ігор: 'multi _ match'з бустом'title ^ 4','tags ^ 2', фасети по провайдеру/волатильності, фільтри по регіону/валюті, гібрид з векторами для «тематики» (наприклад, «єгипет», «fruit classic»).
Промо/бонуси: синоніми («фріспіни», «free spins»), дата-фільтри'active _ from/active _ to', підказки через completion.
KYC/AML журнали: ECS-схема, повнотекст по'message', агрегації по'rule _ name','country', аномалії по'@timestamp'гістограмі.
Довідник провайдерів: keyword поля для фасетів і сортувань; текстові описи - «text» з морфологією.
Регуляторні сторінки: мультимовні поля,'search _ as _ you _ type'для м'яких підказок.
Підсумок
Ефективний пошук на Elasticsearch - це не тільки «включити BM25»: це правильні аналізатори і маппінги, мультиполя і nested, гібрид ВМ25 + вектори, акуратні фасети і агрегації, дисципліна шардування і ILM, чіткі SLO і спостережуваність, а також безпека і FinOps. З цими принципами ваш пошук буде швидким, релевантним і передбачуваним - і витримає піки трафіку продуктової платформи.