需求
查詢某個索引的全部數據,用於導出
什么是 scroll 查詢
scroll 查詢 可以用來對 Elasticsearch 有效地執行大批量的文檔查詢,而又不用付出深度分頁那種代價。
游標查詢允許我們 先做查詢初始化,然后再批量地拉取結果。 這有點兒像傳統數據庫中的 cursor 。
游標查詢會取某個時間點的快照數據。 查詢初始化之后索引上的任何變化會被它忽略。 它通過保存舊的數據文件來實現這個特性,結果就像保留初始化時的索引 視圖 一樣。
深度分頁的代價根源是結果集全局排序,如果去掉全局排序的特性的話查詢結果的成本就會很低。 游標查詢用字段 _doc 來排序。 這個指令讓 Elasticsearch 僅僅從還有結果的分片返回下一批結果。
啟用游標查詢可以通過在查詢的時候設置參數 scroll 的值為我們期望的游標查詢的過期時間。 游標查詢的過期時間會在每次做查詢的時候刷新,所以這個時間只需要足夠處理當前批的結果就可以了,而不是處理查詢結果的所有文檔的所需時間。 這個過期時間的參數很重要,因為保持這個游標查詢窗口需要消耗資源,所以我們期望如果不再需要維護這種資源就該早點兒釋放掉。 設置這個超時能夠讓 Elasticsearch 在稍后空閑的時候自動釋放這部分資源。
解釋來自 https://www.elastic.co/guide/cn/elasticsearch/guide/2.x/scroll.html
具體使用
public static void exportExcel(String ip, String name, String type) throws HttpProcessException, IOException {
// 請求體,查詢條件
JSONObject jsonObject = JSONUtil.parseObj(json);
jsonObject.putOpt("size", 10000);
HttpConfig config = HttpConfig.custom()
.url("http://" + ip + ":9200/" + name + "/" + type + "/_search?scroll=1m")
.json(jsonObject.toString());
String response = HttpClientUtil.post(config);
//解析查詢結果
JSONObject object = JSONUtil.parseObj(response);
if (response.contains("error")) {
String reason = object.getJSONObject("error").getStr("reason");
return;
}
// 獲取本次查詢的 scroll_id,后續查詢帶上這個 id 即可
String scroll_id = object.getStr("_scroll_id");
JSONObject hits = object.getJSONObject("hits");
// 結果集
JSONArray hitsArray = hits.getJSONArray("hits");
List<JSONObject> hitsList = hitsArray.toList(JSONObject.class);
JSONObject scroll = new JSONObject();
scroll.putOpt("scroll_id", scroll_id);
scroll.putOpt("scroll", "2m");
// 循環
while (hitsList.size() != 0) {
// 這里填寫你的業務邏輯,即對每一條數據的處理
// 繼續向后查詢
config = HttpConfig.custom()
.url("http://" + ip + ":9200/_search/scroll")
.json(JSONUtil.toJsonStr(scroll));
object = JSONUtil.parseObj(HttpClientUtil.post(config));
hits = object.getJSONObject("hits");
// 結果集
hitsArray = hits.getJSONArray("hits");
hitsList = hitsArray.toList(JSONObject.class);
}
}