Elasticsearch中keyword和numeric對性能的影響分析


Elasticsearch中keyword和numeric對性能的影響分析java

初學者認爲這兩個關鍵字的沒啥關係,一個是用於字符串的精確匹配查詢,一個是數字類型的字段用在計數的場景,好比說博客的點贊數,訂單金額等。mysql

可是有些場景彷佛兩個關鍵字均可以用,好比電商場景下的訂單狀態,通常咱們也是用數字表示不一樣的狀態,好比1表示待支付,2表示支付成功。第一反應是用Byte(屬於numeric),沒有問題。可是用keyword是否能夠呢?sql

numeric除了支持等值精確查詢,還能夠範圍查詢。可是大部分狀況下咱們業務場景對於訂單狀態的使用都是精確查詢的,不會有大於某個狀態或者小於某個狀態這樣的狀況。微信




因此剛纔說的訂單狀態的場景,用keyword和numeric確定均可以知足。可是那種方案好呢?答案是keyword。數據結構




對於keyword類型的term query,ES使用的是倒排索引。可是numeric類型爲了能有效的支持範圍查詢,它的存儲結構並非倒排索引。app

咱們知道倒排索引在內存裏維護了詞典 (Term Dictionary)和文檔列表(Postings List)的映射關係,倒排索引自己對於精確匹配查詢是很是快的,直接從字典表找到term,而後就直接找到了posting list。post

numeric類型從lucene6.0開始,使用了一種名爲block KD tree的存儲結構。性能

Block KD tree介紹

kd-tree(k-dimensional樹的簡稱),是一種對k維空間中的實例點進行存儲以便對其進行快速檢索的樹形數據結構。這種存儲結構相似於mysql裏的B+數,咱們知道B+數這種數據結構對於範圍查找的支持是很是好的。不一樣於mysql, Block KD tree的葉子節點存儲的是一組值的集合(block),大概是512~1024個值一組。這也是爲何叫block kd tree。flex

Block KD tree對於範圍查詢,鄰近搜索支持的很是好,尤爲是多維空間的狀況下。spa

看上圖,每一個節點有三個元素,因此這裏K=3,不一樣於簡單二叉樹每一個節點都是一個元素(以下面這個圖)。這樣就能夠方便的在一個三維的空間進行範圍的比較。

 

標準的二叉樹

對於上圖中的kd-tree,搜索的過程是這樣的:首先和根節點比較第一項,小於往左,大於往右,第二層比較第二項,依次類推。每層參與比較的數據是不同的。

具體的ES內部(實際上是Lucene),目前的版本是基於所謂的PointValues,好比整型在Lucene內部是IntPoint類表示,還有DoublePoint等,完整的對應關係是:

Java type Lucene classint IntPointlong LongPointfloat FloatPointdouble DoublePointbyte[] BinaryPoint

而這些PointValues是基於kd-tree存儲的,根據官方文檔的介紹,lucene把葉子節點在磁盤是順序存儲的,這樣搜索的效率就會很是高。

爲啥numeric對於term精確匹配的查詢性能沒有keyword好

前面咱們提到了IntPoint類,這個類有三個查詢方法:

//構造精確查詢,內部仍是調用newRangeQueryQuery newExactQuery(String field, int value)
//構造一維查詢,內部是調用多維查詢的方法Query newRangeQuery(String field, int lowerValue, int upperValue)
//構造多維查詢Query newRangeQuery(String field, int[] lowerValue, int[] upperValue)

IntPoint.java 

好比咱們有這樣一個索引:

PUT blogs { "mappings": { "properties": {  "title": { "type": "keyword" },  "content": { "type": "text" },  "status": { "type": "integer" } } }}

若是咱們基於status查詢,

{ "query": { "term": { "title": { "status": 2 } } }}

在lucene內部其實仍是進行了一個2~2的範圍查詢。即使kd-tree的性能也很高,可是對於這種精確查詢仍是要到樹上走一遭,而倒排索引至關因而直接在內存裏就定位到告終果集的文檔id。若是是bool組合查詢的話,term還能夠利用跳錶,這點numeric字段也是作不到的。

多維查詢的newRangeQuery裏面是調用了PointRangeQuery類的查詢方法。

引用:

https://www.elastic.co/cn/blog/searching-numb3rs-in-5.0

本文分享自微信公衆號 - 犀牛飼養員的技術筆記(coder_start_up)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索