3

我正在使用 PHP AWS SDK 与 CloudSearch 进行通信。根据这篇文章,分页可以使用cursorstart参数来完成。但是当你有超过 10,000 次点击时,你就不能使用start.

使用时start,我可以指定['start' => 1000, 'size' => 100]直接进入第 10 页。
如何使用第 1000 页(或任何其他随机页面)cursor?也许有什么方法可以计算这个参数?

4

1 回答 1

1

我希望更好的方法,但这里有......

我发现游标的一件事是,在同一数据集上搜索时,它们会为重复的搜索请求返回相同的值,因此不要将它们视为会话。虽然您的数据没有更新,但您可以有效地缓存分页的各个方面以供多个用户使用。

我想出了这个解决方案,并用 75,000 多条记录对其进行了测试。

1)确定你的开始是否会低于 10k 限制,如果是,则使用非光标搜索,否则当超过 10K 时,首先使用initial光标和大小为 10K 的搜索并返回_no_fields。这给出了我们的起始偏移量,没有字段加快了我们必须消耗的数据量,无论如何我们都不需要这些 ID

2)计算出您的目标偏移量,并计划将光标定位在目标结果页面之前需要多少次迭代。然后我使用我的请求作为缓存哈希来迭代和缓存结果。

对于我的迭代,我从 10K 块开始,然后随着我开始“更接近”目标偏移量,将大小减小到 5k,然后 1k 块,这意味着后续分页使用的是更接近最后一个块的前一个光标。

例如,这可能看起来像:

  • 获取 10000 条记录(初始光标)
  • 获取 5000 条记录
  • 获取 5000 条记录
  • 获取 5000 条记录
  • 获取 5000 条记录
  • 获取 1000 条记录
  • 获取 1000 条记录

这将帮助我到达 32,000 偏移标记附近的块。如果我需要达到 33,000,我可以使用我的缓存结果来获取将返回前一个 1000 的游标并从该偏移量重新开始......

  • 获取 10000 条记录(缓存)
  • 获取 5000 条记录(缓存)
  • 获取 5000 条记录(缓存)
  • 获取 5000 条记录(缓存)
  • 获取 5000 条记录(缓存)
  • 获取 1000 条记录(缓存)
  • 获取 1000 条记录(缓存)
  • 获取 1000 条记录(使用缓存游标工作)

3)现在我们位于目标结果偏移量的“附近”,您可以开始将页面大小指定为目标之前的位置。然后您执行最终搜索以获取实际的结果页面。

4)如果您从索引中添加或删除文档,您将需要一种机制来使以前的缓存结果无效。我通过存储索引上次更新时间的时间戳并将其用作缓存键生成例程的一部分来完成此操作。

重要的是缓存方面,您应该构建一个使用请求数组作为缓存哈希键的缓存机制,以便可以轻松创建/引用它。

对于非种子缓存,这种方法很,但是如果您可以预热缓存并且仅在索引文档发生更改时将其过期(然后再次预热),您的用户将无法判断。

这个代码想法适用于每页 20 个项目,我很想研究这个,看看我如何能更聪明/更高效地编写它,但是这个概念就在那里......

// Build $request here and set $request['start'] to be the offset you want to reach

// Craft getCache() and setCache() functions or methods for cache handling.

// have $cloudSearchClient as your client

if(isset($request['start']) === true and $request['start'] >= 10000)
{
  $originalRequest = $request;
  $cursorSeekTarget = $request['start'];
  $cursorSeekAmount = 10000; // first one should be 10K since there's no pagination under this
  $cursorSeekOffset = 0;
  $request['return'] = '_no_fields';
  $request['cursor'] = 'initial';
  unset($request['start'],$request['facet']);
  // While there is outstanding work to be done...
  while( $cursorSeekAmount > 0 )
  {
    $request['size'] = $cursorSeekAmount;
    // first hit the local cache
    if(empty($result = getCache($request)) === true)
    {
      $result = $cloudSearchClient->Search($request);
      // store the results in the cache
      setCache($request,$result);
    }
    if(empty($result) === false and empty( $hits = $result->get('hits') ) === false and empty( $hits['hit'] ) === false )
    {
      // prepare the next request with the cursor
      $request['cursor'] = $hits['cursor'];
    }
    $cursorSeekOffset = $cursorSeekOffset + $request['size'];
    if($cursorSeekOffset >= $cursorSeekTarget)
    {
      $cursorSeekAmount = 0; // Finished, no more work
    }
    // the first request needs to get 10k, but after than only get 5K
    elseif($cursorSeekAmount >= 10000 and ($cursorSeekTarget - $cursorSeekOffset) > 5000)
    {
      $cursorSeekAmount = 5000;
    }
    elseif(($cursorSeekOffset + $cursorSeekAmount) > $cursorSeekTarget)
    {
      $cursorSeekAmount = $cursorSeekTarget - $cursorSeekOffset;
      // if we still need to seek more than 5K records, limit it back again to 5K
      if($cursorSeekAmount > 5000)
      {
        $cursorSeekAmount = 5000;
      }
      // if we still need to seek more than 1K records, limit it back again to 1K
      elseif($cursorSeekAmount > 1000)
      {
        $cursorSeekAmount = 1000;
      }
    }
  }
  // Restore aspects of the original request (the actual 20 items)
  $request['size'] = 20;
  $request['facet'] = $originalRequest['facet'];
  unset($request['return']); // get the default returns
  if(empty($result = getCache($request)) === true)
  {
    $result = $cloudSearchClient->Search($request);
    setCache($request,$result);
  }
}
else
{
  // No cursor required
  $result = $cloudSearchClient->Search( $request );
}

请注意,这是使用自定义 AWS 客户端而不是官方 SDK 类完成的,但请求和搜索结构应该具有可比性。

于 2015-06-05T12:57:52.490 回答