Elasticsearch的路由机制与其分片机制有着直接的关系。Elasticsearch的路由机制便是经过哈希算法,将具备相同哈希值的文档放置到同一个主分片中。这个和经过哈希算法来进行负载均衡几乎是同样的。oop
而Elasticsearch也有一个默认的路由算法:它会将文档的ID值做为依据将其哈希到相应的主分片上,这种算法基本上会保持全部数据在全部分片上的一个平均分布,而不会产生数据热点。post
而咱们为何会须要自定义的Routing模式呢?首先默认的Routing模式在不少状况下都是能知足咱们的需求的——平均的数据分布、对咱们来讲是透明的、多数时候性能也不是问题。可是在咱们更深刻地理解咱们的数据的特征以后,使用自定义的Routing模式可能会给咱们带来更好的性能。性能
假设你有一个100个分片的索引。当一个请求在集群上执行时会发生什么呢?ui
1. 这个搜索的请求会被发送到一个节点url
2. 接收到这个请求的节点,将这个查询广播到这个索引的每一个分片上(多是主分片,也多是复制分片)
3. 每一个分片执行这个搜索查询并返回结果
4. 结果在通道节点上合并、排序并返回给用户
由于默认状况下,Elasticsearch使用文档的ID(相似于关系数据库中的自增ID,固然,若是不指定ID的话,Elasticsearch使用的是随机值)将文档平均的分布于全部的分片上,这致使了Elasticsearch不能肯定文档的位置,因此它必须将这个请求广播到全部的100个分片上去执行。这同时也解释了为何主分片的数量在索引建立的时候是固定下来的,而且永远不能改变。由于若是分片的数量改变了,全部先前的路由值就会变成非法了,文档至关于丢失了。
而自定义的Routing模式,可使咱们的查询更具目的性。咱们没必要盲目地去广播查询请求,取而代之的是:咱们要告诉Elasticsearch咱们的数据在哪一个分片上。
原来的查询语句:“请告诉我,USER1的文档数量一共有多少”
使用自定义Routing(在USESR ID上)后的查询语句:“请告诉我,USER1的文档数量一共有多少,它就在第三个分片上,其它的分片就不要去扫描了”
全部的文档API(get,index,delete,update和mget)都能接收一个routing参数,能够用来造成个性化文档分片映射。一个个性化的routing值能够确保相关的文档存储到一样的分片上——好比,全部属于同一个用户的文档。
第一种方法,也是比较直观的方法就是直接在请求的URL中指定routing参数:
[plain] view plaincopy
<EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
curl -XPOST 'http://localhost:9200/store/order?routing=user123' -d '
{
"productName": "sample",
"customerID": "user123"
}'
这样咱们就按照用户的customerID的值将具备相同customerID的文档置于同一分片上了。
第二种方法就是直接从文档中提取到对应的路由值:
[plain] view plaincopy
<EMBED id=ZeroClipboardMovie_2 height=18 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
curl -XPUT 'http://localhost:9200/store/order/_mapping' -d '
{
"order": {
"_routing": {
"required": true,
"path": "customerID"
}
}
}'
这样的方法和第一种方法在效果上同样的,可是有一点须要注意,相比于第一种方法这种方法的效率稍低,由于第一种方法直接就在请求的参数中肯定了路由的值,而第二种方法中,首先须要将文档读入以后,再从中提取到对应的路由值。
利用路由机制的查询也是很是简单明了的,只须要在查询中指定对应的路由值便可:
[plain] view plaincopy
<EMBED id=ZeroClipboardMovie_3 height=18 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
curl -XGET 'http://localhost:9200/store/order/_search?routing=user123' -d '
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"term": {
"userID": "user123"
}
}
}
}
}'
经过指定的路由值,咱们就能够直接定位到user123的文档所在的分片,而不用一股脑的向索引的全部节点都发送请求。这样的话,会大大减小系统资源的浪费。
固然,也能够同时指定多个路由值,方法也是显而易见的,只须要在查询参数中指定多个路由值便可:
[plain] view plaincopy
<EMBED id=ZeroClipboardMovie_4 height=18 name=ZeroClipboardMovie_4 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=4&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
curl -XGET 'http://localhost:9200/forum/posts/?routing=Admin,Moderator' -d '{}'
实际上,若是不明确指明使用路由机制,实际上路由机制也是在发挥做用的,只是默认的路由值是文档的id而已。而个性化路由的需求主要是和业务相关的。默认的路由(若是是自动的生成的id)直观上会把全部的文档随机分配到一个分片上,而个性化的路由值就是和业务相关的了。这也会形成一些潜在的问题,好比user123自己的文档就很是多,有数十万个,而其余大多数的用户只有几个文档,这样的话就会致使user123所在的分片较大,出现数据偏移的状况,特别是多个这样的用户处于同一分片的时候,现象会更明显。具体的使用仍是要结合实际的应用场景来选择的。