GH GambleHub

Фільтрація та повнотекстовий пошук

1) Навіщо потрібен пошуковий шар

Фільтрація і повнотекстовий пошук (FTS) забезпечують швидкий доступ до даних «за змістом», а не тільки за первинними ключами. Правильно спроектований шар пошуку поєднує:
  • Суворі фільтри (категорії, дати, ціни, права доступу)
  • Повнотекст (лексичний матч і ранжування)
  • Фасети (агрегати для навігації)
  • Гібридне ранжування (BM25/TF-IDF + векторні ембеддинги)
  • Надійні протоколи (пагінація курсорами, TTL токенів, крос-шардинг)

2) Архітектурна картина

Компоненти:

1. Ingest/ETL → нормалізація, дедуплікація, збагачення, побудова полів для індексу.

2. Індексатор → зворотний індекс (лексеми → документи), колонічні структури, векторний індекс (HNSW/IVF-PQ).

3. Query Layer → парсер запитів, застосування фільтрів/прав доступу, планувальник шардів, k-way merge.

4. Ranker → BM25 + (опц.) LTR/Neural re-rank.

5. Serving → кеш, курсори, фасети, хайлайти, автокомпліт.

6. Спостережуваність → метрики латентності, якості, A/B-експерименти.

3) Модель даних та індексу

3. 1 Поля та аналізатори

Типи: keyword (рівний збіг), text (аналізується), numeric/date/geo, vector.
Аналізатори: токенізація, нормалізація (lowercase, Unicode NFKC), фільтри (стоп-слова, стемінг/лемматизація).
Багатомовність: per-field аналізатори (ru, uk, en); ICU-аналіз; транслітерація; Облік діакритики.

3. 2 Зворотний індекс (sparse)

Структура: term → posting list (docID, term freq, позиції).
Ранжування: BM25 (або класичний TF-IDF) з польовими бустами.

3. 3 Векторний індекс (dense)

Ембеддинги тексту (наприклад, 384-1024-мірні).
ANN-структури: HNSW, IVF-PQ, Flat (для малих наборів).
Косинусна близькість/inner product; калібрування з BM25 (гібрид).

3. 4 Фасети та агрегати

Прекомпьют/колонкове зберігання значень для швидких count-ів.
Ієрархічні фасети (категорія/підкатегорія).
Діапазони (цінові біни, дати).

4) Запити: фільтри + повнотекст + сортування

4. 1 Контракти API (REST)

Запит:

GET /v1/search? q = classic slots & limit = 20 & cursor =... & sort = score: desc, created _ at: desc
&filters=brand:("NetEnt","EGT"); price:[10 TO 50];published_at:[2024-01-01 TO ]
&facets=brand,year,price:range(0,10,20,50,100)
Відповідь (фрагмент):
json
{
"items": [ { "id":"...", "title":"...", "score": 12. 3, "highlight": { "content": ["..."] } } ],
"facets": { "brand": [{"value":"NetEnt","count":123},...] },
"page": { "limit":20, "has_more":true, "next_cursor":"opaque-token" }
}

4. 2 GraphQL (спрощено)

graphql type Query {
search(query: String!, filter: SearchFilter, first: Int, after: String, sort: [Sort!]): SearchConnection!
}

4. 3 gRPC

proto message SearchRequest {
string query = 1;
map<string,string> filters = 2;
int32 page_size = 3;
string page_token = 4; // курсор repeated string facets = 5;
}

5) Обробка природної мови (NLP)

Токенізація/нормалізація: Unicode-безпечно, облік дефісів/апострофів.
Стоп-слова: налаштування списків мов.
Стеммінг vs лемматизація: для ru/uk краще лемматизація (якість> швидкість).
Синоніми: двонаправлені/спрямовані словники; версії словників з TTL.
Друкарські помилки (fuzzy): Damerau-Levenshtein з обмеженням відстані і бустами точного збігу.
N-грами/edge-ngrams: для автокомпліту і підказок.
Транслітерація: «shch» ↔ «щ», «kiev/kyiv» - правила відповідностей.

6) Релевантність і ранжування

6. 1 Базовий лексичний скоринг

BM25 з налаштуванням «k1», «b» по колекції.
Бусти по полях (title ^ 3, tags ^ 1. 5, body^1).
Свіжість: `score += freshness_boost(decay(created_at))`.

6. 2 Поведінкові сигнали

Click-through rate, dwell time, збереження в вибране (з анти-позиційним байасом).
Дедуплікація: склеювання документів з ~ ідентичним вмістом (MinHash/SimHash).

6. 3 Learning-to-Rank (LTR)

Фічі: BM25 по полях, довжина, свіжість, популярність, збіг за фразою, позиційний швидкість.
Моделі: LambdaMART/XGBoost; офлайн-метрики NDCG @k, MAP, Precision @k; онлайн A/B.

6. 4 Нейро-переранжування

Двоетапка: recall (BM25/ANN) → top-N (наприклад, 200) → cross-encoder rerank.
Облік вартості: тайм-бюджет, fallback без нейро-етапу при навантаженні.

6. 5 Гібридний пошук (sparse + dense)

Або fusion (нормалізація скорів і сума), або multi-stage (dense як rerank).
Важливе калібрування: min-max/ z-score/ quantile mapping.

7) Фільтрація, фасети і доступ

7. 1 Фільтри

Оператори: '=','IN', діапазони, префікси, geo-bounding box/geo-distance.
Комбінації: 'AND'за фільтрами,'OR'всередині безлічі значень (brand IN...).
Типобезпека: числові поля не аналізуються як текст.

7. 2 Фасети

Дешеві count-и по перерахованим структурам.
«Застосовані» фасети показують варіанти, що залишилися (post-filter faceting).

7. 3 Доступ/мульти-тенантність

Фільтри безпеки інтегруються до ранжування (pre-filter).
ABAC/RBAC поля в документі ('tenant _ id','visibility','acl').
Токен запиту підписаний; при мульти-тенанті - автоматичний'tenant _ id'фільтр.

8) Пагінація, курсори та консистентність

Пагінація seek-курсором по'( score, tie-breaker)'або по'( created_at, id)'при сортуванні за часом.
Непрозорі'page _ token'c HMAC і TTL.
Консистентність: near-real-time (NRT) індексу: затримка 0. 5-2 з між записом і видимістю. Документуйте це в SLA.
Крос-шард: локальний пошук → k-way merge по глобальному порядку, per-shard курсори в токені.

9) Автодоповнення та підказки

Suggesters: prefix-trie/edge-ngrams по полю'title'.
Popular queries: лог кліків → підказки по популярності + персоналізація (сегменти).
Spell-as-you-type: швидкий fuzzy-пошук з обмеженням відстані'< = 1'.

Приклад REST:

GET /v1/suggest? q=kaz&limit=8&locale=ru
→ ["casino," "casual games,..."]

10) Хайлайти і сніпети

Позиційний індекс → вилучення фраз зі збігами.
Екранування HTML, ліміт довжини, об'єднання сусідніх фрагментів.
Ранжування сніпетів за щільністю релевантних термінів.

11) Продуктивність, кеш і SLO

Індекси: гарячі сегменти в пам'яті; компресія postings; doc values для фасетів.
Кеш: L1 (процес), L2 (Redis), кеш фасетів/агрегатів; інвалідувати за версією індексу.
SLO: P95 <150-200 мс при'k <= 20', P99 <500 мс; доступність 99. 9%.
Backpressure: зменшення'k', відключення нейро-етапу при перевантаженні.
Rate limiting на ключ API/користувача/тенанта.

12) Спостережуваність і метрики якості

Техметрики:
  • `search_latency_ms` (P50/P95/P99), `qps`, `timeouts`, `error_rate`
  • `cache_hit_ratio`, `facet_cache_hit`, `rerank_share`
  • `shard_fanout`, `merge_time_ms`, `ann_recall@k`
Якість (оффлайн):
  • NDCG @k, MAP, MRR, Recall @k, Precision @k на розмічених вибірках.
Онлайн:
  • CTR@k, sCTR (satisfied clicks), dwell time, отказ (pogostick rate).

A/B: фіксуйте «guardrail» метрики (латентність, помилки) + цільові (NDCG proxy).

13) Тестування

Relevance unit tests: перевірка очікуваних матчів за ключовими запитами.
Property-based: стійкість до помилок/синонімів/мов.
Пагінація: відсутність дублікатів на межі сторінок (seek-контракти).
Безпека: фільтри доступу застосовуються завжди (навіть на faset-count).
Регреси словників: версіонування синонімів і fuzzy-правил.

14) Безпека і приватність

Поля з PII не індексувати як text; зберігати окремо/шифрувати.
Мінімізувати збережені вихідні тексти (store = false, тільки поля для сніпетів).
Query privacy: не логувати сирі запити з PII; анонімізація/хешування.
Мульти-тенант: сувора ізоляція індексів або обов'язковий'tenant _ id'фільтр.

15) Міграції та сумісність

Версіонування схеми індексу (v1→v2) з подвійним записом і поступовим перемиканням.
Сумісність аналізаторів: тримати старі ланцюжки поки не переіндексуєте.
Ротація словників синонімів/стоп-слів: `version`, `activated_at`, rollback.

16) Практичні рецепти

16. 1 Класичний лексичний пошук (BM25)

Поля: `title^3`, `tags^2`, `body^1`.
Аналізатори: мова-специфічні + лемматизація.
Fuzzy для коротких запитів ('< = 3'токенів),'fuzziness = 1'.

16. 2 Гібрид sparse + dense

1. ANN-пошук по ембеддингу запиту (k = 200)

2. Об'єднати з top-200 BM25

3. Калібрувати і злити (Reciprocal Rank Fusion)

4. Взяти top-N (N = 20), опціонально - rerank cross-encoder-ом при достатньому бюджеті.

16. 3 Фасетна навігація каталогу

Жорсткий pre-filter з прав/тенанту

Пост-фільтрові фасети (counts з урахуванням активних фільтрів)

Сортування: за релевантністю або за бізнес-полем (ціна/новизна)

17) Приклади запитів (псевдо-DSL)

Фільтри та сортування:
json
{
"query": "live casino,"
"filters": {
"country": ["EE","LV","LT"],
"license": ["MGA","UKGC"],
"launched_at": {"gte": "2023-01-01"}
},
"sort": ["_score:desc","launched_at:desc"],
"facets": ["country","license"],
"page": {"limit": 20, "cursor": "opaque"}
}
Геопошук:
json
{
"query": "casino",
"geo": {"lat": 59. 437, "lon": 24. 753, "radius_km": 50}
}
Автокомпліт:
json
{ "prefix": "evo", "field": "brand_suggest", "limit": 8 }

18) UX-патерни

Чіпи активних фільтрів + «скинути все».
Порожні результати: показати «спробуйте...» (синоніми, прибрати фільтр).
«Підказки при нулі»: популярні запити/категорії.
Пагінація курсором (кнопка «Ще») і нескінченний скролл; фіксований індикатор застосованих фільтрів.
Окремі перемикачі «враховувати друкарські помилки», «точний збіг фрази».

19) Часті помилки і анти-патерни

Відсутність tie-breaker при сортуванні → дублі/скачки.
Фасети без урахування активних фільтрів → «помилкові» counts.
Застосування фільтрів доступу після ранжування.
Змішування різних мов одним аналізатором.
Глибока пагінація OFFSET/LIMIT замість seek-курсору.
Необмежений fuzzy → вибух за латентністю.

20) Чеклист впровадження

1. Визначте поля та їх типи, призначте аналізатори per-locale.
2. Спроектуйте зворотний індекс + (опц.) векторний ANN.
3. Реалізуйте парсер запитів і безпечні фільтри доступу (pre-filter).
4. Налаштуйте BM25 і польові бусти; підключіть фасети.
5. Введіть курсори (opaque, HMAC, TTL) і k-way merge за шардами.
6. Додайте автокомпліт, хайлайти, безпечне екранування.
7. Метрики: латентність, NDCG @k, CTR; кеш L1/L2.
8. A/B-фреймворк для тюнінгу релевантності.
9. Документуйте SLA: NRT-затримку, ліміти'limit', гарантію консистентності.
10. План міграцій: версії індексу, словників та аналізаторів.

Добре спроектований шар фільтрації і повнотекстового пошуку - це не тільки швидкий індекс, але і чіткий протокольний контракт з курсорами, безпекою, передбачуваним UX і вимірною релевантністю. Такий підхід масштабується від тисяч до мільярдів документів і підтримує як класичний лексичний пошук, так і сучасні гібридні сценарії з нейромережевим ранжируванням.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Telegram
@Gamble_GC
Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.