Пагинация AWS SDK CloudSearch

Я использую PHP AWS SDK для связи с CloudSearch. Согласно этому сообщению, разбивку на страницы можно выполнить с помощью cursor или start параметры. Но когда у вас более 10 000 просмотров, вы не можете использовать start.

При использовании start я могу указать ['start' => 1000, 'size' => 100], чтобы сразу перейти на 10-ю страницу.
Как перейти на 1000-ю страницу (или любую другую случайную страницу) с помощью cursor? Может быть есть какой-то способ рассчитать этот параметр?


person Justinas    schedule 22.09.2014    source источник
comment
Только что нашел это через поиск, я все еще изучаю его, но мое решение для разбивки на страницы в качестве временного исправления заключалось в том, чтобы получить блоки из 10 000 без полей, поэтому я получаю только идентификаторы документов. И затем, как только я подсчитал, что последний извлеченный блок из 10 000 функций ID для нужного мне смещения страницы, я затем объединяю массив результатов, чтобы он возвращал только меньший набор результатов. У меня также есть слой кеша, поэтому последующие вызовы уже имеют кешированные результаты курсора.   -  person Scuzzy    schedule 04.06.2015


Ответы (1)


Я бы ЛЮБОВАЛ, чтобы был лучший способ, но вот...

Одна вещь, которую я обнаружил с курсорами, заключается в том, что они возвращают одно и то же значение для повторяющихся поисковых запросов при поиске в одном и том же наборе данных, поэтому не думайте о них как о сеансах. Пока ваши данные не обновляются, вы можете эффективно кэшировать аспекты разбиения на страницы для использования несколькими пользователями.

Я придумал это решение и протестировал его с более чем 75 000 записей.

1) Определите, будет ли ваш старт меньше 10 КБ, если это так, используйте поиск без курсора, в противном случае при поиске за пределами 10 КБ сначала выполните поиск с курсором initial и размером 10 КБ. и вернуть _no_fields. Это дает наше начальное смещение, а отсутствие полей ускоряет объем данных, которые мы должны потреблять, нам все равно не нужны эти идентификаторы.

2) Выясните целевое смещение и спланируйте, сколько итераций потребуется, чтобы установить курсор непосредственно перед целевой страницей результатов. Затем я повторяю и кеширую результаты, используя свой запрос в качестве хэша кеша.

Для моей итерации я начал с блоков 10 КБ, затем уменьшил размер до 5 КБ, а затем блоков 1 КБ, поскольку я начинаю приближаться к целевому смещению, это означает, что последующая разбивка на страницы использует предыдущий курсор, который немного ближе к последнему фрагменту.

например, как это может выглядеть:

  • Получить 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, но структуры запроса и поиска должны быть сопоставимы.

person Scuzzy    schedule 05.06.2015
comment
Я также только что обнаружил, что вместо кэширования результатов операций поиска достаточно просто кэшировать курсор из ответа для последующих итераций. - person Scuzzy; 06.06.2015