1.對(duì)已知文檔的搜索
如果被搜索的文檔(不論是單個(gè)文檔庙洼,還是批量文檔)能夠從主分片或任意一個(gè)副本分片中被檢索到,則與索引文檔過程相同镊辕,對(duì)已知文檔的搜索也會(huì)用到路由算法油够,Elasticsearch 中的路由算法如下所示:
Shard = hash(routing) % number_of_primary_shards
2.對(duì)未知文檔的搜索
除了對(duì)已知文檔的搜索外,大部分請(qǐng)求實(shí)際上是不知道查詢條件會(huì)命中哪些文檔的征懈。這些被查詢條件命中的文檔可能位于 Elasticsearch 集群中的任意位置上石咬。因此,搜索請(qǐng)求的執(zhí)行不得不去查詢每個(gè)索引中的每一個(gè)分片卖哎。
在 Elasticsearch 中鬼悠,搜索過程分為查詢階段(Query Pahse)和獲取階段(Fetch Phase)。
在查詢階段亏娜,查詢請(qǐng)求會(huì)廣播到索引中的每一個(gè)主分片和備份中焕窝,每一個(gè)分片都會(huì)在本地執(zhí)行檢索,并在本地各建立一個(gè)優(yōu)先級(jí)隊(duì)列(Priority Queue)维贺。該優(yōu)先級(jí)隊(duì)列是一份根據(jù)文檔相關(guān)度指標(biāo)進(jìn)行排序的列表它掂,列表的長度由 from 和 size 兩個(gè)分頁參數(shù)決定。
查詢階段可以再細(xì)分成3個(gè)小的子階段:
(1)客戶端發(fā)送一個(gè)檢索請(qǐng)求給某個(gè)節(jié)點(diǎn)A溯泣,此時(shí)節(jié)點(diǎn)A會(huì)創(chuàng)建一個(gè)空的優(yōu)先級(jí)隊(duì)列虐秋,并配置好分頁參數(shù)from與size。
(2)節(jié)點(diǎn)A將搜索請(qǐng)求發(fā)送給該索引中的每一個(gè)分片垃沦,每個(gè)分片在本地執(zhí)行檢索客给,并將結(jié)果添加到本地優(yōu)先級(jí)隊(duì)列中。
(3)每個(gè)分片返回本地優(yōu)先級(jí)序列中所記錄的ID與sort值肢簿,并發(fā)送給節(jié)點(diǎn)A靶剑。節(jié)點(diǎn)A將這些值合并到自己的本地優(yōu)先級(jí)隊(duì)列中,并做出全局的排序译仗。
在獲取階段抬虽,主要是基于上一階段找到所要搜索文檔的具體位置匿垄,將文檔數(shù)據(jù)內(nèi)容取回并返回給客戶端肉渴。
在Elasticsearch中,默認(rèn)的搜索類型就是上面介紹的Query then Fetch突梦。上述描述運(yùn)作方式就是Query then Fetch咱圆。Query then Fetch有可能會(huì)出現(xiàn)打分偏離的情形笛辟,幸好功氨,Elasticsearch還提供了一個(gè)稱為"DFS Query then Fetch"的搜索方式,它和Query then Fetch基本相同手幢,但是它會(huì)執(zhí)行一個(gè)查詢來計(jì)算整體文檔的frequency捷凄。其處理過程如下所示:
(1)預(yù)查詢每個(gè)分片,詢問Term和Document Frequency等信息围来。
(2)發(fā)送查詢請(qǐng)求到每個(gè)分片跺涤。
(3)找到各個(gè)分片中所有匹配的文檔,并使用全局的Term/Document Frequency信息進(jìn)行打分监透。在執(zhí)行過程中依然需要對(duì)結(jié)果構(gòu)建一個(gè)優(yōu)先隊(duì)列桶错,如排序等。
(4)返回關(guān)于結(jié)果的元數(shù)據(jù)到請(qǐng)求節(jié)點(diǎn)胀蛮。需要指出的是院刁,此時(shí)實(shí)際文檔還沒有發(fā)送到請(qǐng)求節(jié)點(diǎn),發(fā)送的只是分?jǐn)?shù)粪狼。
(5)請(qǐng)求節(jié)點(diǎn)將來自所有分片的分?jǐn)?shù)合并起來退腥,并在請(qǐng)求節(jié)點(diǎn)上進(jìn)行排序,文檔被按照查詢要求進(jìn)行選擇再榄。最終狡刘,實(shí)際文檔從它們各自所在的獨(dú)立的分片上被檢索出來,結(jié)果被返回給讀者困鸥。
3.對(duì)詞條的搜索
具體到一個(gè)分片颓帝,ELasticsearch是如何按照詞條進(jìn)行進(jìn)行搜索的呢?
當(dāng)詞條數(shù)量較少時(shí)窝革,我們可以順序遍歷詞條獲取結(jié)果,但如果詞條有成千上萬個(gè)時(shí)吕座,Elasticsearch為了能快速找到某個(gè)詞條虐译,它對(duì)所有的詞條都進(jìn)行了排序,隨后使用二分法查找詞條吴趴,其查找效率為log(N)漆诽。這個(gè)過程就像查字典一樣,因此排序詞條的集合也稱為Term Dictionary锣枝。
為了提高查詢性能厢拭,Elasticsearch直接通過內(nèi)存查找詞條,而非從磁盤中讀取撇叁。但當(dāng)詞條太多時(shí)供鸠,顯然Term Dictionary也會(huì)很大,此時(shí)全部放在內(nèi)存有些不現(xiàn)實(shí)陨闹,于是引入了Term Index楞捂。
Term Index就像字典中的索引頁薄坏,其中的內(nèi)容如字母A開頭的有哪些詞條,這些詞條分別在哪頁寨闹。通過Term Index,Elasticsearch也可以快速定位到Term Dictionary的某個(gè)OffSet(位置偏移)胶坠,然后從這個(gè)位置再往后順序查找。
前面提及了單個(gè)詞條的搜索方法繁堡,而在實(shí)際應(yīng)用中沈善,更常見的往往是多個(gè)詞條拼接程的"聯(lián)合查詢"。