Searching an index
This guide shows you how to construct search requests using query clauses, filters, facets, and pagination options. Use this guide when building a search interface for an index. For the complete query syntax and options, see the Search API.
Prerequisites
Section titled “Prerequisites”Before you begin, ensure that you have:
- A configured index with indexed documents. For more information, see Define an index.
-
Send an initial search request to retrieve default results:
POST /v1alpha1/indexes/products/search{}An empty request matches every document and returns the first 10 documents. Use this request to populate a search page before a user enters text or selects filters.
-
Add a text search clause to match user search input:
{"query": [{ "type": "text", "text": "rain jack", "fields": { "name": 3, "description": null } }]}The
textclause searches text fields. Specifyfieldsto define where to search and to set relative weights for matches in each field. If you omitfields, the query searches every searchable field. The search treats the last word as a prefix, sorain jackmatchesRain jacket.Configure search options as needed:
- Set
"match": "user"to interpret quotes and minus signs as user search syntax. Use this setting for text entered by a user. Leave the default"match": "all"for text generated by your application code. - Set
"join": "any"on a clause with"match": "user"to return documents that match one part of the typed text instead of all of it. Use this setting for a search box over documentation or articles. Excluded terms still apply. - Set
"relax"to drop unmatched words instead of returning no results. By default, the search drops words that match no documents, and the response reports dropped words inrelaxed. - When a number field of the index declares a unit, user mode reads a
number typed next to the unit or next to a comparative word as a filter
on that field, and the response reports it in
interpreted. Setinterpretto an object withfieldsto choose which fields the number is read on, such as the pricelist of the current customer. For more information, see Read numbers in the search box.
If you query a field that is not enabled in the index definition, the API returns the error
search:usage_unsupported. - Set
-
Separate the base search scope from user filter refinements:
{"query": [{ "type": "text", "text": "jacket" },{ "field": "published", "match": { "value": true } }],"filters": [{ "field": "category", "match": { "type": "in", "values": ["Outerwear"] } },{ "field": "price", "match": { "type": "range", "gte": 50, "lt": 200 } }]}Define conditions in
queryandfiltersbased on how they should affect facet counts:- Put base scope conditions in
query(such as the search box, a catalog section, or a tenant identifier).queryconditions narrow both search results and all facet counts. - Put user-selected refinements in
filters(such as selected checkboxes). A facet excludes filters applied to its own field, which keeps other category values visible when a user selects a category likeOuterwear.
- Put base scope conditions in
-
Request facet counts to build filter lists:
{"facets": [{ "field": "category", "limit": 20 },{ "field": "price", "ranges": [{ "to": 100 },{ "from": 100, "to": 500 },{ "from": 500 }] }]}Add a
facetsarray to calculate value and range counts for fields marked withfacetin the index definition:- Value facets return counts in
values. Pass selected values back as aninfilter on the same field. - Range facets return counts in
buckets. Pass selected buckets back as arangesmatcher, usingfromasgteandtoaslt.
If you only need to refresh filter counts without retrieving hits, set
"limit": 0. For counting category trees or bucketing dates, see facets.totalValuessays how many distinct values match the search. The values past thelimitget no count of their own, so a filter list that has to show one needs a higherlimit.A facet returns at most 1000 values. To let a user type into a filter and reach the values past that cut, send the same
queryandfilterswith the typed text asprefixtoPOST /v1alpha1/indexes/{name}/facets/{field}/values. See Searching the values of a facet. - Value facets return counts in
-
Specify the sort order:
{ "sort": [ { "field": "price", "order": "asc" } ] }If you omit
sort, the search returns results ordered by relevance score or ranking signals (such as top sellers in a browsed category).Specifying
sortoverrides relevance ranking. To allow users to return to relevance sorting, omitsortor pass[ { "type": "score" } ]. -
Restrict response fields and add highlighting:
{"fields": ["name", "price", "image"],"highlight": { "fields": { "name": {}, "description": { "fragments": 1 } } }}- Use
fieldsto limit the returned fields. If omitted, the response includes all stored fields. To select a field inside an object, use dotted notation (for example,"fields": ["variants.price"]). If you request a field that the index cannot return, the request is rejected. - Use
highlightto return matching text fragments wrapped in<em>tags (or custom tags set bypreandpost). The returned fragments are not HTML-escaped; escape the text surrounding the highlight markers when rendering. Highlighting applies to the scoring query, not to filter matches.
- Use
-
Set the search locale for localized fields:
{ "query": [ { "type": "text", "text": "regnjakke" } ], "locale": "nb" }The
localeparameter selects and analyzes the appropriate language variant for the field. The search matches the tag as closely as the field’s declared locales allow (for example,nb-NOmatchesnb). If omitted, fields use their default locale. For supported language rules, see the locale reference. -
Paginate through search results:
{ "limit": 20, "after": "AW8..." }To paginate results, set
limitand pass the cursor returned inafterfrom the previous response. Cursor-based pagination withafterhas consistent performance at any depth. If you useoffset,offsetpluslimitis capped byEXOFIND_SEARCH_MAX_PAGE_DEPTH. To request numbered pages, usepages. For more information, see Paginate search results. -
Count matches without fetching document hits:
{ "query": [ ... ], "limit": 0, "total": "exact" }If you need document counts without returning hits, set
limitto0. By default,totalreturns a lower bound count. Set"total": "exact"when you need an exact count of all matching documents, such as for a numbered pagination control.
Confirming the result
Section titled “Confirming the result”Inspect the JSON response from the search endpoint to verify the results:
hits: Contains matching documents, each withid(the primary key) anddocument(the stored fields or requestedfields).facets: Contains facet counts undervaluesorbuckets.relaxed: Contains any search terms that were dropped whenrelaxwas active.interpreted: Contains any filters and remaining query text read from numbers typed with units or comparative words.total: Contains the count of matching documents.
Related
Section titled “Related”- Search API - Every clause, matcher, sort, and option.
- Architecture - Why a search runs on whichever node receives it and never has to reach a writer.
- Relevance - What decides the order when the search asks for none.
- Tuning ranking - Boosts, ranking signals, tie breakers, and rescoring, without reindexing.
- Searching from a search box - Sending what a person typed, and choosing how many of their words a document must hold.
- Searching by vector - Finding documents by meaning rather than by words.
- Using sub-documents - Asking several things of one value of an
objectfield, and ordering and counting by it. - Paginating search results - Offsets, cursors, and numbered pages.
- Reading numbers in the search box - Reading numbers and units out of search text as filters.
- Reading colours and brands in the search box - Reading the values of a facet field out of search text as filters.
- Localizing fields - Holding and searching values in several languages.
- Defining an index - Opting fields into the ways a search may use them.
Exofind is built by Level Four AB and is available under the Apache License 2.0.