天天看點

Elasticsearch之四種查詢類型和搜尋原理(部落客推薦)

 Elasticsearch Client發送搜尋請求,某個索引庫,一般預設是5個分片(shard)。

  它傳回的時候,由各個分片彙總結果回來。

Elasticsearch之四種查詢類型和搜尋原理(部落客推薦)

   官網API

Elasticsearch之四種查詢類型和搜尋原理(部落客推薦)

es 在查詢時, 可以指定搜尋類型為下面四種:

QUERY_THEN_FETCH

QUERY_AND_FEATCH

DFS_QUERY_THEN_FEATCH

DFS_QUERY_AND_FEATCH

那麼這 4 種搜尋類型有什麼差別?

在講這四種搜尋類型的差別之前, 先分析一下分布式搜尋背景介紹:

ES 天生就是為分布式而生, 但分布式有分布式的缺點。 比如要搜尋某個單詞, 但是資料卻分别在 5 個分片(Shard)上面, 這 5 個分片可能在 5 台主機上面。 因為全文搜尋天生就要排序( 按照比對度進行排名) ,但資料卻在 5 個分片上, 如何得到最後正确的排序呢? ES是這樣做的, 大概分兩步:

step1、 ES 用戶端将會同時向 5 個分片發起搜尋請求。

step2、 這 5 個分片基于本分片的内容獨立完成搜尋, 然後将符合條件的結果全部傳回。

用戶端将傳回的結果進行重新排序和排名,最後傳回給使用者。也就是說,ES的一次搜尋,是一次scatter/gather過程(這個跟mapreduce也很類似)

  然而這其中有兩個問題:

第一、 數量問題。 比如, 使用者需要搜尋"衣服", 要求傳回符合條件的前 10 條。 但在 5個分片中, 可能都存儲着衣服相關的資料。 是以 ES 會向這 5 個分片都發出查詢請求, 并且要求每個分片都傳回符合條件的 10 條記錄。當ES得到傳回的結果後,進行整體排序,然後取最符合條件的前10條返給使用者。 這種情況, ES 中 5 個 shard 最多會收到 10*5=50條記錄, 這樣傳回給使用者的結果數量會多于使用者請求的數量。

第二、 排名問題。 上面說的搜尋, 每個分片計算符合條件的前 10 條資料都是基于自己分片的資料進行打分計算的。計算分值使用的詞頻和文檔頻率等資訊都是基于自己分片的資料進行的, 而 ES 進行整體排名是基于每個分片計算後的分值進行排序的(相當于打分依據就不一樣, 最終對這些資料統一排名的時候就不準确了), 這就可能會導緻排名不準确的問題。如果我們想更精确的控制排序, 應該先将計算排序和排名相關的資訊( 詞頻和文檔頻率等打分依據) 從 5 個分片收集上來, 進行統一計算, 然後使用整體的詞頻和文檔頻率為每個分片中的資料進行打分, 這樣打分依據就一樣了。

Elasticsearch在搜尋過程中存在以下幾個問題:

  (1)傳回資料量問題

    如果資料分散在預設的5個分片上,ES會向5個分片同時送出請求,每個分片都傳回10條資料,最終會傳回總資料為:5 * 10 = 50條資料,遠遠大于使用者請求。

  (2)傳回資料排名問題

    每個分片計算符合條件的前10條資料都是基于自己分片的資料進行打分計算的。計算分值(score)使用的詞頻和文檔頻率等資訊都是基于自己分片的資料進行的,而ES進行整體排名是基于排名是基于每個分片計算後的分值進行排序的(打分依據就不一緻,最終對這些資料統一排名的時候就不準确了)

=============================================================================

再舉個例子解釋一下【 排名問題】:

假設某學校有一班和二班兩個班級。

期末考試之後, 學校要給全校前十名學員發獎金。

但是一班和二班考試的時候使用的不是一套試卷。

一班: 使用的是 A 卷【 A 卷偏容易】

二班: 使用的是 B 卷【 B 卷偏難】

結果就是一班的最高分是 100 分, 最低分是 80 分。

二班的最高分是 70 分, 最低分是 30 分。

這樣全校前十名就都是一班的學員了。 這顯然是不合理的。

因為一班和二班的試卷難易程度不一樣, 也就是打分依據不一樣, 是以不能放在一塊排名。

【 這個就解釋了剛才的排名問題】

如果想要保證排名準确的話, 需要保證一班和二班使用的試卷内容一樣。

可以這樣做, 把 A 卷和 B 卷的内容組合到一塊, 作為 C 卷。

一班和二班考試都使用 C 卷, 這樣他們的打分依據就一樣了, 最終再根據所有學員的成績排

名求前十名就準确合理了。

 這兩個問題, ES 也沒有什麼較好的解決方法, 最終把選擇的權利交給使用者, 方法就是在搜尋的時候指定 search type。

Elasticsearch在搜尋問題的解決思路

  (1)傳回資料數量問題

    第一步:先從每個分片彙總查詢的資料id,進行排名,取前10條資料

    第二步:根據這10條資料id,到不同分片擷取資料

    将各個分片打分标準統一

 Elasticsearch的搜尋類型(SearchType類型)

1、 query and fetch

向索引的所有分片 ( shard)都發出查詢請求, 各分片傳回的時候把元素文檔 ( document)和計算後的排名資訊一起傳回。

這種搜尋方式是最快的。 因為相比下面的幾種搜尋方式, 這種查詢方法隻需要去 shard查詢一次。 但是各個 shard 傳回的結果的數量之和可能是使用者要求的 size 的 n 倍。

優點:這種搜尋方式是最快的。因為相比後面的幾種es的搜尋方式,這種查詢方法隻需要去shard查詢一次。

缺點:傳回的資料量不準确, 可能傳回(N*分片數量)的資料并且資料排名也不準确,同時各個shard傳回的結果的數量之和可能是使用者要求的size的n倍。

2、 query then fetch( es 預設的搜尋方式)

如果你搜尋時, 沒有指定搜尋方式, 就是使用的這種搜尋方式。 這種搜尋方式, 大概分兩個步驟:

第一步, 先向所有的 shard 送出請求, 各分片隻傳回文檔 id(注意, 不包括文檔 document)和排名相關的資訊(也就是文檔對應的分值), 然後按照各分片傳回的文檔的分數進行重新排序和排名, 取前 size 個文檔。

第二步, 根據文檔 id 去相關的 shard 取 document。 這種方式傳回的 document 數量與使用者要求的大小是相等的。

優點:

傳回的資料量是準确的。

缺點:

性能一般,并且資料排名不準确。

3、 DFS query and fetch

這種方式比第一種方式多了一個 DFS 步驟,有這一步,可以更精确控制搜尋打分和排名。也就是在進行查詢之前, 先對所有分片發送請求, 把所有分片中的詞頻和文檔頻率等打分依據全部彙總到一塊, 再執行後面的操作、

資料排名準确

性能一般

傳回的資料量不準确, 可能傳回(N*分片數量)的資料

4、 DFS query then fetch

比第 2 種方式多了一個 DFS 步驟。

也就是在進行查詢之前, 先對所有分片發送請求, 把所有分片中的詞頻和文檔頻率等打分依據全部彙總到一塊, 再執行後面的操作、

  優點:

傳回的資料量是準确的

性能最差【 這個最差隻是表示在這四種查詢方式中性能最慢, 也不至于不能忍受,如果對查詢性能要求不是非常高, 而對查詢準确度要求比較高的時候可以考慮這個】

  DFS 是一個什麼樣的過程?

從 es 的官方網站我們可以發現, DFS 其實就是在進行真正的查詢之前, 先把各個分片的詞頻率和文檔頻率收集一下, 然後進行詞搜尋的時候, 各分片依據全局的詞頻率和文檔頻率進行搜尋和排名。 顯然如果使用 DFS_QUERY_THEN_FETCH 這種查詢方式, 效率是最低的,因為一個搜尋, 可能要請求 3 次分片。 但, 使用 DFS 方法, 搜尋精度是最高的。

  總結一下, 從性能考慮 QUERY_AND_FETCH 是最快的, DFS_QUERY_THEN_FETCH 是最慢的。從搜尋的準确度來說, DFS 要比非 DFS 的準确度更高。

  關于es的四種查詢API程式設計,請見我下面寫的部落格

本文轉自大資料躺過的坑部落格園部落格,原文連結:http://www.cnblogs.com/zlslch/p/6438352.html,如需轉載請自行聯系原作者

繼續閱讀