弹性搜索:Paginated中的RemoteTransportException搜索超过10000个结果

时间:2016-07-26 12:00:09

标签: java search elasticsearch scroll pagination

我正在使用Elastic Search通过我的java程序中的查询集对索引运行分页搜索。在这里,我有两个案例如下所述:

使用ES Scroll进行搜索。

这里例如:总搜索结果是10 010,页面大小是100.因此搜索结果将被分成11页,每页有100条记录。当我在每页上查看我的结果直到第10页时,正确地返回记录,即前10 000条记录。但是当我查看第11页,即从10 001到10 010的记录时,我得到以下错误:

  

RemoteTransportException [[James Jaspers] [127.0.0.1:9300] [indices:data / read / search [phase / query + fetch]]];嵌套:QueryPhaseExecutionException [结果窗口太大,+大小必须小于或等于:[10000]但是[10010]。
  引发者:QueryPhaseExecutionException [结果窗口太大,+大小必须小于或等于:[10000]但是[10010]。有关请求大型数据集的更有效方法,请参阅scroll api。可以通过更改[index.max_result_window]索引级别参数

来设置此限制

以下是代码段,在此搜索页面中,值传递为100,DEFAULT_SEARCH_PAGE_SIZE为1000

if (searchPage != null) {
            builder.setFrom((int) searchPage.getPageStart());
            builder.setSize((int) searchPage.getPageSize());
        } else {
            builder.setFrom(0);
            builder.setSize(DEFAULT_SEARCH_PAGE_SIZE);
        }

builder.setTypes(getType());
SearchResponse response = builder.execute().actionGet(60000);
SearchHits hits = response.getHits();
if (hits.getTotalHits() > 0) {
        for (SearchHit hit : response.getHits()) {
                    //process my hits and add them to list

        }
  }
//return the list

正如上面的错误所示,我尝试在下面的代码中使用弹性搜索中的Scroll,当我这样做时,上面的错误没有生成,但每页上返回的结果是相同的,即在每个页面上显示前100条记录。

    if (searchPage != null) {
                builder.setFrom((int) searchPage.getPageStart());
                builder.setSize((int) searchPage.getPageSize());
            } else {
                builder.setFrom(0);
                builder.setSize(DEFAULT_SEARCH_PAGE_SIZE);
            }
           builder.setTypes(getType()).setScroll(new TimeValue(60000));

            SearchResponse response = builder.execute().actionGet(60000);
            SearchHits hits = response.getHits();
            if (hits.getTotalHits() > 0) {
                    for (SearchHit hit : response.getHits()) {
                        //process my hits and add them to list
                        }
                    }  
           //return the result

我知道在使用Elastic Search Scroll API时会有请求scrollId来获取我的下一个结果集,并且在使用之后,当我在我的搜索中顺序移动时,我可以在每个页面上得到正确的结果,即1,2,3, 4..etc。但是我还想直接跳到某个页面上,例如:我在第1页,想要继续第5页,然后Scroll Api将如何处理这个?

更新阻止

正如adityasinghraghav解释

  

虽然您只请求数百个(在您的情况下仅存在10个)结果,即。从10000-10010引擎盖下弹性搜索必须得到所有10010结果排序然后丢弃10000结果

我已阅读有关max_result_window参数的信息。此参数默认为10,000,这对几乎所有群集都是安全的。 高于每个搜索和每个执行搜索的分片会占用大量堆内存的值。最安全的是保留此值,但此设置是动态的,因此可以根据需要升高或降低。

如果我的总结果= 500 000且我设置了最大结果Windows大小= 100 000且页面大小= 1000。

如果我想申请第5页,那么:

  • 弹性搜索列表是否为100 000个值_i.e最大结果窗口值,对这些100 000进行排序,然后先丢弃前4 000然后获得下一个1000结果

OR

  • 在这种情况下,它是否会根据所需页面列出它将是5 000个值,将这5 000个丢弃4 000排序然后得到下一个1000个结果?

2 个答案:

答案 0 :(得分:2)

这是因为elasticsearch的最大结果窗口大小默认为10000。现在,虽然您只请求数百(在您的情况下只存在10)结果,即。从10000-10010引擎盖下弹性搜索必须得到所有10010结果排序它们然后丢弃10000结果然后给你10左,因此超过最大窗口大小的问题。 你可以做的最简单的事情是将这个默认值10000增加到一个非常高的值。您可以使用以下命令执行此操作:

curl -XPUT http://1.2.3.4:9200/index/_settings -d '{ "index" : { "max_result_window" : 1000000}}'

来到滚动api,它不返回分页结果,因此from的概念不存在,size参数以不同的方式使用。 滚动API将询问每个分片是否为其提供顶部" size"结果如果size为10并且您有5个主分片,则elasticsearch将返回50个结果。 现在,对滚动API的每个请求都会生成一个滚动ID,您需要将其传递给下一个查询以获取下一个"页面"结果而且,既然你没有这样做,你会得到相同的结果。 您应该阅读有关scroll api here的实现的更多信息。

  

但是我还想直接跳到某个页面上,例如:我在第1页,想要继续第5页

此外,由于滚动API中没有分页,因此您无法在非连续页面之间跳转。

现在您还必须记住,滚动弹性搜索会在索引时获取快照,因此如果您在滚动上下文打开期间对索引进行任何更改,这些更改将赢得&#39 ;反映在结果中。

答案 1 :(得分:0)

我不建议增加max_result_window。限制是有原因的,我认为我们应该避免篡改它。

让我们举一个例子,你运行一个通配符查询返回超过2000万个匹配(我在我的数据中看到,我们的索引有超过10亿条记录,主存储大小超过5 TB),用户要求最后一页是20万条记录。增加结果窗口将避免异常但会尝试加载堆中的所有2000万条记录,这将导致Out Of Memory崩溃整个服务器,我想这将非常糟糕。

如果滚动不是一个选项,我建议你应该使用Search After(https://www.elastic.co/guide/en/elasticsearch/reference/5.1/search-request-search-after.html)。但是Search after有其自身的局限性,应予以考虑。