- Elastic Stack應用寶典
- 田雪松編著
- 2899字
- 2020-07-22 17:21:29
4.2 分頁與排序
在查詢大量數據時必須要做分頁,一方面是便于用戶瀏覽,但更重要的是防止一次加載數據量過大而導致內存溢出。_search接口提供了一組參數可用于檢索結果分頁,但它們有各自不同的應用場景,需要區別對待。
4.2.1 from/size參數
_search接口提供的from和size兩個參數可以實現分頁,其中from參數代表檢索文檔的起始位置,默認值為0;而size參數則代表每次檢索文檔的總量,默認值為10。form和size即可以在URI參數中使用,也可以在請求體中使用。例如示例4-5中的兩個請求都是從第100條文檔開始,一共取20條文檔:

示例4-5 from/size參數
from與size的和不能超過index.max_result_window這個索引配置項設置的值。默認情況下這個配置項的值為10000,所以如果要查詢10000條以后的文檔,就必須要增加這個配置值。例如,要檢索第10000條開始的200條數據,這個參數的值必須要大于10200,否則將會拋出類似“Result window is too large”的異常。由此可見,Elasticsearch在使用from和size處理分頁問題時會將所有數據全部取出來,然后再截取用戶指定范圍的數據返回。所以在查詢非常靠后的數據時,即使使用了from和size定義的分頁機制依然有內存溢出的可能,而index.max_result_window設置的10000條則是對Elasticsearch的一種保護機制。
那么Elasticsearch為什么要這么設計呢?首先,在互聯網時代的數據檢索應該通過相似度算法,提高檢索結果與用戶期望的附和度,而不應該讓用戶在檢索結果中自己挑選滿意的數據。以互聯網搜索為例,用戶在瀏覽搜索結果時很少會看到第3頁以后的內容。假如用戶在翻到第10000條數據時還沒有找到需要的結果,那么他對這個搜索引擎一定會非常失望。其次,如果真的需要遍歷所有數據,不能單純使用from和size,應該結合scroll接口使用。
4.2.2 scroll參數
scroll即是_search接口的參數也是接口,它提供了一種類似數據庫游標的文檔遍歷機制,一般用于非實時性的海量文檔處理需求。例如,將一個索引中的文檔導入到另一個索引中,或者將索引中的文檔導入到MySQL中。使用scroll機制有兩個步驟,第一步是創建游標,第二步則是對游標遍歷。這兩個步驟基于_search接口執行,例如:


示例4-6 創建游標
其中,scroll參數只能在URI中使用,而不能出現在請求體中。它定義了檢索生成的游標需要保留多長時間,比如2m代表2分鐘,1h代表1小時。scroll保留時長不是處理完所有數據所需要的時長,而是處理單次遍歷所需要的時間。從性能角度來看,保留時間越短,空間利用率就越高,所以應該根據單次處理能力設置這個值。size參數可以放在請求體中,也可以掛在地址后面,代表了每次遍歷時返回的文檔數量。size只能在初始查詢時指定在遍歷時不能更改,請求體中還可以包含其他_search接口的合法參數。在添加了scroll參數后,返回的結果中將包含一個名為_scroll_id的字段,它惟一地代表了一個scroll查詢的結果。接下來,根據這個_scroll_id就可以對結果進行遍歷了。例如:

示例4-7 遍歷游標
在遍歷游標時,不需要指明索引或映射類型,反復調用_search/scroll接口就可實現對結果的遍歷了。請求體中的scroll參數相當于延長了游標的存活時長,而scroll_id則是在初始查詢時返回的_scroll_id值。在遍歷過程中將根據初始查詢時設置的size值返回相應數量的文檔,但在遍歷過程中不能重新修改size值。每次調用scroll都會自動向后遍歷,直到所有文檔全部遍歷結束。在遍歷過程中,每次返回的結果中還是會包含_scroll_id字段,通常來說它的值會保持不變。
scroll在超時后將自動刪除,但Elasticsearch也為用戶提供了主動刪除scroll的接口。可以通過請求體發送要刪除的游標,例如:

示例4-8 刪除游標
對于海量文檔的遍歷,Elasticsearch還支持對scroll再做片段分割,每一個分割后的片段又可以被獨立使用。例如:

示例4-9 游標分段
其中,max定義了分割片段的總量為2,而id則定義了當前請求返回哪一個片段。所以,上面的請求將會把游標分為兩個片段,當前請求返回第一個片段。id值從0開始,所以它的值應該小于max。在返回的結果中,同樣也會包含_scroll_id字段。每一個游標片段都是獨立的,可以使用多線程并發處理。從物理角度來看,Elasticsearch會讓游標片段分配到不同的索引分片上以提升遍歷速度。所以,游標片段數量不應該大于索引分片數量,否則游標分段的性能將受到影響。正因如此,游標片段數量也有上限,默認為1024,由index.max_slices_per_scroll參數設置。
4.2.3 search_after參數
在前面介紹分頁時提到了兩種機制,一種是使用from/size,一種是使用scroll。這兩種機制都會將數據整體加載進來,不同的是from/size機制下每一次請求都會加載,而scroll則只在初始時加載。所以,scroll實際上比較適合對同一結果集做多次迭代,但在數據量比較大時依然對性能有影響。為此,Elasticsearch提供了另外一種機制search after,它使用search_after參數定義檢索應該在文檔某些字段的值之后查詢其他文檔,所以需要預先以這些字段排序。例如:

示例4-10 search_after
在上面的請求中,kibana_sample_data_flights將按DestCountry和FlightNum字段排序,但只返回DestCountry為AE并且FlightNum為AR9OTDM之后的10條文檔(size默認為10)。所以這種機制本質上是通過匹配字段,動態決定第一條文檔是哪一個,所以在這種情況下from必須設置為0或-1。不僅如此,參與排序的字段值需要保證惟一。雖然這種惟一性保證并非必須,但如果不惟一則在查詢時將導致歧義,有可能返回不正確的結果。
需要特別注意的是,這種機制在匹配字段時并非使用精確匹配,而是只要部分滿足即可。在上面的例子中,如果含有一個FlightNum為AR9OTDMXXX,也是滿足匹配條件的。但由于AR9OTDMXXX會排在AR9OTDM之后,所以還是不會出現問題的。
排序后的檢索結果中,都會在最后附帶一個排序字段的值,例如示例4-10檢索結果最后會包含如下內容:

示例4-11 排序結果
這個內容正好與當前檢索結果中的DestCountry和FlightNum字段值相同,可以為下一次search after使用。講到這里就涉及到檢索的另外一個重要內容-排序。
4.2.4 sort參數
排序是文檔檢索中另一個重要的話題,在很多應用中排序都是一個必不可少的功能。例如,按商品售價、銷量排序以搜索出物美價廉的商品。例如在示例4-10中,由于使用search after機制已經使用到了排序。Elasticsearch提供的排序可以依照文檔一個或多個字段排序,包括兩個虛擬字段_score和_doc。按_score排序就是按文檔相似度得分排序,而_doc則是按索引次序排序。例如:

示例4-12 排序
在示例4-12中給出了幾種排序方法,將會依次按AvgTicketPrice、FlightDelayMin字段升序排列,再按DistanceKilometers、_score字段降序排列。排序執行的順序與它們在sort數組中的次序一致。與SQL語言類似,asc代表升序,desc代表降序。默認情況下,除_score按降序排列,其余字段都按升序排列。Elasticsearch支持使用數組類型或多值類型字段做排序,但需要定義如何使用數組中的數據。這包括min、max、avg、sum、median等幾種情況,分別代表取最小值、最大值、平均值、總和或中值參與排序,可通過參數mode來定義。例如在下面的示例中,將按products.base_price字段的最大值做降序排列:

示例4-13 數組排序
默認情況下,查詢結果會按_score字段降序排列,_score字段是文檔與查詢條件的相似度得分。也就是說,越是靠前的結果與查詢條件的相似度越高,這與人們的使用習慣相符。相似度問題在全文檢索中是一個非常重要的話題,將在本書第6章中專門討論。
此外,由于排序算法需要知道所有參與排序的值才可能做運算,所以參與排序字段在文檔中的值都需要加載到內存中來。這一方面對節點分配的內存提出了更高要求,另一方面也要求參與排序的字段必須支持文檔值(Doc Value)或fielddata機制。這是因為倒排索引保存的是詞項到文檔的對應關系,適用于通過詞項檢索文檔。但在排序時需要的是通過文檔找到字段值參與排序,所以必須保證能夠通過文檔找到字段值。在默認情況下,文檔值機制對于非text類型的字段都是開啟的,而text類型則只能通過開啟fielddata機制才可能支持排序。這兩種機制在本書第2章2.2.2節有過介紹,如果不記得了可以翻回去查看。
- Mastering Concurrency Programming with Java 8
- 數據庫原理及應用(Access版)第3版
- C語言程序設計基礎與實驗指導
- Developing Middleware in Java EE 8
- Machine Learning with R Cookbook(Second Edition)
- OpenCV 3和Qt5計算機視覺應用開發
- 編寫高質量代碼:改善Python程序的91個建議
- 精通API架構:設計、運維與演進
- 區塊鏈:以太坊DApp開發實戰
- 利用Python進行數據分析(原書第3版)
- Active Directory with PowerShell
- Android Wear Projects
- 代替VBA!用Python輕松實現Excel編程
- JSP程序設計與案例實戰(慕課版)
- Kohana 3.0 Beginner's Guide