Search shard routing
editSearch shard routing
editTo protect against hardware failure and increase search capacity, Elasticsearch can store copies of an index’s data across multiple shards on multiple nodes. When running a search request, Elasticsearch selects a node containing a copy of the index’s data and forwards the search request to that node’s shards. This process is known as search shard routing or routing.
Adaptive replica selection
editBy default, Elasticsearch uses adaptive replica selection to route search requests. This method selects an eligible node using shard allocation awareness and the following criteria:
- Response time of prior requests between the coordinating node and the eligible node
- How long the eligible node took to run previous searches
-
Queue size of the eligible node’s
search
threadpool
Adaptive replica selection is designed to decrease search latency. However, you
can disable adaptive replica selection by setting
cluster.routing.use_adaptive_replica_selection
to false
using the
cluster settings API. If disabled, Elasticsearch routes
search requests using a round-robin method, which may result in slower searches.
Set a preference
editBy default, adaptive replica selection chooses from all eligible nodes and shards. However, you may only want data from a local node or want to route searches to a specific node based on its hardware. Or you may want to send repeated searches to the same shard to take advantage of caching.
To limit the set of nodes and shards eligible for a search request, use
the search API’s preference
query parameter.
For example, the following request searches my-index-000001
with a
preference
of _local
. This restricts the search to shards on the
local node. If the local node contains no shard copies of the index’s data, the
request uses adaptive replica selection to another eligible node
as a fallback.
response = client.search( index: 'my-index-000001', preference: '_local', body: { query: { match: { "user.id": 'kimchy' } } } ) puts response
GET /my-index-000001/_search?preference=_local { "query": { "match": { "user.id": "kimchy" } } }
You can also use the preference
parameter to route searches to specific shards
based on a provided string. If the cluster state and selected shards
do not change, searches using the same preference
string are routed to the
same shards in the same order.
We recommend using a unique preference
string, such as a user name or web
session ID. This string cannot start with a _
.
You can use this option to serve cached results for frequently used and
resource-intensive searches. If the shard’s data doesn’t change, repeated
searches with the same preference
string retrieve results from the same
shard request cache. For time series use cases, such as
logging, data in older indices is rarely updated and can be served directly from
this cache.
The following request searches my-index-000001
with a preference
string of
my-custom-shard-string
.
response = client.search( index: 'my-index-000001', preference: 'my-custom-shard-string', body: { query: { match: { "user.id": 'kimchy' } } } ) puts response
GET /my-index-000001/_search?preference=my-custom-shard-string { "query": { "match": { "user.id": "kimchy" } } }
If the cluster state or selected shards change, the same preference
string may not route searches to the same shards in the same order. This can
occur for a number of reasons, including shard relocations and shard failures. A
node can also reject a search request, which Elasticsearch would re-route to another
node.
Use a routing value
editWhen you index a document, you can specify an optional routing value, which routes the document to a specific shard.
For example, the following indexing request routes a document using
my-routing-value
.
POST /my-index-000001/_doc?routing=my-routing-value { "@timestamp": "2099-11-15T13:12:00", "message": "GET /search HTTP/1.1 200 1070000", "user": { "id": "kimchy" } }
You can use the same routing value in the search API’s routing
query
parameter. This ensures the search runs on the same shard used to index the
document.
response = client.search( index: 'my-index-000001', routing: 'my-routing-value', body: { query: { match: { "user.id": 'kimchy' } } } ) puts response
GET /my-index-000001/_search?routing=my-routing-value { "query": { "match": { "user.id": "kimchy" } } }
You can also provide multiple comma-separated routing values:
response = client.search( index: 'my-index-000001', routing: 'my-routing-value,my-routing-value-2', body: { query: { match: { "user.id": 'kimchy' } } } ) puts response
GET /my-index-000001/_search?routing=my-routing-value,my-routing-value-2 { "query": { "match": { "user.id": "kimchy" } } }
Search concurrency and parallelism
editBy default, Elasticsearch doesn’t reject search requests based on the number of shards the request hits. However, hitting a large number of shards can significantly increase CPU and memory usage.
For tips on preventing indices with large numbers of shards, see Size your shards.
You can use the max_concurrent_shard_requests
query parameter to control
maximum number of concurrent shards a search request can hit per node. This
prevents a single request from overloading a cluster. The parameter defaults to
a maximum of 5
.
response = client.search( index: 'my-index-000001', max_concurrent_shard_requests: 3, body: { query: { match: { "user.id": 'kimchy' } } } ) puts response
GET /my-index-000001/_search?max_concurrent_shard_requests=3 { "query": { "match": { "user.id": "kimchy" } } }
You can also use the action.search.shard_count.limit
cluster setting to set a
search shard limit and reject requests that hit too many shards. You can
configure action.search.shard_count.limit
using the
cluster settings API.