Multi-search & Requêtes
Exécuter plusieurs requêtes de recherche en une seule requête pour l'autocomplétion, la recherche fédérée et les scénarios multi-index.
Le multi-search exécute plusieurs requêtes de recherche en un seul aller-retour HTTP. C'est essentiel pour l'autocomplétion (exécuter une requête de résultats + une requête de suggestions simultanément) et la recherche fédérée (rechercher dans plusieurs indexes à la fois).
Point de terminaison multi-search
Point de terminaison : POST /api/search/multi
Auth : Authorization: Bearer ss_search_your_key
{
searches: Array<{
indexSlug: string;
q: string;
queryBy?: string;
filterBy?: string;
facetBy?: string;
sortBy?: string;
page?: number;
perPage?: number;
highlightFields?: string;
}>;
}Réponse :
{
results: Array<SearchResponse>; // un résultat par recherche dans le même ordre
}Modèle d'autocomplétion
Le cas d'utilisation multi-search le plus courant : exécuter une recherche complète plus une requête de suggestions rapides simultanément.
const [mainResults, suggestions] = await client.multiSearch([
{
indexSlug: "products",
q: "wireless head",
queryBy: "title,brand,description",
perPage: 20,
facetBy: "brand,categories",
},
{
indexSlug: "products",
q: "wireless head",
queryBy: "title",
perPage: 5,
includeFields: "id,title",
highlightFields: "title",
},
]);Cela envoie une seule requête HTTP et récupère les deux ensembles de résultats simultanément.
Recherche fédérée sur plusieurs indexes
Rechercher dans plusieurs indexes et fusionner les résultats côté client :
const [productResults, articleResults] = await client.multiSearch([
{
indexSlug: "products",
q: "sustainability",
queryBy: "title,description,tags",
perPage: 10,
},
{
indexSlug: "knowledge",
q: "sustainability",
queryBy: "content,title",
perPage: 5,
},
]);Remarque : pour les résultats multi-index, fusionnez et reclassez côté client.
Paramètres de requête en détail
q — requête de recherche
La chaîne de recherche. Utilisez "*" pour une navigation par joker (pas de correspondance plein texte, utile pour la navigation filtrée).
{ "q": "wireless headphones" } // recherche plein texte
{ "q": "*" } // naviguer tout (combiner avec filterBy)queryBy — quels champs rechercher
Liste de champs séparés par des virgules. L'ordre compte — les champs antérieurs obtiennent un poids plus élevé par défaut.
{ "queryBy": "title,sku,brand,description" }Pour chaque champ, vous pouvez spécifier un poids personnalisé par champ :
{ "queryBy": "title,brand,description", "queryByWeights": "10,5,2" }filterBy — expression de filtre
Expression booléenne utilisant la syntaxe de filtre AACSearch :
Égalité : field:=value
field:=[value1, value2]
Plage : field:>100
field:[50..200]
Chaîne exacte : field:=value
Négation : field:!=value
ET logique : cond1 && cond2
OU logique : cond1 || cond2
Regroupement : (cond1 || cond2) && cond3Exemples :
"filterBy": "availability:=in_stock"
"filterBy": "price:[50..200] && brand:=[Sony, Bose]"
"filterBy": "categories:=Electronics && availability:!=out_of_stock"facetBy — calculer les comptages de facettes
Retourne les distributions de valeurs pour les champs spécifiés. Les champs de facette doivent être indexés avec facet: true
dans le schéma de collection.
{ "facetBy": "brand,categories,availability" }La réponse inclura facetCounts avec des paires valeur → comptage pour chaque champ de facette.
sortBy — ordre de tri
Tri sur un ou plusieurs champs :
{ "sortBy": "price:asc" }
{ "sortBy": "_text_match:desc,price:asc" }
{ "sortBy": "created_at:desc" }Champs de tri disponibles : price, sale_price, created_at, _text_match (score de pertinence).
Tolérance aux fautes de frappe
La tolérance aux fautes de frappe de AACSearch est appliquée automatiquement. Par défaut :
- 1 faute de frappe autorisée pour les requêtes de 5+ caractères
- 2 fautes de frappe autorisées pour les requêtes de 8+ caractères
Cela gère les fautes de frappe courantes comme « ecouteurs » → correspond à « écouteurs ».
Mise en surbrillance
Les termes correspondants sont mis en surbrillance avec des balises configurables :
{
"highlightFields": "title,description",
"highlightStartTag": "<em class='highlight'>",
"highlightEndTag": "</em>"
}Mises en surbrillance dans la réponse :
{
"highlights": [
{
"field": "title",
"snippet": "Sony <em class='highlight'>Wireless</em> <em class='highlight'>Headphones</em>"
}
]
}Pagination
Les résultats sont paginés en utilisant page (indexé à partir de 1) et perPage :
{ "page": 2, "perPage": 20 }La réponse inclut found (comptage total de correspondances) pour calculer les totaux de pages :
const totalPages = Math.ceil(results.found / perPage);Maximum perPage : 100. Pour les exports nécessitant plus de résultats, implémentez une itération basée sur curseur
en utilisant des valeurs de page croissantes.
Recommandations de performance
- Gardez
perPage ≤ 20pour la recherche au fil de la frappe (autocomplétion) - Utilisez
includeFieldspour ne retourner que les champs que vous affichez — réduit la taille de la réponse - Évitez d'exécuter des facettes à chaque frappe — appliquez un debounce de 150 à 300 ms
- Pour les grands ensembles de résultats avec de nombreuses facettes, envisagez de séparer la requête de facette de la requête principale en utilisant le multi-search
Limits
| Limit | Value |
|---|---|
| Max searches per multi-search request | 20 — enforced in public-handler.ts. |
Max perPage | 100 |
Max page | 1000 |
Max numTypos | 3 |
Max rangeFacets per search | 20 |
Exceeding the multi-search batch limit returns 400 invalid_input with the Zod path searches. Use two consecutive requests rather than batching past 20.
Partial failures
A multi-search request is atomic at the HTTP level — sub-searches can still fail individually inside a 200. Each result envelope carries its own status: success carries hits, found, page; failure carries error and code. Iterate the results array in order; treat any entry with error as a sub-search failure. A single sub-search failure does not roll back the others.
Common error reasons: collection_not_found, invalid_filter, not_authorized (scoped token mismatch), rate_limit_exceeded, internal_error. Engine errors are normalised before reaching the client (Invariant 6 — never echoed raw).
Shared authentication and quota
Authentication is per request, not per sub-search. The same Authorization: Bearer ss_search_* (or ss_scoped_*) header validates the entire batch. A scoped token's scopedFilter is AND-combined into every sub-search (Invariant 4).
Quota / rate limit treats the batch as a single HTTP unit but charges per sub-search. A 20-batch is 20× the unit cost of a single search.
Tenant isolation (Invariant 5) holds at the sub-search level — every sub-search has tenantId AND-combined automatically.
Analytics grouping
Each multi-search response carries a parent queryId (the whole batch) and a per-sub-result queryId. Click events posted via POST /events/track should carry the child queryId so per-search CTR computes correctly. Conversion events follow the same rule. See Analytics overview.
A common bug is to record clicks against the first sub-search's queryId regardless of which list the click came from — that inflates the suggestions-list CTR and deflates the main-results CTR. Always pass through the specific child queryId.
Caching and debouncing
Recommended values (matching the bundled widget): keystroke debounce 200 ms (range 150–300 ms), min characters 2, client-side LRU 30 entries scoped to indexSlug, popular-queries TTL 10 min.
Do not extend the server-side response cache without a rate-limit-aware invalidation path — stale suggestions can keep linking to products that have been removed by a curation change.
Federated suggestions example
Combining a primary product search with a categories suggestion and an articles suggestion in one round-trip:
const [products, categories, articles] = await client.multiSearch([
{ indexSlug: "products", q: "wireless head", queryBy: "title,brand,description", perPage: 20, facetBy: "brand,categories" },
{ indexSlug: "categories", q: "wireless head", queryBy: "name,aliases", perPage: 3, includeFields: "id,name,slug" },
{ indexSlug: "articles", q: "wireless head", queryBy: "title,excerpt", perPage: 3, includeFields: "id,title,url,published_at" },
]);Three sub-searches still count as three units against the rate-limit bucket — budget accordingly.
Tokens de recherche limités
Générer des tokens HMAC de courte durée qui restreignent les permissions d'une clé de recherche — filtres par utilisateur, durée de vie et modèle de sécurité.
Filtres, tri & pagination
Référence complète pour les expressions de filtre, les options de tri, les facettes et la pagination dans les requêtes AACsearch.