Semantic Search
Semantic search lets users search by describing what they want rather than typing the exact words that appear in your documents. A query like movies about a man who loses his memory or tom hanks movies is interpreted by an LLM, expanded into targeted keyword searches against your index, and the results are fused into a single ranked list. Scores are calibrated onto the same BM25 scale as a standard keyword search, so semantic results read like any other Searchcraft search response.
Unlike vector search, Searchcraft semantic search does not use embeddings or a vector index. There is no re-ingestion or backfill step. It works on your existing index the moment AI configuration is in place.
Semantic search runs through the standard search endpoints as an additional query kind alongside fuzzy, exact, and dynamic.
How This Differs From Vector Search
Section titled “How This Differs From Vector Search”Most semantic search offerings are built on vector embeddings, and that choice commits you to a pipeline you have to maintain forever:
- Every document must be run through an embedding model at ingestion time before it is semantically searchable, adding cost and lag to every write.
- The resulting vectors must be stored in a separate ANN (approximate nearest neighbor) index, which grows your storage and memory footprint alongside the text index.
- Every document update means re-embedding the document and updating the vector index to keep it in sync.
- Upgrading or switching the embedding model, which is the main lever for improving vector search quality, invalidates every stored vector and forces a full re-embedding of the entire corpus.
Searchcraft skips all of that. The LLM interprets the query rather than your documents, so the only index involved is the full-text index you already have:
- Instant enablement. Turning semantic search on is a single
PATCHto the index’saiconfiguration. Every document already in the index is semantically searchable immediately, with no backfill job and no embedding queue to drain. - Nothing to keep in sync. Newly ingested documents are semantically searchable as soon as they are committed, exactly like keyword search. There is no window where a document is findable by keyword but invisible to semantic queries.
- Free model upgrades. Changing
intent_detection_modelto a newer, smarter, or cheaper model takes effect on the next query. There is no corpus to reprocess; the intent cache simply repopulates against the new model. - No extra infrastructure. No vector database, no ANN index tuning, no additional storage or memory beyond the standard index. The per-query cost is one small LLM call (cached across repeated queries), not a per-document embedding cost across your whole corpus.
It also means semantic quality benefits from the relevancy tuning you have already done. Field weights, synonyms, stopwords, and language stemming all apply, because the searches being run are standard searches.
Searchcraft Cloud: The intent detection model is pre-determined by Searchcraft and cannot be changed. If your plan includes AI and AI is enabled, semantic search is configured automatically, so there is nothing for you to set up. The configuration options below (
llm_provider,intent_detection_model, and related fields) are intended only for self-hosted installs.
API Endpoint Reference
Section titled “API Endpoint Reference”POST /index/:index/searchAccepts asemanticquery clause when the index has AI configured.POST /federation/:federation_name/searchAccepts asemanticquery clause when the federation itself has AI configured.GET /index/:index/capabilitiesReturns AI capability flags, including whether semantic search is configured.GET /federation/:federation_name/capabilitiesReturns AI capability flags for a federation. See Search Result Summaries for details.
Semantic clauses are not supported on POST /index/:index/search/summary or POST /federation/:federation_name/search/summary. A summary request containing a semantic clause returns a 400 response.
Auth Requirement
Section titled “Auth Requirement”Authenticated requests containing a semantic clause require a key with the LLM_RAG_SUMMARIES permission. A plain read/search key is not sufficient. See the Access Keys reference for key types. If your instance runs without authentication enabled, no key is required.
Prerequisites
Section titled “Prerequisites”Searchcraft Cloud: Semantic search is configured automatically when your plan supports AI and AI is enabled. The prerequisites below apply to self-hosted installs only.
Before an index can serve semantic queries it needs:
ai_enabledset totrueon the index.- An
aiconfiguration block with anllm_provider(plus that provider’s required credential fields) and anintent_detection_model.
See Optional AI configuration for the full configuration reference and provider credential requirements. For federations, the federation itself needs ai_enabled and a matching ai configuration block. A federation resolves semantic search configuration entirely from its own ai_enabled and ai fields, never from member indexes, even when every member index has AI fully configured. See Optional AI configuration on the Federation Management page.
Use the capabilities endpoint to verify readiness:
curl -H "Authorization: read-key-value" https://searchcraft-cluster-url/index/data_test/capabilities{ "status": 200, "data": { "ai": { "enabled": true, "searchSummaryConfigured": false, "llmProviderConfigured": true, "llmModelConfigured": false, "semanticSearchConfigured": true, "intentDetectionModelConfigured": true } }}semanticSearchConfigured is true when both llm_provider and intent_detection_model are set on the index.
Configuration
Section titled “Configuration”This section applies to self-hosted installs only. On Searchcraft Cloud the intent detection model is pre-determined and cannot be changed.
Semantic search adds one new field to the ai configuration block:
ai.intent_detection_model- Optional string. The model identifier used for semantic intent detection. Must be non-empty when present. Required for thesemanticquery kind to be available. Intent detection is a small, latency-sensitive prompt, so a fast lightweight model is a good fit.
Example CURL request to enable semantic search with Bedrock
Section titled “Example CURL request to enable semantic search with Bedrock”curl -X PATCH \ -H "Content-Type: application/json" \ --data '{ "ai": { "llm_provider": "bedrock", "llm_region": "us-east-1", "intent_detection_model": "global.anthropic.claude-haiku-4-5-20251001-v1:0" } }' \ https://searchcraft-cluster-url/index/data_testNote: On Bedrock, newer Claude models cannot be invoked with a bare foundation model ID. Use an inference-profile prefixed ID. The
global.prefix carries no pricing premium, whileus./eu.regional prefixes add a surcharge. A bare model ID will fail with a BedrockValidationException.
The same providers available for Search Result Summaries are supported for intent detection: anthropic, bedrock, google, llamacpp, mistral, ollama, openai, and xai. PATCH replaces the entire ai block when present, so include your full desired AI configuration (including any existing search_summary settings) when adding intent_detection_model.
Making a Semantic Query
Section titled “Making a Semantic Query”A semantic clause carries a single ctx value containing the natural-language search term:
curl -X POST -H "Content-Type: application/json" -H "Authorization: llm-key-value" --data '{"query":{"semantic":{"ctx":"tom hanks movies"}}}' https://searchcraft-cluster-url/index/data_test/searchSemantic clauses compose with the rest of the query payload. Filters and other clauses in the same payload are applied to every expanded search, and the standard top-level parameters (limit, offset, order_by, sort) apply to the final fused result set:
curl -X POST -H "Content-Type: application/json" -H "Authorization: llm-key-value" --data '{"limit":10,"query":[{"semantic":{"ctx":"movies about a man who loses his memory"}},{"occur":"must","term":{"ctx":"/movies","fields":"category"}}]}' https://searchcraft-cluster-url/index/data_test/searchComposition rules:
- Only one
semanticclause is allowed per query. - A semantic clause cannot use
"occur": "mustnot". - The
ctxvalue must be text.
Violating any of these returns a 400 response.
How It Works
Section titled “How It Works”Semantic search is a query-side feature. Your documents and your index are left alone; the LLM only ever sees the search term, and your existing full-text index does the actual searching.
- Intent detection. The model you configure as
intent_detection_modelreads the search term along with your index’s searchable fields, and returns a short statement of what the user is after plus a ranked set of expansion keywords grounded in the vocabulary that actually appears in your corpus. Detected intents are cached, so repeat queries skip this step. - Targeted full-text search. The expansion runs as a set of weighted standard searches, executed concurrently. Every non-semantic clause in your payload (filters, term clauses, occur rules) is applied to each of them. On a federation, each one runs as a full federated search, so your per-index weighting still applies.
- Fused ranking. The result sets are merged, deduplicated by document, and returned as a single ranked list with scores calibrated onto the normal BM25 scale. A semantic response reads on the same scale as a plain keyword search, so relative score thresholds you already rely on carry over.
Response
Section titled “Response”The response is the standard search response shape plus a semantic metadata block:
{ "status": 200, "data": { "hits": [ { "doc": { "title": "Forrest Gump", "id": "1187" }, "document_id": "1187", "score": 14.82 } ], "count": 37, "time_taken": 0.214, "semantic": { "original_query": "tom hanks movies", "detected_intent": "The user wants films starring Tom Hanks.", "bm25_keywords": ["Forrest Gump", "Cast Away", "Saving Private Ryan"], "intent_cached": false } }}| Field | Description |
|---|---|
original_query | The ctx value from the semantic clause. |
detected_intent | The LLM’s one-sentence interpretation of the query. |
bm25_keywords | The expansion keywords that were searched, in ranked order (maximum 5). |
intent_cached | true when intent detection was served from cache and no LLM call was made. |
count reflects the total number of unique documents matched across all expanded searches, and time_taken covers the search execution (not the LLM call). hits, facets, and federation source_index values behave exactly as they do for standard searches.
Caching, Latency, and Provider Failures
Section titled “Caching, Latency, and Provider Failures”Detected intents are cached, keyed on the query text, provider, and model, so repeated semantic queries skip the LLM call entirely (intent_cached: true). The cache honors the server’s standard cache settings (SEARCHCRAFT_CACHE_ENABLED, SEARCHCRAFT_CACHE_TTL_SECONDS, SEARCHCRAFT_CACHE_MAX_MEMORY_MB), and because the intent depends only on the query and model, cached intents survive re-indexing. Disabling the server cache means every semantic request pays an LLM round trip.
On a cache miss, a semantic query makes at least one LLM round trip before the search runs, so it will always be slower than a plain keyword query. Semantic search is best suited to deliberate, submitted searches rather than search-as-you-type.
If the LLM provider fails at request time (unreachable, rate limited, or returns an error), the request fails with a 502. Configuration errors (missing model, invalid provider) return a 400 HTTP error.
Error Reference
Section titled “Error Reference”| Status | Message | Cause |
|---|---|---|
| 400 | only one semantic clause is allowed per query | Multiple semantic clauses in the payload. |
| 400 | a semantic clause cannot use occur "mustnot" | Semantic clause negated with mustnot. |
| 400 | a semantic clause requires a text value | Non-text ctx value. |
| 401 | semantic queries require a key with LLM permissions | Key lacks the LLM_RAG_SUMMARIES permission. |
| 400 | AI features are disabled for this index | ai_enabled is false on the index. |
| 400 | AI features not configured for this index | No ai block on the index. |
| 400 | AI features are disabled for this federation | ai_enabled is false on the federation. |
| 400 | AI features not configured for this federation | No ai block on the federation. |
| 400 | intent_detection_model is not configured for this index | ai block exists but intent_detection_model is missing. |
| 400 | semantic query clauses are not supported on the summary endpoint | Semantic clause sent to POST /index/:index/search/summary. |
| 500 | All keyword searches failed | Every expanded search failed to execute. |
| 502 | Semantic search failed: the LLM provider could not complete intent detection (...) | The LLM provider failed during intent detection; the provider’s error is included in parentheses. |