1. 程式人生 > >SpringBoot整合Elasticsearch遊標查詢(scroll)

SpringBoot整合Elasticsearch遊標查詢(scroll)

## 遊標查詢(scroll)簡介 `scroll` 查詢 可以用來對 Elasticsearch 有效地執行大批量的文件查詢,而又不用付出深度分頁那種代價。 遊標查詢會取某個時間點的快照資料。 查詢初始化之後索引上的任何變化會被它忽略。 它通過儲存舊的資料檔案來實現這個特性,結果就像保留初始化時的索引 檢視 一樣。 啟用遊標查詢可以通過在查詢的時候設定引數 `scroll` 的值為我們期望的遊標查詢的過期時間。 遊標查詢的過期時間會在每次做查詢的時候重新整理,所以這個時間只需要足夠處理當前批的結果就可以了,而不是處理查詢結果的所有文件的所需時間。 這個過期時間的引數很重要,因為保持這個遊標查詢視窗需要消耗資源,所以我們期望如果不再需要維護這種資源就該早點兒釋放掉。 設定這個超時能夠讓 Elasticsearch 在稍後空閒的時候自動釋放這部分資源。 ```bash GET /old_index/_search?scroll=1m { "query": { "match_all": {}}, "sort" : ["_doc"], "size": 1000 } ``` scroll=1m:保持遊標查詢視窗一分鐘。 返回結果示例: ```json { "_scroll_id": "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs=", "took": 10, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 2633253, "max_score": 1.0, "hits": [ { "_index": "old_index", "_type": "old_index_type", "_id": "1", "_score": 1.0, "_source": { ... } } ] } } ``` 這個查詢的返回結果包括一個欄位 `_scroll_id`, 它是一個base64編碼的長字串 。 現在我們能傳遞欄位 `_scroll_id` 到 `_search/scroll` 查詢介面獲取下一批結果: ```bash GET /_search/scroll { "scroll": "1m", "scroll_id" : "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs=" } ``` 注意:需要再次設定遊標查詢過期時間為一分鐘。 這個遊標查詢返回下一批結果。 另外儘管我們指定欄位 `size` 的值為`1000`,但是我們有可能取到超過這個值數量的文件。 當查詢的時候, 欄位 `size` 作用於單個分片,所以每個批次實際返回的文件數量最大為 `size * number_of_primary_shards`。 注意:遊標查詢每次返回一個新欄位 `_scroll_id`。每次我們做下一次遊標查詢, 我們必須把前一次查詢返回的欄位`_scroll_id` 傳遞進去。 當沒有更多的結果返回的時候,我們就處理完所有匹配的文件了。 ## 整合 新增以下三個方法: ```java /** * 遊標查詢 * @param params 查詢入參 * @param indexName 索引名稱 * @param type 索引型別 * @param defaultSort 預設排序 * @param keyMappings 欄位對映 * @param keyMappingsMap 索引對應欄位對映 * @param scrollTimeInMillis 遊標開啟的時間 * @return Page */ protected Page commonStartScroll(Map params, String indexName, String type, String defaultSort, Map keyMappings, Map> keyMappingsMap, long scrollTimeInMillis) { SearchQuery searchQuery = buildSearchQuery(params, indexName, type, defaultSort, keyMappings, keyMappingsMap); return elasticsearchTemplate.startScroll(scrollTimeInMillis, searchQuery, Map.class); } /** * 遊標查詢 * @param scrollId 遊標ID * @param scrollTimeInMillis 遊標開啟的時間 * @return Page */ protected Page commonContinueScroll(String scrollId, long scrollTimeInMillis) { return elasticsearchTemplate.continueScroll(scrollId, scrollTimeInMillis, Map.class); } /** * 根據遊標ID清除遊標(提早釋放資源,降低ES的負擔) * @param scrollId 遊標ID */ protected void clearScroll(String scrollId) { elasticsearchTemplate.clearScroll(scrollId); } ``` `StoreSearchService`中增加遊標查詢方法以及清除遊標方法: ```java /** * 遊標查詢 * @param params 查詢條件 * @return page */ public Page scroll(Map params) { IndexConfig config = indexEntity.getConfigByDocCode(DOC_CODE); // 如果請求引數包含遊標ID,則說明執行翻頁操作,否則認為開啟新的遊標查詢 String scrollId = params.getOrDefault(SCROLL_ID, null); if (StringUtils.isNotBlank(scrollId)) { return commonContinueScroll(params.get(scrollId), config.getScrollTimeInMillis()); } return commonStartScroll(params, config.getIndexName(), config.getType(), DEFAULT_SORT, keyMappings, keyMappingsMap, config.getScrollTimeInMillis()); } public void clearScroll(String scrollId) { super.clearScroll(scrollId); } ``` 對外暴露介面: ```java @PostMapping("/scroll") public ResponseResult scroll(@RequestBody Map params) { return ResponseResult.success(storeSearchService.scroll(params)); } @GetMapping("/scroll/clear/{scrollId}") public ResponseResult clearScroll(@PathVariable String scrollId) { storeSearchService.clearScroll(scrollId); return ResponseResult.success(null); } ``` 遊標查詢分為開啟和繼續兩個步驟,介面`/scroll`中根據`_scrollId`判斷為開啟遊標查詢還是繼續遊標查詢。 若條件允許的話,儘量將遊標查詢及時關閉,以釋放ES叢集的資源,降低負擔。 ## 原始碼 Git專案地址:[https://github.com/lifengdi/search](https://github.com/lifengdi/search) 如果覺得有幫助的話,請幫忙點贊、點星小小的支援一下~ 謝謝~~ 原文連結:[https://www.lifengdi.com/archives/article/2119](https://www.lifengdi.com/archives/artic