A catalog search needs matching words, not only exact database-field equality. Arkoren combines full-text matching, field filters, and ordering behind a typed search engine. Your application chooses the documents to index; the engine returns those documents as typed hits.
Search Boundaries
An index declares a document type, its identity, and the fields available
for searching, filtering, and sorting. A query describes which documents
to match. The engine, *search.Engine, validates these definitions, converts
documents to and from JSON, and delegates storage and matching to a driver.
Choose and construct a backend in Search Drivers. Declare your document shape in Indexing Documents, then synchronize its index before putting documents or searching. Registration alone does not create a backend index.
Keep authoritative records in your database or another rebuildable source. Search does not automatically follow source changes, enforce application permissions, or replace your database. Backend ranking and capacity differ; facets, highlighting, and typo tolerance are outside the portable contract.
Finding Products
Assume engine is configured with the populated Products index from
Indexing Documents, and ctx is your
operation context. Import search from arkoren.dev/core/service/search and
pagination from arkoren.dev/core/pagination. Focused examples leave error
results visible but omit routine propagation; handle errors in your application.
For a tenant-scoped catalog search box, take tenantID from trusted,
authorized application state and combine it with the text and price filter:
query := search.NewQuery(Products, "red shoes", func(selection *search.QueryBuilder) {
selection.Where("tenant_id", tenantID)
selection.Where("price", "<=", 100)
})
This publishes an immutable query without performing I/O. It requires both words, allows the last word to match a prefix, and limits matches to products in that tenant costing at most 100. Run it to fetch one window:
page, err := engine.Search(ctx, query, pagination.PageParams{Page: 1, PerPage: 20})
page is a pagination.Page[search.Hit[Product]]. Its items contain each hit’s
stored ID, decoded Document, and Score; its metadata describes the bounded
result set. After checking err, use hit.Document.Title to display a product.
No matches produces an empty items collection, not search.ErrNotFound.
Reading Results
Without explicit sort keys, positive text matches rank by descending relevance, then ascending document ID. Scores are comparable only within one result, not between queries or drivers, and are not percentages. Empty or exclusion-only text has score zero.
Search reaches only the first 1,000 hits. Search Queries explains text syntax, permission filters, explicit ordering, and this result-window bound. The pagination guide explains the shared page types; its SQL examples are not search-query syntax.
Operation Boundaries
The engine rejects an invalid query before driver I/O. An unregistered index,
or a registered name used with a different field definition, returns
search.ErrNotFound. Invalid or duplicate registrations are retained at
construction and fail every operational call; Sync or Check exposes them
before serving requests.
Pass a context with a deadline when work must stop with its caller. Cancellation is cooperative: individual key callbacks and JSON encoders or decoders finish before the next facade check. A decode failure or cancellation during result decoding returns an error, not a successful partial page. Cancellation after writes begin does not imply rollback; see batch behavior.
The engine is safe for concurrent use when its driver is. Driver() and
DriverAs return shared drivers, not copies. Calling them directly bypasses
facade validation, JSON conversion, telemetry, and notifications. Configure
Monitoring on the engine to observe ordinary operations.
For application tests, use an independent Memory driver,
synchronize it, and put only the documents each test needs. Assert matching IDs
and explicit orders rather than backend-specific relevance scores. A custom
driver can use searchtest.Run from arkoren.dev/core/service/search/searchtest;
the conformance guide explains what a suite
does and does not establish. Memory tests do not prove native backend behavior.
For every function and option, see the search API reference.