动态更改Elasticsearch查询中的“从”值

时间:2019-12-03 08:11:17

标签: elasticsearch

在我的elasticsearch查询中,我有以下内容:

  

“ from”:0,     “大小”:100,

我在数据库中有成千上万条记录,我想批量获取100条记录。 我处理一批,然后取下一批100,依此类推。我知道总共要取多少条记录。

因此'from'的值需要动态更改。 如何在代码中修改“来源”?

编辑:我正在用Groovy编程。

1 个答案:

答案 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

https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high-search-scroll.html