Elasticsearch Filter 緩存加速檢索的細(xì)節(jié),你知道嗎?
1、前言
ES 進(jìn)行信息檢索的時(shí)候,boolean 查詢(xún)組合條件有 must/must_not/should/filter四個(gè)操作。
其中 must 和 filter 的用途都是用于過(guò)濾必要符合的條件,但是 filter 在查詢(xún)過(guò)程中不算分并且可以進(jìn)行緩存,這樣邏輯簡(jiǎn)單又可以加速的查詢(xún)方式經(jīng)常得到官方的提倡。
可是,只有 filter 的條件可以被緩存么?這里的緩存是屬于哪一部分?
緩存有什么樣的進(jìn)入和淘汰機(jī)制?怎么去監(jiān)控緩存的使用情況?
這些問(wèn)題也會(huì)伴隨著對(duì) Elasticsearch 的深入使用自然而然的產(chǎn)生。
本文中,我們結(jié)合官方的一些資料進(jìn)行探索。
2、什么是 Filter Context?
仔細(xì)去看官方的文檔可以發(fā)現(xiàn),在 filter 的使用介紹里是這么寫(xiě)的。
Filter clauses are executed in filter context, meaning that scoring is ignored and clauses are considered for caching.
這里不僅措辭嚴(yán)謹(jǐn)?shù)恼f(shuō) filter 條件以 filter context 的方式執(zhí)行,
并在如下官方鏈接做了詳盡解釋。
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html#filter-context
簡(jiǎn)而言之,filter context 主要用于查詢(xún)的過(guò)濾條件,并且不用算分,與 bool 的 filter 條件沒(méi)有嚴(yán)格關(guān)聯(lián),除了 bool 的 filter 外,bool 中的 must_not, constant_score 查詢(xún)中的 filter,聚合中的 filter 也都屬于。
filter context
3、如何進(jìn)入 Query Cache
現(xiàn)在我們來(lái)看看查詢(xún)是怎么進(jìn)入 Query Cache的:
3.1. 找到匹配文檔
在倒排索引中找到 filter 條件符合的詞項(xiàng),并在所有的文檔中檢索這個(gè)詞項(xiàng)。
3.2. 建立一個(gè)位圖 bitset
建立一個(gè)只包含1和0的位圖 bitset,這個(gè) bitset 用于描述所有文檔的匹配情況,匹配的文檔被設(shè)置為1。ES 實(shí)際執(zhí)行時(shí),使用的是 RoaringBitMap。
3.3. 迭代 bitset
一旦為某個(gè)查詢(xún)生成了 bitset, Elasticsearch 就會(huì)遍歷 bitset 以查找滿(mǎn)足所有過(guò)濾條件的匹配文檔集。
執(zhí)行順序通常是首先迭代最稀疏的bitset(因?yàn)樗懦俗疃鄶?shù)量的文檔)。
3.4. 增加使用計(jì)數(shù)
把查詢(xún)條件和其結(jié)果的 bitset 組合作為 key-value 進(jìn)行緩存,這里利用對(duì)查詢(xún)條件的使用記錄來(lái)判斷是否進(jìn)緩存。
簡(jiǎn)單來(lái)說(shuō),如果一個(gè)查詢(xún)?cè)谧罱?56個(gè)查詢(xún)中被多次使用,它將被緩存在內(nèi)存中。更為詳細(xì)的保留機(jī)制見(jiàn)下一節(jié)。
圖片
4、Query Cache 的緩存機(jī)制
總體來(lái)說(shuō),Query Cache 是 Lucene 層面實(shí)現(xiàn)的,ES 層面會(huì)進(jìn)行一些策略控制和信息統(tǒng)計(jì)。
Query Cache 僅應(yīng)用于相對(duì)較大的 segment。
對(duì)于文檔數(shù)少于 1 萬(wàn)或 segment 大?。╯ize,單位:MB、GB等)小于整體索引大小 3% 的 segment(如下公式),Query Cache 將不啟用。
docs_count(segment) < 10000 || segment.size < 3%*index.size
因?yàn)樾?segment 的查詢(xún)本身已經(jīng)足夠快,不需要緩存來(lái)加速。
其管理策略類(lèi)是 lucene 的 UsageTrackingQueryCachingPolicy,符合 LRU 的規(guī)則,也就是說(shuō) Query Cache 中的查詢(xún)結(jié)果長(zhǎng)時(shí)間不被訪問(wèn)會(huì)被優(yōu)先淘汰。
這里判斷是否被緩存的方法是shouldCache(Query query),有興趣的同學(xué)可以去研究下
判斷是否可以緩存的主要規(guī)則如下:
- 判斷是否為 filter 查詢(xún)assert query instanceof BoostQuery == false;
- 命中永不緩存 shouldNeverCache 條件的淘汰,其中包括:TermQuery、MatchAllDocsQuery、MatchNoDocsQuery、以及子查詢(xún)?yōu)榭盏腂ooleanQuery、DisjunctionMaxQuery
- 某些大于特定閾值的查詢(xún)可以被緩存:3.1 大于2次:MultiTermQuery、MultiTermQueryConstantScoreWrapper、TermInSetQuery、PointQuery(在 isCostly方法中定義)3.2 大于5次:除了上面列出條件的所有 filter 查詢(xún)
5、使用和觀測(cè) Query Cache
最后,我們來(lái)看下怎么去使用和觀測(cè) Query Cache。
默認(rèn)情況下節(jié)點(diǎn)的 Query cache最多緩存 10000個(gè)子查詢(xún)的結(jié)果,或者最多使用堆內(nèi)存的10%,都可以通過(guò)配置來(lái)調(diào)整:
indices.queries.cache.count #默認(rèn) 10000
indices.queries.cache.size #默認(rèn) 10%
對(duì) Query Cache 也可以進(jìn)行人工清理:POST /<index>/_cache/clear?query=true
而 Nodes stats API 和 Index stats API 都提供了 Query Cache 的監(jiān)控
"query_cache": {
"memory_size_in_bytes": 1110305640,//使用的size
"total_count": 45109997,//歷史查詢(xún)總條數(shù) total=hit+miss
"hit_count": 1192144,//命中的
"miss_count": 43917853,//未命中的
"cache_size": 1309,//當(dāng)前緩存的條數(shù)
"cache_count": 51509,//歷史緩存總條數(shù)
"evictions": 50200//被驅(qū)逐的條數(shù)
}
使用小建議:
- 當(dāng) evictions 大量發(fā)生時(shí),緩存被大量置換,對(duì)高敏感的業(yè)務(wù)可能會(huì)有一定的查詢(xún)抖動(dòng)。
- 在監(jiān)控項(xiàng)上添加一個(gè) hit/total 的百分比監(jiān)控,更加直觀。
6、小結(jié)
本文短暫總結(jié)了 Filter context 如何形成 Query Cache 并進(jìn)行維護(hù)觀測(cè)的整體流程。
重點(diǎn):Filter context 本身可以省去復(fù)雜的算分過(guò)程,再加上 Query Cache 的加速優(yōu)勢(shì),建議大家在編寫(xiě)只需要匹配過(guò)濾查詢(xún)語(yǔ)句中優(yōu)先選擇。
也就是:實(shí)際業(yè)務(wù)開(kāi)發(fā)能使用 filter 過(guò)濾的,記得一定加上!
作者介紹
金多安,Elastic 認(rèn)證專(zhuān)家,Elastic資深運(yùn)維工程師,死磕Elasticsearch知識(shí)星球嘉賓,星球Top活躍技術(shù)專(zhuān)家,搜索客社區(qū)日?qǐng)?bào)責(zé)任編輯。