Я использую PHP AWS SDK для связи с CloudSearch. В соответствии с эта почта, нумерация страниц может быть сделана либо cursor
или же start
параметры. Но когда у вас есть более 10000 хитов, вы не можете использовать start
,
Когда используешь start
Могу указать ['start' => 1000, 'size' => 100]
чтобы попасть прямо на 10-ю страницу.
Как добраться до 1000-й страницы (или любой другой случайной страницы), используя cursor
? Может быть, есть какой-нибудь способ рассчитать этот параметр?
я мог бы ЛЮБИТЬ Там будет лучший путь, но здесь идет …
Одна вещь, которую я обнаружил с помощью курсоров, заключается в том, что они возвращают одно и то же значение для дублирующих поисковых запросов при поиске по одному и тому же набору данных, поэтому не думайте о них как о сеансах. Пока ваши данные не обновляются, вы можете эффективно кэшировать аспекты своей нумерации страниц для использования несколькими пользователями.
Я придумал это решение и проверил более 75 000 записей.
1) Определите, будет ли ваш старт ниже предела 10К, если это так, используйте поиск без курсора, в противном случае при поиске за пределами 10К сначала выполните поиск с помощью initial
курсор и размер 10K и возврат _no_fields
, Это дает нам начальное смещение, а отсутствие полей ускоряет объем данных, которые мы должны использовать, в любом случае нам не нужны эти идентификаторы.
2) Определите целевое смещение и спланируйте, сколько итераций потребуется для позиционирования курсора непосредственно перед целевой страницей результатов. Затем я повторяю и кеширую результаты, используя мой запрос в качестве хеша кеша.
Для моей итерации я начал с блоков по 10 КБ, затем уменьшил размер до 5 КБ, а затем блоков по 1 КБ, когда я начал «приближаться» к целевому смещению, это означает, что при последующей разбивке на страницы используется предыдущий курсор, который немного ближе к последнему фрагменту.
например, что это может выглядеть так:
Это поможет мне добраться до блока с отметкой 32 000 смещений. Если мне нужно получить 33000, я могу использовать свои кэшированные результаты, чтобы получить курсор, который вернет предыдущую 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, но структуры запросов и поиска должны быть сопоставимы.
Других решений пока нет …