ElasticSearch裡面的路由功能介紹

ElasticSearch Solr MySQL 技術 科技優家 2017-06-24

在ElaticSearch裡面,路由功能算是一個高級用法,大多數時候我們用的都是系統默認的路由功能,我們知道一個es索引可以分多個shard和每個shard又可以有多個replia,那麼現在思考一個問題,我們添加進去的數據,是如何分佈在各個shard上面的,而查詢時候它是又怎麼找到特定的數據呢。

默認情況下,索引數據的分片規則,是下面的公式:

shard_num = hash(_routing) % num_primary_shards

_routing字段的取值,默認是_id字段或者是_parent字段,這樣的取值在hash之後再與有多少個shard的數量取模,最終得到這條數據應該在被分配在那個一個shard上,也就是說默認是基於hash的分片,保證在每個shard上數據量都近似平均,這樣就不會出現負載不均衡的情況,然後在檢索的時候,es默認會搜索所有shard上的數據,最後在master節點上匯聚在處理後,返回最終數據。

但有時候,我們會有另外一種情況,比如說存儲一年的數據,如果按hash去索引,那就是分佈非常均勻,這樣的話無論查詢什麼數據都會去所有的shard上查詢,如果數據量比較大,那麼響應速度就比較慢,但這時,我們通過調查發現,一年12個月的數據本身分佈並不均勻,有幾個月的數據偏多,有幾個月的數據偏少,理想情況下,數據偏少的月,查詢性能應該更快,但如果是基於hash分片,那麼我們並不能實現這種需求,因為hash分片,查詢時候必須要命中所有shard之後,查詢的結果才是準的,這樣以來,每次查詢都要掃描所有shard,比如我已經知道數據本身就是1月份的,那其實最好的情況下,只查詢1月的數據就行,而不需要把一年的數據都掃描一遍,導致最終的結果就是慢的更慢,快的也慢,所以我們要針對性的做優化。

那麼如何優化,其實思路也比較明確了,那就是按照月份分區,每一個月的數據都存在指定的分區中,如果是mysql那就是每個月份一張表,然後查詢時候,直接查詢對應月份的數據即可,在es和solr中原理也大致如此,唯一不同的地方在於es和solr都比較方便的支持了路由字段的設置而如果是數據庫,則需要自己通過中間件的方式來搞定,比如說mycat等。

下面來介紹如何在es中使用路由字段,先看一個官網給的簡單的例子:

PUT my_index/my_type/1?routing=user1&refresh=true 
{
  "title": "This is a document"
}

GET my_index/my_type/1?routing=user1

上面的代碼中,指定了一個用戶屬性作為路由進行分區,然後查詢的時候也必須指定路由。這一點需要注意

只要在索引時候加入路由字段,那麼在以後的get,delete,update操作中都必須使用路由字段,否則會出現問題。

當然,路由字段本身,也是可以被查詢的,看下面的代碼:

GET my_index/_search
{
  "query": {
    "terms": {
      "_routing": [ "user1" ] 
    }
  }
}


除此之外,路由字段,也可以指定多個:

GET my_index/_search?routing=user1,user2 
{
  "query": {
    "match": {
      "title": "document"
    }
  }
}

如果指定多個用戶屬性,那麼es會僅僅查詢關聯了這兩個route屬性的shard

如果加入路由字段之後,其他的操作(indexing,getting,deleting,updating)都必須指定路由字段,為了避免在使用時忘記添加路由字段,導致同類數據會分佈在多個shard上,這就違反了路由的原則,所以我們可以在mapping中

設置路由字段是必須字段,否則會提示錯誤:

PUT my_index2
{
  "mappings": {
    "my_type": {
      "_routing": {
        "required": true 
      }
    }
  }
}

PUT my_index2/my_type/1 
{
  "text": "No routing value provided"
}

缺失路由字段會拋出異常:

routing_missing_exception

還需要注意到是如果使用了路由字段,那麼_id字段只能由用戶保證唯一性,因為同一個id的數據,如果路由字段不一樣,它是可以被存在到多個shard中的,而默認情況下是不會出現這種情況的。

最後接著說開頭的例子,如果某個月數據量偏大,全部路由到一個shard裡面依然性能有問題,es也提供了同一個路由的字段的數據可以被分配到多個shard上,注意這是是多個shard,而不是所有shard,當然這裡面有一定限制一般情況下,不建議使用這種模式。

對solr中路由感興趣的朋友,可以查看我以前寫的文章:

相關推薦

推薦中...