ElasticSearch 查詢(xún)的性能與評(píng)分問(wèn)題

Elasticsearch是一個(gè)基于Lucene的搜索服務(wù)器。它提供了一個(gè)分布式多用戶(hù)能力的全文搜索引擎,它天生支持分布式搜索機(jī)制,具有搜索、分析、挖掘海量數(shù)據(jù)的能力,同時(shí)還是一個(gè)可擴(kuò)展、近實(shí)時(shí)的搜索引擎。

本文主要分析ElasticSearch分布式搜索的機(jī)制,比較不同的搜索類(lèi)型,并針對(duì)ElasticSearch在搜索過(guò)程中存在的一些問(wèn)題進(jìn)行分析,同時(shí)給出優(yōu)化方案。
ES分布式搜索過(guò)程中,需要將請(qǐng)求分發(fā)到所有相關(guān)的分片,并將各分片的結(jié)果聚合到一起。故搜索過(guò)程分為兩個(gè)階段:Query和Fetch。假設(shè)集群設(shè)置為2個(gè)主分片、1個(gè)副本分片,即每個(gè)索引會(huì)有4個(gè)主副本分片。如圖所示:

Query階段:
1.用戶(hù)搜索請(qǐng)求到ES集群的某一個(gè)節(jié)點(diǎn)上,該節(jié)點(diǎn)收到用戶(hù)請(qǐng)求后,以協(xié)調(diào)節(jié)點(diǎn)的身份,在4個(gè)分片中隨機(jī)選擇2個(gè)分片(構(gòu)成完整的數(shù)據(jù)集),將請(qǐng)求分發(fā)到對(duì)應(yīng)分片所在的數(shù)據(jù)節(jié)點(diǎn)上。
2.各節(jié)點(diǎn)收到請(qǐng)求后,搜索相關(guān)分片上的文檔,根據(jù)本分片上詞頻及文檔頻率進(jìn)行相關(guān)性評(píng)分計(jì)算,同時(shí)根據(jù)分值進(jìn)行排序,返回from+size個(gè)排序后結(jié)果給協(xié)調(diào)節(jié)點(diǎn),這個(gè)結(jié)果并不包含全部的文檔信息,僅提供足夠協(xié)調(diào)節(jié)點(diǎn)對(duì)所有結(jié)果進(jìn)行合并重排序的信息。
Fetch 階段:
協(xié)調(diào)節(jié)點(diǎn)會(huì)將Query階段從每個(gè)分片上獲取到的排序后的結(jié)果重新進(jìn)行排序及合并,按照集群配置,協(xié)調(diào)節(jié)點(diǎn)總共會(huì)收到2*(from+size)個(gè)結(jié)果,根據(jù)重新排序的結(jié)果選取from+size個(gè)結(jié)果,同時(shí)根據(jù)結(jié)果中的文檔ID,去對(duì)應(yīng)的分片根據(jù)文檔ID獲取詳細(xì)文檔數(shù)據(jù),返回給客戶(hù)端。
ES的這種查詢(xún)方式存在兩個(gè)問(wèn)題:
1.性能問(wèn)題
在查詢(xún)過(guò)程中,每個(gè)分片需要返回的文檔個(gè)數(shù)為:from+size個(gè),協(xié)調(diào)節(jié)點(diǎn)需要匯總處理number_of_shards*(from+size)個(gè)文檔,ES為了避免深度分頁(yè)消耗節(jié)點(diǎn)過(guò)多內(nèi)存,默認(rèn)限定只能查詢(xún)10000個(gè)文檔,from+size的數(shù)量越大(出現(xiàn)深度分頁(yè)情況),協(xié)調(diào)節(jié)點(diǎn)處理的數(shù)據(jù)越多,占用協(xié)調(diào)節(jié)點(diǎn)的內(nèi)存越大,給協(xié)調(diào)節(jié)點(diǎn)帶來(lái)較大壓力。
2.評(píng)分問(wèn)題
在查詢(xún)過(guò)程中,為文檔相關(guān)性評(píng)分計(jì)算都是基于本分片上的詞頻和文檔頻率進(jìn)行的,而協(xié)調(diào)節(jié)點(diǎn)排序是基于各分片評(píng)分的結(jié)果進(jìn)行綜合排序的,各分片的評(píng)分依據(jù)不一致,會(huì)導(dǎo)致相關(guān)性評(píng)分偏離的問(wèn)題;在主分片數(shù)量大于1的情況下,如果主分片數(shù)里越多,相關(guān)性算法會(huì)越不準(zhǔn)。
針對(duì)以上的兩個(gè)問(wèn)題,ES提供了一些解決方案:
針對(duì)性能問(wèn)題(深度分頁(yè)問(wèn)題),ES有兩種用于查詢(xún)深度分頁(yè)情況下的查詢(xún)方法:Search After,使用search after進(jìn)行查詢(xún)時(shí),每次查詢(xún)時(shí)會(huì)返回當(dāng)前頁(yè)的sort值,可以根據(jù)sort值查詢(xún)下一頁(yè)的數(shù)據(jù)。使用Search after時(shí)多個(gè)分頁(yè)請(qǐng)求需要有相同的查詢(xún)和排序參數(shù)。如果多次分頁(yè)請(qǐng)求之間,ES進(jìn)行了refresh操作(即index-buffer中的數(shù)據(jù)寫(xiě)入到segment,這時(shí)index-buffer中的數(shù)據(jù)將能被查詢(xún)到),這樣會(huì)導(dǎo)致排序結(jié)果的改變,使得跨頁(yè)的排序結(jié)果不一致。為了避免發(fā)生這種情況,可以通過(guò)創(chuàng)建PIT的方式,在多次分頁(yè)請(qǐng)求中保持當(dāng)前索引的狀態(tài),獲取PIT時(shí)可以指定keep_alive參數(shù),指定PIT存在的時(shí)間。
例:POST /my-index-000001/_pit?keep_alive=1m 該API返回一個(gè)PIT ID:


第一次查詢(xún)時(shí),帶上PIT ID,同時(shí)在sort參數(shù)中,需要指定一個(gè)唯一的排序字段,這個(gè)字段的取值是唯一的(例如doc IDs),如果排序參數(shù)中沒(méi)有這個(gè)字段,則有可能會(huì)丟失結(jié)果或者出現(xiàn)重復(fù)結(jié)果。
查詢(xún)返回結(jié)果:
返回結(jié)果中,會(huì)有sort值,在查詢(xún)下一頁(yè)時(shí),帶上前一頁(yè)查詢(xún)返回的sort值,即可實(shí)現(xiàn)向下翻頁(yè)。如果使用了PIT需要一并放在查詢(xún)參數(shù)中。

通過(guò)重復(fù)這個(gè)查詢(xún)操作即可實(shí)現(xiàn)滾動(dòng)翻頁(yè)的功能。查詢(xún)完畢后應(yīng)該通過(guò)DELETE /_pit接口將PIT刪除。
Search After存在的局限性:不支持指定頁(yè)數(shù),即不能設(shè)定from參數(shù),只能從第一頁(yè)開(kāi)始往后進(jìn)行;只支持向后翻頁(yè),不能跨頁(yè)訪(fǎng)問(wèn),只能從當(dāng)前頁(yè)一頁(yè)一頁(yè)往后翻。Scroll API(當(dāng)前版本7.11已不再推薦使用Scroll進(jìn)行深度分頁(yè),在這里還是介紹一下這種查詢(xún)方式)
Scroll查詢(xún)方式的原理相當(dāng)于對(duì)當(dāng)前查詢(xún)創(chuàng)建一個(gè)快照,后面的每次查詢(xún),都基于第一次查詢(xún)創(chuàng)建的快照進(jìn)行。在第一次查詢(xún)時(shí),需要在請(qǐng)求中指定scroll參數(shù),并設(shè)置快照保存的時(shí)間。如scroll=1m即該查詢(xún)的快照將被保持一分鐘。

查詢(xún)將會(huì)返回_scroll_id,_scroll_id一般不會(huì)發(fā)生變化,但是以防萬(wàn)一,下一個(gè)查詢(xún)的請(qǐng)求最好還是使用上一個(gè)查詢(xún)請(qǐng)求返回的_scroll_id。當(dāng)查詢(xún)只需要返回全量文檔,不考慮文檔排序值時(shí),可將sort值指定為_(kāi)doc,這樣可以?xún)?yōu)化查詢(xún)的速度??梢酝ㄟ^(guò) POST /_search/scroll 接口更新scroll保存的時(shí)間。
因?yàn)閟croll是對(duì)當(dāng)前查詢(xún)創(chuàng)建一個(gè)副本快照,會(huì)占用較大的內(nèi)存,所以當(dāng)scroll使用完畢后,需要及時(shí)對(duì)scroll進(jìn)行清理??梢允褂肈ELETE /_search/scroll {scroll_id:””}的方式進(jìn)行。es對(duì)scroll的最大數(shù)量進(jìn)行了限制,默認(rèn)可以創(chuàng)建500個(gè)scroll,可以通過(guò)search.max_open_scroll_context參數(shù)進(jìn)行設(shè)置。
scroll存在的局限性:因?yàn)槭菍?duì)查詢(xún)結(jié)果創(chuàng)建快照進(jìn)行查詢(xún),所以當(dāng)查詢(xún)期間,如果有新數(shù)據(jù)寫(xiě)入,這些新增的數(shù)據(jù)將無(wú)法被查詢(xún)到。
根據(jù)以上對(duì)不同查詢(xún)類(lèi)型的分析,可以得出不同搜索類(lèi)型的適用場(chǎng)景:
普通from+size查詢(xún)方式:適用于只需要獲取排序靠前的部分文檔。
Search after查詢(xún)方式:適用于深度分頁(yè)情況。
Scroll查詢(xún)方式:適用于單個(gè)請(qǐng)求需要獲取大量文檔的情況。
評(píng)分問(wèn)題
1.當(dāng)數(shù)據(jù)量不大時(shí),將主分片的數(shù)量設(shè)置為1,當(dāng)數(shù)據(jù)量很大時(shí),保證文檔均勻分布在各個(gè)分片上。
2.使用DFS Query Then Fetch,這樣在搜索的時(shí)候各個(gè)分片會(huì)收集詞頻和文檔頻率,然后根據(jù)這些詞頻和文檔頻率統(tǒng)一進(jìn)行相關(guān)性評(píng)分計(jì)算,這樣文檔的相關(guān)性評(píng)分最為準(zhǔn)確。但是一般不建議使用這種方式,因?yàn)闀?huì)耗費(fèi)較多的CPU和內(nèi)存。
作者:中國(guó)農(nóng)業(yè)銀行研發(fā)中心 王燦
![]()
