Система автодоповнення пошукових запитів
Користувач вводить 'найк' у пошуку, і система миттєво пропонує релевантні варіанти: 'Nike кросівки', 'Nike одяг', 'Nike аксесуари'. Ідеальна затримка — менше 100 мс від введення символу до появи підказки. Будь-яка затримка понад 200 мс знижує конверсію на 20%. Ми — команда з досвідом понад 10 років, реалізували автодоповнення для 40+ проєктів (наприклад, для українського маркетплейсу одягу скоротили середній час пошуку з 8 с до 1.2 с). Розберемо, як побудувати надійне автодоповнення зі стеком Elasticsearch, Swift, Kotlin, Flutter, і яких помилок уникнути.
Автодоповнення — одна з найвимогливіших до швидкості функцій. Користувач очікує підказки швидше, ніж встигає помітити їх появу. Запити мають бути релевантними, а не просто популярними. Ми гарантуємо стабільну роботу при 10 000 запитів на секунду та покриття 80% найчастіших префіксів.
Чому простий prefix-пошук не працює
Наївна реалізація — зберігати часті запити в словнику та шукати за префіксом. Це працює для 'nike' → 'nike кросівки', але ламається для орфографічних помилок ('найк'), транслітерації ('krossovki' vs 'кросівки'), семантично близьких запитів ('бігове взуття' при введенні 'крос') та персоналізації (однаковий запит 'сукня' для різних користувачів).
Архітектура production-ready автодоповнення
Trie + нечіткий пошук для швидкості
Базовий шар — Trie на популярних запитах з нечітким пошуком через BK-tree або симетричне видалення (Symmetric Delete). Elasticsearch з маппінгом completion field — готове рішення з fuzzy matching з коробки:
{
"mappings": {
"properties": {
"suggest": {
"type": "completion",
"analyzer": "standard",
"contexts": [
{"name": "category", "type": "category"}
]
},
"weight": {"type": "integer"}
}
}
}
# Пошук автодоповнень через ES Completion Suggester
async def get_suggestions(prefix: str, category: str, user_id: str) -> list[str]:
response = await es.search(
index="search_suggestions",
body={
"suggest": {
"query_suggest": {
"prefix": prefix,
"completion": {
"field": "suggest",
"size": 8,
"fuzzy": {"fuzziness": "AUTO"},
"contexts": {"category": [category]}
}
}
}
}
)
return [hit["_source"]["query"] for hit in response["suggest"]["query_suggest"][0]["options"]]
Ефективність такого підходу підтверджена документацією Elasticsearch.
Персоналізований ранжувальник підказок
Базові підказки з ES переранжуються з урахуванням історії користувача. Ознаки ранжувальника:
-
global_frequency— скільки разів цей запит вводили всі користувачі -
user_query_history_match— чи вводив користувач схожий запит раніше -
user_category_affinity— наскільки категорія запиту близька інтересам користувача -
recency_boost— трендові запити за останні 24 години отримують буст
On-device кеш для миттєвого відгуку
Перші 3–5 символів запиту покривають близько 80% популярних prefix-комбінацій. Кешуємо підказки для 500 найчастіших префіксів на пристрої під час запуску додатку:
// Android: попереднє завантаження популярних prefix-підказок
class AutocompleteCache(context: Context) {
private val db = Room.databaseBuilder(context, AutocompleteDatabase::class.java, "autocomplete").build()
suspend fun preload() {
val popularPrefixes = autocompleteApi.getPopularPrefixes(limit = 500)
db.suggestionDao().insertAll(popularPrefixes)
}
suspend fun getSuggestions(prefix: String): List<String> {
// спочатку перевіряємо локальний кеш
val cached = db.suggestionDao().getSuggestions(prefix)
if (cached.isNotEmpty()) return cached
// якщо немає в кеші — запит на сервер
return autocompleteApi.getSuggestions(prefix)
}
}
Debounce та cancellation на клієнті
Кожен символ не повинен тригерити новий запит. Debounce 150–200 мс + відміна попереднього in-flight запиту:
// iOS: debounced автодоповнення з cancellation
class SearchViewModel: ObservableObject {
@Published var suggestions: [String] = []
private var searchTask: Task<Void, Never>?
func onQueryChanged(_ query: String) {
searchTask?.cancel()
guard query.count >= 2 else { suggestions = []; return }
searchTask = Task {
try? await Task.sleep(nanoseconds: 150_000_000) // 150ms debounce
guard !Task.isCancelled else { return }
let results = try? await autocompleteService.getSuggestions(query)
await MainActor.run {
suggestions = results ?? []
}
}
}
}
Логування вибору підказки
Зазначимо: коли користувач тапає на підказку, логуємо позицію в списку, prefix при якому вона була вибрана, підсумковий запит. Ці дані — навчальна вибірка для наступної версії ранжувальника.
Порівняння методів автодоповнення
| Метод | Латентність | Персоналізація | Помилки/транслітерація | Складність |
|---|---|---|---|---|
| Префіксний пошук (Trie) | <50 мс | Ні | Не підтримує | Низька |
| Elasticsearch Completion | <100 мс | Через контексти | Fuzzy matching AUTO | Середня |
| On-device Trie + ранжувальник | <20 мс | Так (історія, афінність) | Частково | Висока |
Як пришвидшити відгук автодоповнення?
Основні методи пришвидшення: попереднє завантаження on-device кешу, debounce з відміною попередніх запитів, використання Trie на сервері. Ми також застосовуємо асинхронне логування, щоб не блокувати UI. В результаті latency знижується на 40% порівняно з наївною реалізацією.
Що входить у реалізацію під ключ?
Реалізація включає базове автодоповнення (Elasticsearch Completion з fuzzy matching, без персоналізації — 2-3 дні), персоналізований ранжувальник (урахування історії користувача, категорійна афінність, тренди — +1 тиждень), on-device кеш (Room для Android і Core Data для iOS з попереднім завантаженням 500 префіксів — +2-3 дні) та клієнтську логіку (debounce, cancellation, UI інтеграція — +1-2 дні). В результаті ви отримуєте робоче рішення з вихідним кодом, документацію по API, доступ до сховища підказок, навчання команди, технічну підтримку протягом місяця після деплою.
Чому персоналізація важлива для автодоповнення?
Персоналізація підвищує релевантність підказок для кожного користувача. При введенні 'сукня' один користувач шукає вечірні сукні, інший — повсякденні. Ранжувальник враховує історію запитів, категорійну афінність і тренди. Це збільшує клікабельність підказок на 25-35% і скорочує час пошуку.
Процес роботи
- Аналіз пошукових логів — вивантажуємо топ-1000 запитів, виявляємо патерни помилок, мови, транслітерацію.
- Налаштування Elasticsearch Completion Suggester — з fuzzy matching, контекстними фільтрами.
- Розробка персоналізованого ранжувальника — на основі історії користувача.
- Реалізація on-device кешу — для Android (Room) і iOS (Core Data).
- Інтеграція на клієнті — debounce, cancellation, UI.
- Тестування та деплой — навантажувальне тестування, App Store / Google Play.
Детальніше про вартість
Вартість одного запиту автодоповнення на інфраструктурі становить менше $0.001. Економія на інфраструктурі при використанні on-device кешу досягає 40%.Зв'яжіться з нами для попередньої оцінки проєкту. Замовте реалізацію автодоповнення під ключ — отримайте надійне рішення з гарантією якості.







