本文将從資料存儲和搜尋的角度簡單分析Elasticsearch的搜尋運作機制,主要涉及搜尋API、搜尋機制、存在問題和解決方案。
Search API允許使用者執行一個搜尋查詢并傳回比對查詢的搜尋命中結果。
Elasticsearch查詢主要有兩種方式:<code>URI Search</code>和<code>Request Body Search</code>。
URI Search:通過URI參數實作搜尋,特點是操作簡便,僅包含部分查詢文法,常用參數如下:
q:指定查詢語句,使用Query String Syntax
df:預設字段,不指定時,會對所有字段進行查詢
sort:排序
profile:用于檢視查詢是如何被執行的
Request Body Search:完備的查詢文法Query DSL,是以還是建議使用Request Body Search。
建議先參考上篇Elasticsearch核心技術(四):分布式存儲架構與索引原理分析,其中主要介紹了ES的分布式存儲架構和原理。
Elasticsearch的分布式搜尋的運作機制稱為<code>Query-then-Fetch</code>。具體分為Query和Fetch兩個階段:

Query階段
使用者發出搜尋請求到達ES節點。節點收到請求後,會以協調節點(Coordinating Node)的身份,在6個主副分片中随機選擇3個分片,發送查詢請求。
被選中的節點,進行排序(根據score值進行排序)。然後每個分片都傳回 From+size 個排序後的文檔id和排序值給協調節點。 注意這裡傳回的是文檔id。
Fetch階段
Coordinating節點将Query階段從每個分片擷取的排序的文檔id清單重新進行排序,選取 From 到 From+size 個文檔的id。
以<code>multi get</code>請求的方式,到相應的分片擷取詳細的文檔資料。
因為Elasticsearch在查詢的時候不知道文檔位于哪個分片,是以索引的所有分片都要參與搜尋,然後協調節點将結果合并,在根據文檔ID擷取文檔内容。例如現在有5個分片,需要查詢比對度Top10的資料,那麼每個分片都要查詢出目前分片的Top10的資料,協調節點将5×10個結果再次進行排序,傳回Top10的結果給用戶端。
Query-then-Fetch存在問題分為兩方面,一個是性能問題,一個是相關性算分問題。
性能問題
性能問題主要表現為深度分頁的問題。Elasticsearch資料是分片存儲的,資料分布在多台機器上。有這樣一個場景,如何擷取前1000個文檔?當擷取從990-1000的文檔時候,會在每個分片上面都先擷取1000個文檔,然後再由協調節點聚合所有分片的結果在排序選取前1000個文檔。
這個過程有什麼問題嗎?當然是有的,頁數越深,處理文檔越多,占用記憶體越多,耗時越長。是以要盡量避免深度分頁。當然,ES官方也注意了這個問題,是以通過<code>index.max_result_window</code>限定最多到10000條資料。當然我們也可以根據業務需要修改這個參數,這也解釋了:為什麼Google搜尋結果隻有相關度最高的17頁結果,百度隻有76頁的結果,原因之一是受限于Elasticsearch深度分頁的性能問題。
相關性算分問題
另外一個問題是相關性算分不準确問題。每個分片都基于自己分片上面的資料進行相關度計算。這會導緻打分偏離的情況,特别是資料量很少的時候。相關性算分在分片之間是互相獨立。當文檔總數很少的情況下,如果主分片大于1,如果主分片數越多,相關性算分會越不準。
如何解決算分不準的問題?
當資料量不大的時候,将主分片數設定為1;當資料量足夠大的時候,隻要保證文檔均勻分布在各個分片上面,結果一般不會出現偏差
使用<code>DFS Query Then Fetch</code>
在搜尋的URL中指定參數 <code>_search?search_type=dfs_query_then_fetch</code> ;這樣就可以保證每個分片把各個分片的詞頻和文檔頻率進行搜集,然後進行一次相關性算分。但是這樣會耗費更多的CPU和記憶體資源,執行性能較低。
如何避免深度分頁的問題?
使用<code>Search_After</code>:
ES提供實時的下一頁文檔擷取功能,這個功能隻能下一頁,不能上一頁;
不能指定頁數,不能使用from參數;
三種分頁方式對比:
類型
場景
From/Size
需要實時擷取頂部的部分文檔,且需要自由翻頁
Scroll
需要全部文檔,如導出所有資料的功能
Search_After
需要全部文檔,不需要自由翻頁
經濟基礎決定上層建築,ES的分片存儲決定了搜尋機制。其實存儲和搜尋不能分割開來看,隻存儲不可搜尋,這個存儲是沒有意義的;隻搜尋沒有存儲(資料源)是空中樓閣。
由于部落客也是在攀登的路上,文中可能存在不當之處,歡迎各位多指教! 如果文章對您有用,那麼請點個”推薦“,以資鼓勵!