日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

从根上理解elasticsearch(lucene)查询原理(2)-lucene常见查询类型原理分析

發布時間:2023/12/24 windows 36 coder
生活随笔 收集整理的這篇文章主要介紹了 从根上理解elasticsearch(lucene)查询原理(2)-lucene常见查询类型原理分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大家好,我是藍胖子,在上一節我提到要想徹底搞懂elasticsearch 慢查詢的原因,必須搞懂lucene的查詢原理,所以在上一節我分析了lucene查詢的整體流程,除此以外,還必須要搞懂各種查詢類型內部是如何工作,比如比較復雜的查詢是將一個大查詢分解成了小查詢,然后通過對小查詢的結果進行合并得到最終結果。

今天就來看看幾種比較常見的查詢其內部的工作原理。

BooleanQuery 查詢分析

首先來看下布爾查詢,拿下面這段代碼舉例,我用lucene寫了一個布爾查詢的例子,布爾查詢由兩個term查詢組成,其中一個term是用must,一個term用的是should。

BooleanQuery.Builder query = new BooleanQuery.Builder();  
query.add(new TermQuery(new Term(field1, "w3")), BooleanClause.Occur.MUST);  
query.add(new TermQuery(new Term(field2, "xx")), BooleanClause.Occur.SHOULD);  
int[] expDocNrs = {2, 3, 1, 0};  
queriesTest(query.build(), expDocNrs);

布爾查詢會將兩個term查詢的倒排鏈進行合并,得到最終結果。上一節有提到,計分邏輯是通過bulkScore.score方法實現的。在bulkScore.score方法內部 ,需要先遍歷篩選出符合條件的文檔,然后對該文檔進行計分,無論是篩選出符合條件的文檔,還是對文檔計分,都與weight對象創建的scorer對象有關,遍歷用到的是DocIdSetIterator,計分用到的是score() 方法,scorer涉及到的方法如下,

其中計分方法score是在scorer抽象類又繼承的一個Scorable 抽象類中,如下所示

public abstract class Scorer extends Scorable {
	...
}

在遍歷倒排列表取出文檔id時,會調用DocIdSetIterator 的nextDoc 方法取出當前文檔id,并將便利指針移動到倒排列表的下一個文檔id處。

但是布爾查詢往往是多個條件的組合查詢,它不可能是只遍歷一個倒排鏈表,所以布爾查詢的實現中,針對查詢條件生成了特殊的scorer對象,比如ConjunctionScorer 交集scorer,它會將查詢條件組合起來,并且利用子查詢的DocIdSetIterator 構造新的DocIdSetIterator 用于遍歷篩選出符合條件的文檔id。ConjunctionScorer 的nextDoc方法就相當于是在執行多個倒排鏈表合并的過程。

關于倒排鏈表的合并過程就不在這篇文檔繼續展開了。除此以外,布爾查詢構建的scorer對象還有 并集DisjunctionSumScorer,差集ReqExclScorer,ReqOptSumScorer。它們的nextDoc方法也都是在做遍歷倒排鏈表取出文檔id的操作,不過遍歷合并倒排鏈表的邏輯各有不同。

所以,如果你的布爾查詢命中結果比較多,并且需要計分的話, 會導致在進行倒排鏈表合并操作時花費比較長的時間。比如我之前碰到的一個慢查詢,經過profile的分析如下,布爾查詢在next_doc操作上耗時比較長,next_doc對于布爾查詢而言是在進行倒排鏈表的合并。

而對于布爾查詢的子查詢term查詢你會發現耗時基本是花在了advance操作上。因為倒排列表合并過程中會有很多移動遍歷指針的操作也就是advance操作,所以在倒排列表比較長時,要想完整遍歷合并多個倒排列表則會有很多advance操作。

MultiTermQuery 查詢分析

接著看另外一個常見的查詢類型MultiTermQuery,它的查詢重寫分好幾種類型,具體的重寫類型區別可以查看官方文 https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-term-rewrite.html

這里我拿其中一種 CONSTANT_SCORE_BLENDED_REWRITE 舉例,這也是在復雜查詢例如

  • fuzzy
  • prefix
  • query_string
  • regexp
  • wildcard

默認使用的重寫類型。

wildcardQuery這些模糊匹配,正則匹配差詢首先是構建自動狀態機,然后默認會將查詢重寫成為了CONSTANT_SCORE_BLENDED_REWRITE類型的MultiTermQuery查詢。

之后在創建weight的scorer對象時,會將詞典term dictionary中的term與自動狀態機做匹配,選出符合條件的term,根據term的個數判斷是將查詢重寫為布爾查詢還是直接構建bitset用于后續計分時進行迭代遍歷。

符合條件的term 大于16個,則會進行bitset的構建,構建過程則是將符合條件的term對應的倒排列表取出來加到一個bitset中。這個過程是比較耗時的,特別是term對應的倒排列表過大或者term數量過多時,耗時會非常長。注意這個構建過程是發生在scoer對象創建的時候,即build_scorer階段。拿我之前遇到的一個慢查詢舉例,這是一個匹配到的term數量比較多的wildcardQuery,

下面是執行的DSL語句,

{"size":1000,"query":{"bool":{"filter":[{"term":{"owner_uid":{"value":712377485,"boost":1.0}}},{"term":{"pid":{"value":0,"boost":1.0}}},{"wildcard":{"name":{"wildcard":"*","boost":1.0}}},{"exists":{"field":"vgroup","boost":1.0}}],"adjust_pure_negative":true,"boost":1.0}},"_source":{"includes":["name"],"excludes":[]}}

經過profile分析可以看到wildcardQuery已經被重寫為了MultiTermQueryConstantScoreWrapper,耗時過長最大的階段則是在build_scorer階段,對每個階段不太熟悉的話可以翻看我前一篇文章 https://mp.weixin.qq.com/s/Drhs6lKPYy8vDHa2RouiyA

注意像wildcardQuery,前綴匹配這些查詢都會構建自動狀態機,構建自動狀態機的過程在匹配規則文本比較長時,非常消耗cpu,生產上注意限制匹配規則文本長度,并且構建自動狀態機花費的時長不會體現在profile輸出結果中。

總結

以上是生活随笔為你收集整理的从根上理解elasticsearch(lucene)查询原理(2)-lucene常见查询类型原理分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。