The Elasticsearch ids query returns documents whose _id metadata field matches any value in a supplied list. It works against the internal _id field on every index, so no mapping is required. Use it for ad-hoc lookups when you already know the document identifiers but need to apply scoring, highlighting, aggregations, or filters that the multi-get API does not support.
Syntax
{
"query": {
"ids": {
"values": ["id1", "id2", "id3"]
}
}
}
The values array accepts strings. There are no other parameters on the ids query itself.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
values |
array of strings | yes | One or more _id values to match. |
Examples
Basic lookup of three documents:
GET /my-index/_search
{
"query": {
"ids": { "values": ["1", "4", "100"] }
}
}
Combine with a filter and source filtering:
GET /products/_search
{
"_source": ["name", "price"],
"query": {
"bool": {
"must": [ { "ids": { "values": ["sku-001", "sku-002", "sku-003"] } } ],
"filter": [ { "term": { "in_stock": true } } ]
}
}
}
Cross-index lookup (the same ids are searched across both indices):
GET /orders-2024,orders-2025/_search
{
"query": { "ids": { "values": ["a1b2", "c3d4"] } }
}
Use with aggregations - the ids query reduces the working set, then the aggregation runs on the matched documents:
GET /events/_search
{
"size": 0,
"query": { "ids": { "values": ["e1", "e2", "e3", "e4"] } },
"aggs": { "by_type": { "terms": { "field": "type" } } }
}
Performance and Use Notes
The ids query is internally rewritten to a TermInSetQuery over the _id field, which is fast for small to mid-size value lists. For pure point-lookup workloads where scoring, highlighting, and aggregations are not needed, the multi-get API (_mget) is the canonical choice - it skips the query phase entirely. The ids query is the right tool when you want id-based selection to participate in a regular search request.
Keep the values list bounded. Lists of thousands of ids inflate the request body, the term dictionary lookup cost, and the per-shard fetch. If you find yourself passing tens of thousands of ids, the data model is usually the problem: a terms query over an indexed key field is typically faster and more cacheable.
Misused ids lookups - especially in hot paths driven by application code - show up as elevated search latency without obvious cause. Pulse monitors Elasticsearch query patterns and flags inefficient id-based access patterns, so teams can replace them with _mget or a terms query before they show up as user-facing latency.
Common Mistakes
- Using
idsfor bulk retrieval of hundreds of documents when_mgetwould be faster. - Assuming the response order matches the input array order - it does not; add
sortif order matters. - Expecting an error for missing ids; the query silently skips ids that do not exist.
- Forgetting that
_idis always a string in the query, even if your application treats it as numeric. - Pairing
idswith a routing value that points to the wrong shard, causing zero hits.
Frequently Asked Questions
Q: How is the Elasticsearch ids query different from the multi-get API?
A: The ids query runs through the search pipeline and supports scoring, highlighting, aggregations, and source filtering across multiple indices. The multi-get API (_mget) skips the query phase and goes directly to the document store, making it faster for pure point lookups.
Q: Is there a hard limit on the number of ids in an ids query?
A: There is no fixed limit, but the request size is bounded by http.max_content_length (default 100 MB) and practical performance considerations. Lists above a few thousand ids typically perform better as a terms query against an indexed key field.
Q: Does the ids query work across multiple indices?
A: Yes. Targeting my-index-* or a comma-separated list of indices searches the same id values across all of them. If the same _id exists in more than one index, all matches are returned.
Q: Does the ids query return results in the order of the values array?
A: No. The ids query does not preserve input order. To return documents in a specific order, sort by a field, or post-process the response in the application.
Q: Can the ids query be used in a filter context?
A: Yes. Wrapping ids in bool.filter keeps it out of scoring and lets the result set be cached as a bitset, which is the recommended pattern when score is irrelevant.
Q: Why does my ids query return fewer documents than ids supplied?
A: Missing documents are silently skipped. Either the id never existed, the document was deleted (and the deletion has been merged away), or the request is hitting a routing alias that excludes the shard holding the document.
Related Reading
- Elasticsearch Bool Query: combine ids with other filter clauses.
- Elasticsearch Term Query: exact-value matching on indexed fields.
- Elasticsearch Invalid Multi-Get Operation: common errors from
_mgetrequests. - Elasticsearch Match Query: full-text alternative when you need analysis.
- Elasticsearch Constant Score Query: wrap an ids filter with a fixed score.