1. 程式人生 > >elasticsearch(9) filter 和terms

elasticsearch(9) filter 和terms

現在es 5.2版本,type=text,預設會設定兩個field,一個是field本身,比如articleID,就是分詞的;還有一個的話,就是field.keyword,articleID.keyword,預設不分詞,會最多保留256個字元

(1)根據使用者ID搜尋帖子

GET /forum/article/_search {     "query" : {         "constant_score" : {              "filter" : {                 "term" : {                      "userID" : 1                 }             }         }     } }

term filter/query:對搜尋文字不分詞,直接拿去倒排索引中匹配,你輸入的是什麼,就去匹配什麼 比如說,如果對搜尋文字進行分詞的話,“helle world” --> “hello”和“world”,兩個詞分別去倒排索引中匹配 term,“hello world” --> “hello world”,直接去倒排索引中匹配“hello world”

(2)搜尋沒有隱藏的帖子

GET /forum/article/_search {     "query" : {         "constant_score" : {              "filter" : {                 "term" : {                      "hidden" : false                 }             }         }     } }

(3)根據發帖日期搜尋帖子

GET /forum/article/_search {     "query" : {         "constant_score" : {              "filter" : {                 "term" : {                      "postDate" : "2017-01-01"                 }             }         }     } }

4)根據帖子ID搜尋帖子

GET /forum/article/_search {     "query" : {         "constant_score" : {              "filter" : {                 "term" : {                      "articleID" : "XHDK-A-1293-#fJ3"                 }             }         }     } }

{   "took": 1,   "timed_out": false,   "_shards": {     "total": 5,     "successful": 5,     "failed": 0   },   "hits": {     "total": 0,     "max_score": null,     "hits": []   } }

GET /forum/article/_search {     "query" : {         "constant_score" : {              "filter" : {                 "term" : {                      "articleID.keyword" : "XHDK-A-1293-#fJ3"                 }             }         }     } }

{   "took": 2,   "timed_out": false,   "_shards": {     "total": 5,     "successful": 5,     "failed": 0   },   "hits": {     "total": 1,     "max_score": 1,     "hits": [       {         "_index": "forum",         "_type": "article",         "_id": "1",         "_score": 1,         "_source": {           "articleID": "XHDK-A-1293-#fJ3",           "userID": 1,           "hidden": false,           "postDate": "2017-01-01"         }       }     ]   } }

articleID.keyword,是es最新版本內建建立的field,就是不分詞的。所以一個articleID過來的時候,會建立兩次索引,一次是自己本身,是要分詞的,分詞後放入倒排索引;另外一次是基於articleID.keyword,不分詞,保留256個字元最多,直接一個字串放入倒排索引中。

所以term filter,對text過濾,可以考慮使用內建的field.keyword來進行匹配。但是有個問題,預設就保留256個字元。所以儘可能還是自己去手動建立索引,指定not_analyzed吧。在最新版本的es中,不需要指定not_analyzed也可以,將type=keyword即可。

(5)檢視分詞

GET /forum/_analyze {   "field": "articleID",   "text": "XHDK-A-1293-#fJ3" }

預設是analyzed的text型別的field,建立倒排索引的時候,就會對所有的articleID分詞,分詞以後,原本的articleID就沒有了,只有分詞後的各個word存在於倒排索引中。 term,是不對搜尋文字分詞的,XHDK-A-1293-#fJ3 --> XHDK-A-1293-#fJ3;但是articleID建立索引的時候,XHDK-A-1293-#fJ3 --> xhdk,a,1293,fj3

2.filter的原理

(1)在倒排索引中查詢搜尋串,獲取document list

date來舉例

word        doc1        doc2        doc3

2017-01-01    *        * 2017-02-02            *        * 2017-03-03    *        *        *

filter:2017-02-02

到倒排索引中一找,發現2017-02-02對應的document list是doc2,doc3

(2)為每個在倒排索引中搜索到的結果,構建一個bitset,[0, 0, 0, 1, 0, 1]

非常重要

使用找到的doc list,構建一個bitset,就是一個二進位制的陣列,陣列每個元素都是0或1,用來標識一個doc對一個filter條件是否匹配,如果匹配就是1,不匹配就是0

[0, 1, 1]

doc1:不匹配這個filter的 doc2和do3:是匹配這個filter的

儘可能用簡單的資料結構去實現複雜的功能,可以節省記憶體空間,提升效能

(3)遍歷每個過濾條件對應的bitset,優先從最稀疏的開始搜尋,查詢滿足所有條件的document

後面會講解,一次性其實可以在一個search請求中,發出多個filter條件,每個filter條件都會對應一個bitset 遍歷每個filter條件對應的bitset,先從最稀疏的開始遍歷

[0, 0, 0, 1, 0, 0]:比較稀疏 [0, 1, 0, 1, 0, 1]

先遍歷比較稀疏的bitset,就可以先過濾掉儘可能多的資料

遍歷所有的bitset,找到匹配所有filter條件的doc

請求:filter,postDate=2017-01-01,userID=1

postDate: [0, 0, 1, 1, 0, 0] userID:   [0, 1, 0, 1, 0, 1]

遍歷完兩個bitset之後,找到的匹配所有條件的doc,就是doc4

就可以將document作為結果返回給client了

(4)caching bitset,跟蹤query,在最近256個query中超過一定次數的過濾條件,快取其bitset。對於小segment(<1000,或<3%),不快取bitset。

比如postDate=2017-01-01,[0, 0, 1, 1, 0, 0],可以快取在記憶體中,這樣下次如果再有這個條件過來的時候,就不用重新掃描倒排索引,反覆生成bitset,可以大幅度提升效能。

在最近的256個filter中,有某個filter超過了一定的次數,次數不固定,就會自動快取這個filter對應的bitset

segment(上半季),filter針對小segment獲取到的結果,可以不快取,segment記錄數<1000,或者segment大小<index總大小的3%

segment資料量很小,此時哪怕是掃描也很快;segment會在後臺自動合併,小segment很快就會跟其他小segment合併成大segment,此時就快取也沒有什麼意義,segment很快就消失了

針對一個小segment的bitset,[0, 0, 1, 0]

filter比query的好處就在於會caching,但是之前不知道caching的是什麼東西,實際上並不是一個filter返回的完整的doc list資料結果。而是filter bitset快取起來。下次不用掃描倒排索引了。

(5)filter大部分情況下來說,在query之前執行,先儘量過濾掉儘可能多的資料

query:是會計算doc對搜尋條件的relevance score,還會根據這個score去排序 filter:只是簡單過濾出想要的資料,不計算relevance score,也不排序

(6)如果document有新增或修改,那麼cached bitset會被自動更新

postDate=2017-01-01,[0, 0, 1, 0] document,id=5,postDate=2017-01-01,會自動更新到postDate=2017-01-01這個filter的bitset中,全自動,快取會自動更新。postDate=2017-01-01的bitset,[0, 0, 1, 0, 1] document,id=1,postDate=2016-12-30,修改為postDate-2017-01-01,此時也會自動更新bitset,[1, 0, 1, 0, 1]

(7)以後只要是有相同的filter條件的,會直接來使用這個過濾條件對應的cached bitset