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"]
}
| Field | Default | Purpose |
|---|---|---|
query | match all | The query clause |
sort | by score | Sort clauses |
from | 0 | Pagination offset applied after merge. from + size must be ≤ 10000. |
size | 10 | Result count |
_source | true | true, 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
| Clause | Purpose |
|---|---|
match | Analyzed full-text match |
match_phrase | Phrase match, with optional slop |
term | Exact keyword match |
range | Numeric or datetime bounds |
bool | must / should / must_not / filter composition |
match_all | Every document |
geo_distance | Within a radius of a point |
geo_shape | Spatial relation against a shape field (also matches xy_shape and point fields) |
knn | Vector similarity over an embedded field |
late_interaction | ColBERT-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": []
}
}
coveragehits 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
| Method | Path | Purpose |
|---|---|---|
GET | /v1/node/version | Version, brand, OS, and build profile |
GET | /v1/node/status | Peers, storage, admission, liveness |
GET | /v1/node/explain | Ownership, readiness, and routing policy |
GET | /v1/node/stats | Indexing, storage, proof, and query counters |
GET | /v1/node/peers | Known peers with health and RTT |
GET | /v1/indexes | Indexes on this node |
PUT GET DELETE | /v1/indexes/{index} | Create, inspect, delete an index |
GET | /v1/indexes/{index}/_schema | Declared fields |
GET | /v1/indexes/{index}/_count | Document count |
POST | /v1/indexes/{index}/_doc | Index one document |
POST | /v1/indexes/{index}/_bulk | Index many |
POST | /v1/memory/remember · /v1/memory/recall | Agent memory |
GET | /v1/repositories | Backup repositories — Backup and restore |
PUT GET DELETE | /v1/repositories/{repo}/snapshots/{snapshot} | Create, describe, delete a snapshot |
POST | /v1/repositories/{repo}/snapshots/{snapshot}/_restore | Restore |
GET | /v1/snapshot_jobs | Snapshot, 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.