Full-Text Search — MDDB API
Keyword-based full-text search
Full-text search #
POST /v1/fts
Perform full-text search across documents in a collection. Supports 7 search modes with auto-detection and multi-language stemming (18 languages).
Search modes (mode parameter, default auto):
simple: Classic keyword search scored by algorithm (TF-IDF, BM25, BM25F, PMISparse)boolean: AND/OR/NOT operators,+required,-excludedtermsphrase: Exact word sequence matching using"quoted phrases"wildcard: Pattern matching with*(any chars) and?(single char)proximity: Terms within N words —"term1 term2"~5auto(default): Auto-detects mode from query syntax (quotes → phrase, operators → boolean, etc.)
Algorithms (for simple/boolean modes):
tfidf(default): Classic TF-IDF scoringbm25: Okapi BM25 with document length normalization (k1=1.2, b=0.75)bm25f: BM25F field-weighted scoring — applies different weights to title, metadata, and content fieldspmisparse: PMISparse — BM25 + PMI query expansion
Range filtering: Use rangeMeta to filter by numeric, date, or string ranges on metadata fields.
In-graph filtering: Use filterMeta to narrow results by metadata before scoring, same as vector search.
Authorization: BearerAuth or APIKeyAuth or none
Request body #
Required.
Content type application/json: FTSSearchRequest
{
"algorithm": "bm25",
"bm25B": 0.75,
"bm25K1": 0,
"boost": {
"category:health": -2,
"tag:breed": 5
},
"cacheTtl": 60,
"collection": "blog",
"disableStem": false,
"disableSynonyms": false,
"distance": 5,
"facetBy": [
"category",
"lang"
],
"facetMaxValues": 0,
"facetScope": "returned",
"fieldWeights": {
"content": 1,
"meta": 2,
"title": 3
},
"filter": {
"kind": {
"not": [
"test"
]
},
"modified": {
"gte": "2026-09-01"
},
"path": {
"prefix": "internal/"
},
"size": {
"lt": 10000
},
"summary": {
"exists": true
},
"title": {
"contains": "hnsw"
}
},
"filterMeta": {
"category": [
"tutorial"
]
},
"format": "results",
"fragmentSize": 150,
"fuzzy": 0,
"groupBy": {
"key": "path",
"perGroup": 1
},
"highlight": false,
"highlightTag": "\u003cmark\u003e",
"includeImages": false,
"lang": "en",
"limit": 50,
"maxHighlights": 3,
"mode": "auto",
"passageLines": 0,
"query": "cancel subscription",
"rangeMeta": [
{
"field": "price",
"gt": "string",
"gte": "10",
"lt": "string",
"lte": "100"
}
]
}
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Full-text search results | oneOf FTSSearchResponse | PassagesResponse (application/json) |
400 |
Invalid request | ErrorResponse (application/json) |
Reindex FTS for a collection #
POST /v1/fts-reindex
Re-indexes all documents in a collection using their stored lang field for language-aware stemming and stop words.
Use this after enabling multi-language support to update existing documents indexed with the default English pipeline.
Every document is rebuilt from scratch, unlike a write, which since v2.18.10 re-indexes only what changed (#367):
run it after changing stop words, stemming or the collection's fts.excludeMetaKeys.
Authorization: BearerAuth or APIKeyAuth or none
Request body #
Required.
Content type application/json: object
| Property | Type | Description |
|---|---|---|
collection (required) |
string |
Collection name to reindex |
{
"collection": "string"
}
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Reindex completed | object (application/json) |
500 |
The documents could not be read | |
400 |
Body is not JSON, or collection is missing |
ErrorResponse (application/json) |
Prefix autocomplete #
GET /v1/autocomplete
Return up to topN terms starting with the given query, ranked by
document frequency. Uses the existing FTS inverted index — no
additional indexing is required.
When field is supplied, the BM25F field-scoped index drives the
scan so callers can autocomplete titles, tags, or body content
independently. A single call scans at most 10000 index entries to
keep latency bounded on pathological prefixes like "a".
Authorization: BearerAuth or APIKeyAuth or none
Parameters #
| Name | In | Type | Description |
|---|---|---|---|
collection (required) |
query | string |
Collection name |
q (required) |
query | string |
Prefix query — lowercased and stripped of non-alphanumerics |
field |
query | string |
Optional field scope (e.g. title, content, meta.tags); empty means global |
topN |
query | integer |
Maximum number of suggestions returned, never above MDDB_SEARCH_MAX_LIMIT or the collection's retrieval.maxTopK (v2.18.10+). Default 10. |
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Suggestions | object (application/json) |
400 |
The request is malformed (a body that is not JSON, a missing or invalid field, an unreadable body) or names a subsystem that is not initialized. The message says which. | ErrorResponse (application/json) |
401 |
Auth is on (MDDB_AUTH_ENABLED=true) and the request carries no credentials, an invalid or expired JWT, or an unknown API key. | ErrorResponse (application/json) |
403 |
The caller lacks the permission the route needs (SEC-019 access gate, auth on: read, write or admin on the collections the request names), or a write meets read-only mode (MDDB_MODE=read or the protocol's own mode). | ErrorResponse (application/json) |
429 |
The client is over the API rate limit (MDDB_RATE_LIMIT_ENABLED=true, MDDB_RATE_LIMIT_REQUESTS per MDDB_RATE_LIMIT_WINDOW seconds). A call that embeds can also be refused by the collection's daily embedding budget, with a QuotaExceeded body. | RateLimitError (application/json) |
400 example (application/json)
{
"error": "missing collection"
}
401 example (application/json)
{
"error": "missing authentication"
}
403 example (application/json)
{
"error": "forbidden"
}
List supported FTS languages #
GET /v1/fts-languages
Returns all supported languages for multi-language FTS with their codes, names, and the configured default language.
Authorization: BearerAuth or APIKeyAuth or none
Responses #
| Status | Description | Body |
|---|---|---|
200 |
Supported languages | object (application/json) |
401 |
Auth is on (MDDB_AUTH_ENABLED=true) and the request carries no credentials, an invalid or expired JWT, or an unknown API key. | ErrorResponse (application/json) |
429 |
The client is over the API rate limit (MDDB_RATE_LIMIT_ENABLED=true, MDDB_RATE_LIMIT_REQUESTS per MDDB_RATE_LIMIT_WINDOW seconds). A call that embeds can also be refused by the collection's daily embedding budget, with a QuotaExceeded body. | RateLimitError (application/json) |
401 example (application/json)
{
"error": "missing authentication"
}