在我的elasticsearch查询中,我有以下内容:
“ from”:0, “大小”:100,
我在数据库中有成千上万条记录,我想批量获取100条记录。 我处理一批,然后取下一批100,依此类推。我知道总共要取多少条记录。
因此'from'的值需要动态更改。 如何在代码中修改“来源”?
编辑:我正在用Groovy编程。
答案 0 :(得分:1)
有两种方法可以做到这一点,具体取决于您的需求-
1)第一个是简单地使用分页,您可以在循环中以所需结果大小不断更新“ from”变量,直到检索到所有结果(考虑开始时总计数),但是这种方法的问题是-直到'from'为<9000为止,它仍然可以正常工作,但是当它超过9000时,您会收到此大小限制错误-
"Result window is too large, from + size must be less than or equal to: [10000] but was [100000]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting"
如错误所述,可以通过更改index.max_result_window设置来抵消。但是,如果您打算将此调用用作一次性操作(例如重新编制索引的示例),则最好将其用于滚动api,如下所述。 (参考-How to retrieve all documents(size greater than 10000) in an elasticsearch index)
2)您可以使用滚动API,在Java中是这样的:
public String getJSONResponse() throws IOException {
String res = "";
int docParsed = 0;
String fooResourceUrl
= "http://localhost:9200/myindex/mytype/_search?scroll=5m&size=100";
ResponseEntity<String> response
= restTemplate.getForEntity(fooResourceUrl, String.class);
JSONObject fulMappingOuter = (JSONObject) new JSONObject(response.getBody());
String scroll_id = fulMappingOuter.getString("_scroll_id");
JSONObject fulMapping = fulMappingOuter.getJSONObject("hits");
int totDocCount = fulMapping.getInt("total");
JSONArray hitsArr = (JSONArray) fulMapping.getJSONArray("hits");
System.out.println("total hits:" + hitsArr.length());
while (docParsed < totDocCount) {
for (int i = 0; i < hitsArr.length(); i++) {
docParsed++;
//do your stuff
}
String uri
= "http://localhost:9200/_search/scroll";
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
JSONObject searchBody = new JSONObject();
searchBody.put("scroll", "5m");
searchBody.put("scroll_id", scroll_id);
HttpEntity<String> entity = new HttpEntity<>(searchBody.toString(), headers);
// // send request and parse result
ResponseEntity<String> responseScroll = restTemplate
.exchange(uri, HttpMethod.POST, entity, String.class);
fulMapping = (JSONObject) new JSONObject(responseScroll.getBody()).get("hits");
hitsArr = (JSONArray) fulMapping.getJSONArray("hits");
// System.out.println("response when trying to upload to local: "+response.getBody());
}
return res;
}
调用滚动API会初始化一个'Scroller'。这将返回第一组结果以及scroll_id,在第一个调用中创建滚动条时,结果数为100。注意第一个网址的参数5m吗?这是为了设置滚动时间,即ElasticSearch将使搜索上下文保持活动状态的时间(以分钟为单位),如果此时间到期,则无法使用此滚动ID进一步获取结果(这也是删除滚动的一种很好的做法(如果您的工作在滚动时间到期之前已经完成,则保持上下文状态,因为保持滚动上下文处于活动状态会占用大量资源) 对于每个后续滚动请求,将发送更新的scroll_id并返回下一批结果。
注意:这里我使用Springboot的RestTemplate客户端进行调用,然后使用JSON解析器解析响应JSON。但是,通过使用Elasticsearch自己的Groovy的高级REST客户端可以实现相同的目的。这是对滚动API的引用- https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-scroll.html