当索引一个文档的时候,文档会被存储到一个主分片中。 Elasticsearch 如何知道一个文档应该存放到哪个分片中呢?当我们创建文档时,它如何决定这个文档应当被存储在分片 1 还是分片 2 中呢?
首先这肯定不会是随机的,否则将来要获取文档的时候我们就不知道从何处寻找了。实际上,这个过程是根据下面这个公式决定的:
shard_num = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。 routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到 余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。
这就解释了为什么我们要在创建索引的时候就确定好主分片的数量 并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。
自定义routing: 表示文档根据'kimchy'进行路由
POST twitter/mytype?routing=kimchy
{
"user" : "kimchy",
"post_date" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
根据routing值查询
GET twitter/mytype/1?routing=kimchy
或者
GET my_index/mytype/_search
{
"query": {
"terms": {
"_routing": [ "kimchy" ]
}
}
}
将请求发送到主动的routing上
GET my_index/_search?routing=user1,user2
{
"query": {
"match": {
"title": "document"
}
}
}
指定CRUD操作必须指定routing值
put 10.127.0.1:9200/myrouting/_mapping
{
"myrouting": {
"mappings": {
"my_type": {
"_routing": { "required": true },
"properties": {
"name": { "type": "keyword" }
}
}
}
}
}
请求时不指定routing值错误演示
post 10.127.0.1:9200/myrouting/my_type/1
{
"error": {
"root_cause": [
{
"type": "routing_missing_exception",
"reason": "routing is required for [myrouting]/[my_type]/[1]",
"index_uuid": "_na_",
"index": "myrouting"
}
],
"type": "routing_missing_exception",
"reason": "routing is required for [myrouting]/[my_type]/[1]",
"index_uuid": "_na_",
"index": "myrouting"
},
"status": 400
}
所有的文档 API( get 、 index 、 delete 、 bulk 、 update 以及 mget )都接受一个叫做 routing 的路由参数 ,通过这个参数我们可以自定义文档到分片的映射。一个自定义的路由参数可以用来确保所有相关的文档——例如所有属于同一个用户的文档——都被存储到同一个分片中。
而我们为什么会需要自定义的Routing模式呢?首先默认的Routing模式在很多情况下都是能满足我们的需求的——平均的数据分布、对我们来说是透明的、多数时候性能也不是问题。但是在我们更深入地理解我们的数据的特征之后,使用自定义的Routing模式可能会给我们带来更好的性能。
自定义路由可能会导致索引分配不均,大量的索引路由到一个分片上,导致这个分片的索引和查询性能降低。为了解决这个问题,可以设置 routing_partition_size 参数。(注意这是一个索引级别的设置,只能在创建索引的时候设置。随着分区大小的增加,数据分布越均匀,代价是每个请求必须搜索更多分片)这样routing将路由到一组分片,然后_id字段在决定文档保存到那一个分片上。由于这个原因。routing_partition_size的值必须是一个大于1但是小于number_of_shards设置的分片数量的一个整数。具体公式如下:
shard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards
请求发到某个节点之后,该节点成为协调节点,计算好routing值之后转发到指定的节点(增删改需求发送到primary shard,查询需求主分片和副本分片都可以,对于查询需求发送到主分片还是副本分片是通过轮询查询中所有的分片),然后将数据返回到协调节点,协调节点将数据返回给客户端