Реалізація AI-автодповнення пошукових запитів в мобільному додатку
Автодповнення — одна з найвимоглівіших до latency функцій мобільного додатка. Користувач очікує підказки швидше, ніж встигне їх помітити: ідеал — < 100 мс від введення символу до появи варіантів. При цьому запити повинні бути релевантними, а не просто «популярними».
Чому простий prefix-пошук не працює
Наївна реалізація — зберігати частові запити в словнику та шукати за префіксом. Це працює для «nike» → «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"]]
Персоналізований рейтингувач підказок
Базові підказки з ES переранжуються з урахуванням історії користувача. Ознаки рейтингувача:
-
global_frequency— скільки разів цей запит вводили всі користувачі -
user_query_history_match— вводив ли цей користувач подібний запит раніше -
user_category_affinity— наскільки категорія запиту близька інтересам користувача -
recency_boost— трендові запити за останні 24 години отримують буст
On-device кеш для миттєвого відклику
Перші 3–5 символів запиту охоплюють ~80% популярних prefix-комбінацій. Кешуємо підказки для них на пристрої при старті додатка (або у фоні):
// 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 ?? []
}
}
}
}
Task.isCancelled перевіряється після debounce — якщо користувач продовжив введення, попередня задача вже скасована.
Логування вибору підказки
Коли користувач тапає на підказку, логуємо: позицію у списку, prefix при якому вона була вибрана, фінальний запит. Ці дані — навчальна вибірка для наступної версії рейтингувача.
Процес роботи
Аналіз пошукових логів: топ-1000 запитів, паттерни опечаток, мова/транслітерація.
Настройка Elasticsearch Completion Suggester з fuzzy matching.
Розробка персоналізованого рейтингувача підказок.
Реалізація on-device кеша + debounce логіки на iOS/Android.
Орієнтири за часом
ES Completion Suggester без персоналізації — 2–3 дні. З персоналізованим рейтингувачем та on-device кешем — 1,5–2 тижні.







