AACSearch / руководство
Правила поиска и синонимы
Мерчандайзинг коллекции с сервера — фильтр исключения, бусты, закрепления, редиректы, разнообразие, fallback при нуле результатов, расписание — и словарь: синонимы, стоп-слова, словари стемминга.
Правила поиска и синонимы меняют то, что возвращает поиск, не меняя запрос, который отправляет витрина. Это конфигурация, поэтому каждой операции на этой странице нужен полный ключ (см. ключи и области доступа); виджет с поисковым или браузерным ключом получит изменения при следующем поиске.
В примерах используется клиент TypeScript SDK из
быстрого старта и curl с
-H "X-NOVA-API-KEY: $NOVA_API_KEY".
Один набор правил на коллекцию
У коллекции один набор правил:
| Операция | Эндпоинт |
|---|---|
getSearchRule | GET /collections/{collectionName}/search_rules |
upsertSearchRule | PUT /collections/{collectionName}/search_rules |
deleteSearchRule | DELETE /collections/{collectionName}/search_rules |
listSearchRules | GET /search_rules — правила всех коллекций |
upsertSearchRule заменяет весь набор: поле, которое вы не передали,
сбрасывается к значению по умолчанию. Сначала прочитайте текущий набор, измените
его и отправьте обратно. Изменение действует со следующего поискового запроса.
const current = await client.searchRules.getSearchRule({ collectionName: "products" });
const { collection, updated_at, ...rules } = current;
await client.searchRules.upsertSearchRule({
collectionName: "products",
body: { ...rules, exclusion_filter_by: "active:=true" },
});Фильтр исключения
exclusion_filter_by — выражение filter_by, которое добавляется через AND к
каждому поиску коллекции, например
active:=true && stock_status:!=discontinued. Он применяется на сервере, так что
ни виджет, ни скопированный ключ не могут его обойти.
Бусты
boosts поднимают документы, подходящие под фильтр, выше остальных:
{
"boosts": [
{ "name": "In stock", "filter_by": "in_stock:true", "weight": 2 },
{ "name": "Clearance last", "filter_by": "clearance:true", "weight": -1 }
]
}- Больший
weight— выше в выдаче; отрицательный опускает вниз. По умолчанию1. - Документ получает оценку самого тяжёлого буста, под который попадает, —
веса не суммируются. Для совместного эффекта объедините условия в одном бусте
(
in_stock:true && has_image:true) с большим весом. - По умолчанию бусты действуют только на поиск, упорядоченный по релевантности,
поэтому явная сортировка «по цене» остаётся строго по цене. Задайте
boosts_override_sort: true, чтобы бусты шли передsort_byвызывающего. priorityразрешает конфликт, когда бусты дают и правило коллекции, и активные кампании.
Закрепления и спонсорские места
Буст влияет только на оценку сортировки. Закрепление гарантирует место:
pins вставляют doc_id в позицию position (с нуля) уже после ответа движка —
независимо от равенства оценок, бустов и сортировки вызывающего.
{
"pins": [
{ "query": "iphone", "match": "prefix", "doc_id": "iphone-17", "position": 0 },
{ "filter_contains": "category:=shoes", "doc_id": "sneaker-42", "position": 2 }
]
}Закрепление с query срабатывает, когда текст поиска совпадает (exact,
prefix или contains). Закрепление с filter_contains срабатывает, когда
filter_by вызывающего дословно содержит эту строку, — так закрепляют товар на
странице категории без текста поиска. Закрепление без обоих полей действует на
каждый поиск. Если несколько закреплений претендуют на одно место, побеждает
больший priority.
Записи sponsored (id, position, query/match, filter_by, label)
размещаются так же, а возвращённый хит несёт маркер _sponsored, чтобы UI мог
подписать его «Реклама». Спонсорское место размещает только документ, который
движок уже вернул по этому запросу.
Редиректы, подсказки и баннеры
redirects— когдаqсовпадает сquery, результат поиска содержитredirect: { url, query }. Хиты всё равно возвращаются, так что клиент без навигации продолжает работать; витрине стоит перейти наurl.suggestions— уточнения, предлагаемые при совпаденииq, например «телефон» → «телефон Apple», «телефон Samsung».banners— произвольный блокcontent(картинка, заголовок, ссылка), который показывается рядом с результатами, когдаqueryсовпадает сqилиfilter_contains— сfilter_byвызывающего. У каждого баннера стабильныйid.
Разнообразие
Правила diversity перестраивают итоговый порядок хитов:
| Настройка | Эффект |
|---|---|
field + max | не больше max хитов с одним значением, например 3 на brand |
field + min (+ from) | каждое присутствующее значение получает минимум min мест в первых from хитах |
near_duplicate | убирает хиты, текст которых по fields почти совпадает с более ранним (threshold, по умолчанию 0.9) |
mmr | переупорядочивает страницу по Maximal Marginal Relevance |
Порядок применения: подавление почти-дубликатов, ограничения max, MMR, минимумы
min.
Когда поиск ничего не нашёл
zero_hits_fallback решает, что вернёт пустой поиск:
| Значение | Возвращает |
|---|---|
none (по умолчанию) | пустой результат |
broaden_query | тот же поиск, повторённый без filter_by вызывающего |
recommendation_model | документы, подходящие под фильтр модели fallback_model_id — задайте и fallback_model_id |
Ответ с fallback несёт заголовок x-nova-fallback с использованным значением.
Расписание и таргетинг
starts_at/ends_at(date-time) — вне этого окна набор правил ведёт себя так, будто не настроен.device(desktop,mobile,tablet),language(тег BCP-47) иcountry(ISO 3166-1 alpha-2) ограничивают правила запросами, у которых query-параметрx_device,x_languageилиx_countryсовпадает точно.
Что сделало правило
Добавьте к поиску debug=true или отправьте X-NOVA-DEBUG: 1. В ответе появится
_trace — его запись rule перечисляет, что применилось (фильтр исключения,
скомпилированное условие бустов, сработавшие закрепления, редирект, баннеры,
подсказки, отброшенное разнообразием), — а у каждого хита объект _explain с
бустами, под которые он попал. Каждый ответ поиска несёт заголовок
X-Nova-Trace-Id, по которому его можно найти в журнале запросов.
curl "https://api.aacsearch.com/v1/collections/products/documents/search?q=iphone&query_by=name&debug=true" \
-H "X-NOVA-API-KEY: $NOVA_API_KEY"Наборы синонимов
Синонимы хранятся в именованных наборах, на которые ссылаются коллекции и поисковые запросы:
| Операция | Эндпоинт |
|---|---|
upsertSynonymSet | PUT /synonym_sets/{synonymSetName} — создать или заменить набор |
upsertSynonymSetItem | PUT /synonym_sets/{synonymSetName}/items/{itemId} — один элемент |
retrieveSynonymSets, retrieveSynonymSet, retrieveSynonymSetItems, retrieveSynonymSetItem | чтение |
deleteSynonymSet, deleteSynonymSetItem | удаление |
exportSynonymSet, importSynonymSet | GET …/export, POST …/import |
У элемента есть id и synonyms. Без root слова взаимозаменяемы; с root
связь односторонняя: поиск по любому слову из synonyms находит и root.
locale выбирает токенизатор, а symbols_to_index сохраняет спецсимволы,
которые иначе отбрасываются.
await client.synonyms.upsertSynonymSet({
synonymSetName: "catalog",
body: {
items: [
{ id: "drill", synonyms: ["дрель", "шуруповёрт", "дрель-шуруповёрт"] },
{ id: "tv", root: "телевизор", synonyms: ["тв", "телек"] },
],
},
});Набор действует там, где на него ссылаются:
-
В коллекции —
updateCollectionсsynonym_sets, тогда их использует каждый поиск коллекции:await client.collections.updateCollection({ collectionName: "products", body: { synonym_sets: ["catalog"] }, }); -
В отдельном поиске — параметр поиска
synonym_sets(имена через запятую).
В отдельном поиске enable_synonyms=false отключает синонимы,
synonym_prefix=true применяет их к префиксам слов, а synonym_num_typos
разрешает их для слов, исправленных по опечаткам.
Предложенные синонимы
generateSynonymSuggestions
(POST /collections/{collectionName}/synonym_suggestions/generate) предлагает
синонимы; listSynonymSuggestions выводит их, а acceptSynonymSuggestion /
rejectSynonymSuggestion принимают решение. deleteSynonymSuggestion
(DELETE /synonym_suggestions/{suggestionId}) удаляет предложение, не
принимая и не отклоняя его, — для устаревшего или ошибочно созданного.
Один из источников — запросы без результатов из ваших
событий: передавайте
found в событиях search, чтобы они туда попадали. Предложения оплачиваются
кредитами (см. ключи и кредиты).
Наборы стоп-слов
Набор стоп-слов — именованный список слов, отбрасываемых из запросов до
сопоставления; полезен для служебных слов, которые алгоритмический токенизатор
знать не может. У набора есть массив stopwords и locale, выбирающий
токенизатор:
| Операция | Эндпоинт |
|---|---|
upsertStopwordsSet | PUT /stopwords/{setId} — создать или заменить |
retrieveStopwordsSets | GET /stopwords |
retrieveStopwordsSet | GET /stopwords/{setId} |
deleteStopwordsSet | DELETE /stopwords/{setId} |
await client.stopwords.upsertStopwordsSet({
setId: "noise-words",
body: { stopwords: ["купить", "недорого", "online"], locale: "ru" },
});Набор применяется там, где поиск его называет: передайте идентификатор набора
в параметре поиска stopwords. Функция тарифа stopwords есть на всех
тарифах (см. тарифы).
Словари стемминга
Стеммер приводит словоформы к корню, чтобы «куртки» находили «куртку».
Алгоритмический стеммер ошибается на неправильных словах; словарь стемминга
чинит ровно эти случаи явными парами слово → корень.
| Операция | Эндпоинт |
|---|---|
listStemmingDictionaries | GET /stemming/dictionaries |
getStemmingDictionary | GET /stemming/dictionaries/{dictionaryId} |
importStemmingDictionary | POST /stemming/dictionaries/import — JSONL с парами слов |
await client.stemming.importStemmingDictionary({
id: "irregular-plurals",
body: '{"word": "люди", "root": "человек"}\n{"word": "дети", "root": "ребёнок"}\n',
});Наборы курирования
Набор курирования содержит правила для отдельных запросов: вставить
документы на позиции, скрыть документы, заменить запрос или переопределить
sort_by. Большую часть закреплений под запрос покрывают pins правил
поиска; набор курирования нужен, когда правилу требуется несколько
элементов с разными позициями или срабатывание только при точном
совпадении filter_by.
| Операция | Эндпоинт |
|---|---|
upsertCurationSet | PUT /curation_sets/{curationSetName} — создать или заменить описание набора |
retrieveCurationSets | GET /curation_sets |
retrieveCurationSet | GET /curation_sets/{curationSetName} |
deleteCurationSet | DELETE /curation_sets/{curationSetName} |
upsertCurationSetItem | PUT /curation_sets/{curationSetName}/items/{itemId} — одно правило |
retrieveCurationSetItems | GET /curation_sets/{curationSetName}/items |
retrieveCurationSetItem | GET /curation_sets/{curationSetName}/items/{itemId} |
deleteCurationSetItem | DELETE /curation_sets/{curationSetName}/items/{itemId} |
rule элемента решает, когда он срабатывает — query с match: "exact"
или "contains", либо filter_by, дословно сверяемый с filter_by
вызывающего. includes (id, position) и excludes (id) — закрепления
и исключения для запроса; filter_by, sort_by и replace_query
переопределяют соответствующие части поиска; remove_matched_tokens
убирает слова правила из запроса перед поиском; metadata возвращается как
есть при срабатывании — для баннера или сообщения, которое отрисует
витрина.
await client.curationSets.upsertCurationSet({
curationSetName: "black-friday",
body: { description: "Мерчандайзинг чёрной пятницы", items: [] },
});
await client.curationSets.upsertCurationSetItem({
curationSetName: "black-friday",
itemId: "drill-push",
body: {
rule: { query: "дрель", match: "contains" },
includes: [{ id: "cordless-drill-42", position: 0 }],
metadata: { banner: "Чёрная пятница: ещё −10% на дрели" },
},
});Страница курирования в консоли редактирует тот же ресурс.
Пресеты, стоп-слова и стемминг
Сохраните повторно используемые параметры поиска как пресет, исключите шумовые слова стоп-словами и научите токенизатор нестандартным корням слов через словарь стемминга.
События и рекомендации
Отправляйте поведенческие события с витрины, настраивайте модели рекомендаций в коллекции и получайте похожие товары, «покупают вместе», тренды и персональные рекомендации.