java的調用接口翻譯為:client.prepareSearch(“index”).setPreference(“_primary”)。
默認情況下es有5種查詢優先級:
_primary: 指查詢只在主分片中查詢
_primary_first: 指查詢會先在主分片中查詢,如果主分片找不到(掛了),就會在副本中查詢。
_local: 指查詢操作會優先在本地節點有的分片中查詢,沒有的話再在其它節點查詢。
_only_node:指在指定id的節點里面進行查詢,如果該節點只有要查詢索引的部分分片,就只在這部分分片中查找,所以查詢結果可能不完整。如_only_node:123在節點id為123的節點中查詢。
Custom (string) value:用戶自定義值,指在參數cluster.routing.allocation.awareness.attributes指定的值,如這個值設置為了zone,那么preference=zone的話就在awareness.attributes=zone*這樣的節點搜索,如zone1、zone2。關於這個值作用可以參考下面文章。
雖然es有提供這5種優先級,但感覺還是不能滿足我的需求,我是想能指定在某一個或多個節點中查詢,比如node1和node2里面的分片能組成一個完整的索引,那我可以只在node1和node2中搜索就行了。看來只能改源碼解決,改源碼也非常簡單。
首先找到org.elasticsearch.cluster.routing.operation.plain.PlainOperationRouting這個類,es搜索時獲取分片信息是通過這個類的。它的preferenceActiveShardIterator()方法就是根據條件來找出響應的分片。看源碼可知其主要是根據preference這個參數來決定取出的分片的。如果沒有指定該參數,就隨機抽取分片進行搜索。如果參數以_shards開頭,則表示只查詢指定的分片。注意,這個功能官網的文檔中沒有寫到。
然后下面就是判斷我上面說的5種優先級情況。我們現在要加個多節點分片查詢的功能,仿照單個節點分片查詢(指_only_node)就行了,在
- if (preference.startsWith("_only_node:")) {
- return indexShard.onlyNodeActiveShardsIt(preference.substring("_only_node:".length()));
- }
后面加上
- if (preference.startsWith("_only_nodes:")) {
- return indexShard.onlyNodesActiveShardsIt(preference.substring("_only_nodes:".length()));
- }
onlyNodesActiveShardsIt這個方法在org.elasticsearch.cluster.routing.IndexShardRoutingTable中是沒有的,要自己寫。加上
- /**
- * Prefers execution on the provided nodes if applicable.
- */
- public ShardIterator onlyNodesActiveShardsIt(String nodeIds) {
- String[] ids = nodeIds.split(",");
- ArrayList<ShardRouting> ordered = new ArrayList<ShardRouting>(shards.size());
- // fill it in a randomized fashion
- for (int i = 0; i < shards.size(); i++) {
- ShardRouting shardRouting = shards.get(i);
- for(String nodeId:ids){
- if (nodeId.equals(shardRouting.currentNodeId())) {
- ordered.add(shardRouting);
- }
- }
- }
- return new PlainShardIterator(shardId, ordered);
- }
重新編譯源碼就行了。查詢時加上preference=_only_nodes:node1id,node2id 就可以指定在node1和node2中搜索