原文地址在這里溶诞,我進(jìn)行了重新排版和措辭修正潤(rùn)色很澄,覺得算是比較好的科普文章甩苛。最近在進(jìn)行業(yè)務(wù)的查詢優(yōu)化讯蒲,有必要學(xué)習(xí)一下 ES 的查詢,所以就轉(zhuǎn)載了赁酝,其實(shí)本人真的特別覺得轉(zhuǎn)載是對(duì)原文作者的不尊重酌呆,不過原文這排版真惡心隙袁。
作者:好記性不如爛筆頭菩收!
出處:http://www.cnblogs.com/zlslch/
本文版權(quán)歸作者和博客園共有娜饵,歡迎轉(zhuǎn)載官辈,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文鏈接褐缠,否則保留追究法律責(zé)任的權(quán)利队魏。
Elasticsearch Client 發(fā)送搜索請(qǐng)求胡桨,某個(gè)索引庫(kù),一般默認(rèn)是5個(gè)分片(shard)昧谊,它返回的時(shí)候呢诬,由各個(gè)分片匯總結(jié)果回來(lái)尚镰,附上官網(wǎng)API狗唉。
在查詢 ES 時(shí)分俯,可以指定的搜索類型為下面四種:
- QUERY_THEN_FETCH
- QUERY_AND_FEATCH
- DFS_QUERY_THEN_FEATCH
- DFS_QUERY_AND_FEATCH
那么這 4 種搜索類型有什么區(qū)別缸剪?在講這四種搜索類型的區(qū)別之前东亦, 先說(shuō)明一下分布式搜索背景讥此。
分布式搜索面對(duì)的共性問題
ES 天生就是為分布式而生萄喳, 但分布式有分布式的缺點(diǎn)。 比如要搜索某個(gè)單詞充坑, 但是數(shù)據(jù)卻分別在 5 個(gè)分片(Shard)上面, 這 5 個(gè)分片可能在 5 臺(tái)主機(jī)上面辈灼。 因?yàn)槿乃阉魈焐鸵判颍?按照匹配度進(jìn)行排名) ,但數(shù)據(jù)卻在 5 個(gè)分片上巡莹, 如何得到最后正確的排序呢降宅? ES是這樣做的腰根, 大概分兩步:
- ES 客戶端將會(huì)同時(shí)向 5 個(gè)分片發(fā)起搜索請(qǐng)求额嘿。
- 這 5 個(gè)分片基于本分片的內(nèi)容獨(dú)立完成搜索劣挫, 然后將符合條件的結(jié)果全部返回捕儒。
客戶端將返回的結(jié)果進(jìn)行重新排序和排名邓夕,最后返回給用戶焚刚。也就是說(shuō)矿咕,ES的一次搜索,是一次 scatter/gather
過程(這個(gè)跟mapreduce也很類似)
然而這其中有兩個(gè)問題:
- 數(shù)量問題碳柱。 比如莲镣, 用戶需要搜索"衣服", 要求返回符合條件的前 10 條的圆。 但在 5個(gè)分片中季俩, 可能都存儲(chǔ)著衣服相關(guān)的數(shù)據(jù)梅掠。 所以 ES 會(huì)向這 5 個(gè)分片都發(fā)出查詢請(qǐng)求瓤檐, 并且要求每個(gè)分片都返回符合條件的 10 條記錄挠蛉。當(dāng)ES得到返回的結(jié)果后谴古,進(jìn)行整體排序掰担,然后取最符合條件的前10條返給用戶带饱。 這種情況勺疼, ES 中 5 個(gè) shard 最多會(huì)收到 10*5=50條記錄执庐, 這樣返回給用戶的結(jié)果數(shù)量會(huì)多于用戶請(qǐng)求的數(shù)量轨淌。
- 排名問題递鹉。 上面說(shuō)的搜索躏结, 每個(gè)分片計(jì)算符合條件的前 10 條數(shù)據(jù)都是基于自己分片的數(shù)據(jù)進(jìn)行打分計(jì)算的窜觉。計(jì)算分值使用的詞頻和文檔頻率等信息都是基于自己分片的數(shù)據(jù)進(jìn)行的禀挫, 而 ES 進(jìn)行整體排名是基于每個(gè)分片計(jì)算后的分值進(jìn)行排序的(相當(dāng)于打分依據(jù)就不一樣旬陡, 最終對(duì)這些數(shù)據(jù)統(tǒng)一排名的時(shí)候就不準(zhǔn)確了), 這就可能會(huì)導(dǎo)致排名不準(zhǔn)確的問題语婴。如果我們想更精確的控制排序描孟, 應(yīng)該先將計(jì)算排序和排名相關(guān)的信息( 詞頻和文檔頻率等打分依據(jù)) 從 5 個(gè)分片收集上來(lái), 進(jìn)行統(tǒng)一計(jì)算砰左, 然后使用整體的詞頻和文檔頻率為每個(gè)分片中的數(shù)據(jù)進(jìn)行打分匿醒, 這樣打分依據(jù)就一樣了。
ES 需要解決的問題
所以缠导,Elasticsearch 在搜索過程中需要解決的問題也類似:
- 返回?cái)?shù)據(jù)量問題廉羔,如果數(shù)據(jù)分散在默認(rèn)的5個(gè)分片上,ES會(huì)向5個(gè)分片同時(shí)發(fā)出請(qǐng)求僻造,每個(gè)分片都返回10條數(shù)據(jù)憋他,最終會(huì)返回總數(shù)據(jù)為:5 * 10 = 50條數(shù)據(jù)竹挡,遠(yuǎn)遠(yuǎn)大于用戶請(qǐng)求宝泵。
- 返回?cái)?shù)據(jù)排名問題男应,每個(gè)分片計(jì)算符合條件的前10條數(shù)據(jù)都是基于自己分片的數(shù)據(jù)進(jìn)行打分計(jì)算的。計(jì)算分值(score)使用的詞頻和文檔頻率等信息都是基于自己分片的數(shù)據(jù)進(jìn)行的,而ES進(jìn)行整體排名是基于排名是基于每個(gè)分片計(jì)算后的分值進(jìn)行排序的(打分依據(jù)就不一致,最終對(duì)這些數(shù)據(jù)統(tǒng)一排名的時(shí)候就不準(zhǔn)確了)
舉個(gè)例子闡述下 排名問題 ,一個(gè)獎(jiǎng)學(xué)金的判定的 Case:
假設(shè)某學(xué)校有一班和二班兩個(gè)班級(jí)。期末考試之后, 學(xué)校要給全校前十名學(xué)員發(fā)獎(jiǎng)金蜈项。但是一班和二班考試的時(shí)候使用的不是一套試卷。
一班: 使用的是 A 卷【 A 卷偏容易】
二班: 使用的是 B 卷【 B 卷偏難】
結(jié)果就是一班的最高分是 100 分博个, 最低分是 80 分。二班的最高分是 70 分, 最低分是 30 分。這樣全校前十名就都是一班的學(xué)員了对湃。 這顯然是不合理的。因?yàn)橐话嗪投嗟脑嚲黼y易程度不一樣, 也就是打分依據(jù)不一樣, 所以不能放在一塊排名肮之。這就解釋了剛才的排名問題,如果想要保證排名準(zhǔn)確的話柑土, 需要保證一班和二班使用的試卷內(nèi)容一樣狐榔〗钨耍可以這樣做昆婿, 把 A 卷和 B 卷的內(nèi)容組合到一塊, 作為 C 卷搁胆。一班和二班考試都使用 C 卷, 這樣他們的打分依據(jù)就一樣了伪煤, 最終再根據(jù)所有學(xué)員的成績(jī)進(jìn)行排名蝗敢。
ES 的解決方案
這兩個(gè)問題拂到, ES 也沒有什么較好的解決方法罐孝, 最終把選擇的權(quán)利交給用戶, 方法就是在搜索的時(shí)候指定 search type承疲。
Elasticsearch在搜索問題的解決思路
- 數(shù)量問題
- 先從每個(gè)分片匯總查詢的數(shù)據(jù)id党远,進(jìn)行排名,取前10條數(shù)據(jù)娩脾;
- 第二步:根據(jù)這10條數(shù)據(jù)id,到不同分片獲取數(shù)據(jù)豺谈;
- 排名問題:將各個(gè)分片打分標(biāo)準(zhǔn)統(tǒng)一
Elasticsearch的搜索類型(SearchType)
query and fetch
向索引的所有分片 ( shard)都發(fā)出查詢請(qǐng)求责掏, 各分片返回的時(shí)候把元素文檔 ( document)和計(jì)算后的排名信息一起返回。這種搜索方式是最快的。 因?yàn)橄啾认旅娴膸追N搜索方式没龙, 這種查詢方法只需要去 shard查詢一次溪王。 但是各個(gè) shard 返回的結(jié)果的數(shù)量之和可能是用戶要求的 size 的 n 倍皱卓。
- 優(yōu)點(diǎn):這種搜索方式是最快的部逮。因?yàn)橄啾群竺娴膸追Nes的搜索方式峡扩,這種查詢方法只需要去shard查詢一次教届。
- 缺點(diǎn):返回的數(shù)據(jù)量不準(zhǔn)確, 可能返回(N*分片數(shù)量)的數(shù)據(jù)并且數(shù)據(jù)排名也不準(zhǔn)確洒擦,同時(shí)各個(gè)shard返回的結(jié)果的數(shù)量之和可能是用戶要求的size的n倍掸茅。
query then fetch( default )
如果你搜索時(shí), 沒有指定搜索方式, 就是使用的這種搜索方式靶草。 這種搜索方式蹄胰, 大概分兩個(gè)步驟:
- 先向所有的 shard 發(fā)出請(qǐng)求, 各分片只返回文檔 id(注意奕翔, 不包括文檔 document)和排名相關(guān)的信息(也就是文檔對(duì)應(yīng)的分值)烤送, 然后按照各分片返回的文檔的分?jǐn)?shù)進(jìn)行重新排序和排名, 取前 size 個(gè)文檔糠悯。
- 根據(jù)文檔 id 去相關(guān)的 shard 取 document帮坚。 這種方式返回的 document 數(shù)量與用戶要求的大小是相等的。
- 優(yōu)點(diǎn):返回的數(shù)據(jù)量是準(zhǔn)確的互艾。
- 缺點(diǎn):性能比 query and fetch 差试和,并且數(shù)據(jù)排名不準(zhǔn)確。
DFS query and fetch
這種方式比 query and fetch 多了一個(gè) DFS 步驟纫普,有這一步阅悍,可以更精確控制搜索打分和排名。也就是在進(jìn)行查詢之前昨稼, 先對(duì)所有分片發(fā)送請(qǐng)求节视, 把所有分片中的詞頻和文檔頻率等打分依據(jù)全部匯總到一塊, 再執(zhí)行后面的操作假栓。
- 優(yōu)點(diǎn):數(shù)據(jù)排名準(zhǔn)確
- 缺點(diǎn):性能比 query then fetch 差寻行,返回的數(shù)據(jù)量不準(zhǔn)確, 可能返回 (N*分片數(shù)量) 的數(shù)據(jù)
DFS query then fetch
比 query then fetch 多了一個(gè) DFS 步驟匾荆。也就是在進(jìn)行查詢之前拌蜘, 先對(duì)所有分片發(fā)送請(qǐng)求, 把所有分片中的詞頻和文檔頻率等打分依據(jù)全部匯總到一塊牙丽, 再執(zhí)行后面的操作简卧。
- 優(yōu)點(diǎn):數(shù)據(jù)量是準(zhǔn)確、數(shù)據(jù)排名準(zhǔn)確
- 缺點(diǎn):性能最差
DFS 是一個(gè)什么樣的過程烤芦?
從 es 的官方網(wǎng)站我們可以發(fā)現(xiàn)举娩, DFS 其實(shí)就是在進(jìn)行真正的查詢之前, 先把各個(gè)分片的詞頻率和文檔頻率收集一下构罗, 然后進(jìn)行詞搜索的時(shí)候铜涉, 各分片依據(jù)全局的詞頻率和文檔頻率進(jìn)行搜索和排名。 顯然如果使用 DFS_QUERY_THEN_FETCH 這種查詢方式绰播, 效率是最低的骄噪,因?yàn)橐粋€(gè)搜索, 可能要請(qǐng)求 3 次分片蠢箩。 但链蕊, 使用 DFS 方法苔可, 搜索精度是最高的例嘱。
小結(jié)
從性能考慮 QUERY_AND_FETCH 是最快的, DFS_QUERY_THEN_FETCH 是最慢的颖变。從搜索的準(zhǔn)確度來(lái)說(shuō)掌实, DFS 要比非 DFS 的準(zhǔn)確度更高陪蜻,用戶可以酌情根據(jù)業(yè)務(wù)場(chǎng)景進(jìn)行類型選擇。