通过scrollId在不同的请求中获取elasticsearch数据

时间:2017-12-11 21:28:55

标签: java elasticsearch scroll pagination

我正在使用带有Java API的elasticsearch来使用滚动方法获取数据,因为我有很多数据,我试图通过scrollId使用多个和后续请求对数据进行分页。

示例:

而不是: POST http://localhost:8080/country

返回:

[
  {
    scrollId: abc,
    data: [{country: brazil}, {country: argentina}]
  },
  {
    scrollId: def,
    data: [{country: france}, {country: germany}]
  }
]

我想用: POST http://localhost:8080/country?paged=true

响应中的第一个scrollId:

{
  nextScrollId: abc
}

然后我可以在nextScrollId存在时执行一些请求:

POST http://localhost:8080/country?scrollId=abc

返回:

{
  nextScrollId: def,
  data: [{country: brazil}, {country: argentina}] //data from the "abc" scrollId
}

然后: POST http://.../data?scrollId=def

返回:

{
  nextScrollId: "", //no more results in this case
  data: [{country: france}, {country: germany}] //data from the "def" scrollId
}

目前我正在使用这段代码:

SearchResponse scrollResponse = elastic.getDataFromElasticSearch();

boolean hasNext = true;
String scrollId = request.getScrollId();
CountryResponse countryResponse = new CountryResponse();

do {
  if (scrollResponse.getScrollId().equals(scrollId)) {

    scrollResponse = client.prepareSearchScroll(scrollId)
                      .setScroll(TimeValue.timeValueMinutes(1))
                      .execute()
                      .actionGet();

    //here i get the data from scrollResponse.getHits().getHits() 
    //and format it to that nextScrollId | data structure
    countryResponse.addCountriesFromElasticSearchResponse(scrollResponse);
  } else {
    hasNext = false;
  }

} while (hasNext == true);

countryResponse.setNextScrollId(scrollResponse.getScrollId());
return countryResponse;

有了这个,我可以正确地返回下一个scrollId。

这里的事情是,每当我尝试使用nextScrollId准备滚动数据时,我在响应中没有数据。

这可能吗?

1 个答案:

答案 0 :(得分:0)

滚动API旨在以单向方式由单个线程使用。 在内部,它创建一个光标,只能通过搜索结果向前移动,每次调用都会改变光标状态,并且不可能为同一个光标重复相同的调用两次(滚动)。

在你的情况下,问题在于理解滚动如何在内部工作 - 第一页只能通过第一次调用获得:

enter image description here

为了实现带有移位迭代器的自定义逻辑(如下所述)

enter image description here

您必须在第一次请求时缓存搜索结果,并使用"您自己的迭代器"将它们保存(缓存)在您的服务器上转移到原始的弹性迭代器。还要记住:

  • 两次调用一个迭代器是不可能的
  • 迭代器可能会过期
  • 如何扩展您的服务?如果您的服务节点很少,则必须将同一会话的请求路由到同一节点(粘性会话)。 Elastic拥有自己的路由服务,并且开箱即用。

所以我强烈建议您按照文档中描述的方式使用elastic scroll API