Skip to main content

Query API

Every node exposes the same HTTP API on port 8080. Send a query to any node holding the index; it plans the fan-out across the claims that make it up.

POST /v1/indexes/{index}/_search
Content-Type: application/json

A minimal query​

curl -s http://localhost:8080/v1/indexes/imagery/_search \
-H 'content-type: application/json' \
-d '{"query": {"match": {"title": "satellite imagery"}}}'

Request​

{
"query": {
"bool": {
"must": [
{"match": {"title": "glacier retreat"}}
],
"filter": [
{"range": {"captured_at": {"gte": "2024-01-01"}}}
]
}
},
"sort": [{"captured_at": "desc"}],
"from": 0,
"size": 25,
"_source": ["title", "captured_at", "sensor"]
}
FieldDefaultPurpose
querymatch allThe query clause
sortby scoreSort clauses
from0Pagination offset applied after merge. from + size must be ≤ 10000.
size10Result count
_sourcetruetrue, false, or an array of fields to return
collapse—Deduplicate by a stored field, keeping the top-scoring document per group
rerank—Post-fusion decay re-ranking by distance from an origin on a numeric or date field

from and size are rejected for kNN queries, which are sized by k.

Clauses​

ClausePurpose
matchAnalyzed full-text match
match_phrasePhrase match, with optional slop
termExact keyword match
rangeNumeric or datetime bounds
boolmust / should / must_not / filter composition
match_allEvery document
geo_distanceWithin a radius of a point
geo_shapeSpatial relation against a shape field (also matches xy_shape and point fields)
knnVector similarity over an embedded field
late_interactionColBERT-style MaxSim over a multi-vector field
{"knn": {"field": "embedding", "vector": [0.1, 0.2], "k": 10}}
{"geo_distance": {"distance": "10km", "location": {"lat": 40.7, "lon": -74.0}}}
{"geo_shape": {"field": "region", "relation": "within", "geometry": {"type": "Polygon", "coordinates": []}}}

Response​

{
"hits": {
"total": {"value": 124, "relation": "gte"},
"hits": [
{
"_id": "5d76c531-2d81-481e-8524-b03a5a1af04e",
"_score": 12.41,
"_version": "1789949076519.0.058a8b37…",
"_source": {
"title": "Puget Sound, cloud-free, 2024-06-11",
"sensor": "sentinel-2"
}
}
]
},
"took": 9,
"partial": false,
"coverage": {
"expected_claims": 4,
"served_claims": 4,
"skipped_claims": []
}
}
Always read coverage

hits alone cannot tell you whether you saw everything. An index is spread across claims, and a claim whose holder is asleep simply does not answer — partial and coverage are how you find out, rather than quietly receiving less than you asked for.

total.relation is gte, not eq: the total tracks size, so a small size reports a lower bound. To count a corpus, use _count rather than reading total from a small query.

Other endpoints​

MethodPathPurpose
GET/v1/node/versionVersion, brand, OS, and build profile
GET/v1/node/statusPeers, storage, admission, liveness
GET/v1/node/explainOwnership, readiness, and routing policy
GET/v1/node/statsIndexing, storage, proof, and query counters
GET/v1/node/peersKnown peers with health and RTT
GET/v1/indexesIndexes on this node
PUT GET DELETE/v1/indexes/{index}Create, inspect, delete an index
GET/v1/indexes/{index}/_schemaDeclared fields
GET/v1/indexes/{index}/_countDocument count
POST/v1/indexes/{index}/_docIndex one document
POST/v1/indexes/{index}/_bulkIndex many
POST/v1/memory/remember · /v1/memory/recallAgent memory
GET/v1/repositoriesBackup repositories — Backup and restore
PUT GET DELETE/v1/repositories/{repo}/snapshots/{snapshot}Create, describe, delete a snapshot
POST/v1/repositories/{repo}/snapshots/{snapshot}/_restoreRestore
GET/v1/snapshot_jobsSnapshot, restore and cleanup jobs

Namespaces mirror the index surface under /v1/namespaces/{ns}/… for the many-tenant case.

Creating an index​

curl -X PUT http://localhost:8080/v1/indexes/notes \
-H 'content-type: application/json' \
-d '{"schema": {"fields": {"body": {"type": "text"}}}}'

fields is a map keyed by field name, not a list. The CLI builds this shape for you — see index create.