Пагинация — это важная функция для любой поисковой системы, позволяющая пользователям эффективно перемещаться по большим наборам результатов. Manticore Search предлагает несколько мощных методов пагинации, каждый из которых имеет свои преимущества и ограничения. Эта статья исследует различные варианты пагинации, доступные в Manticore Search, с практическими примерами SQL, чтобы помочь вам реализовать лучшее решение для вашего случая использования.
Содержание
- Введение в пагинацию
- Настройка тестовой среды
- Традиционная пагинация на основе смещения
- Окно набора результатов и max_matches
- Пагинация на основе прокрутки
- Пагинация через HTTP JSON
- Лучшие практики сортировки для пагинации
- Ограничения и соображения по производительности
- Фасетный поиск с пагинацией
- Практические случаи использования
- Заключение
Введение в пагинацию
При работе с большими наборами данных возвращение всех совпадающих результатов сразу является непрактичным. Пагинация решает эту проблему, разделяя результаты на управляемые части или "страницы". Manticore Search предоставляет несколько подходов к пагинации, чтобы учесть различные случаи использования, от простой навигации по списку до интерфейсов с бесконечной прокруткой.
В этой статье мы рассмотрим три основных метода пагинации:
- Традиционная пагинация на основе смещения ( Раздел 3 )
- Глубокая пагинация с max_matches ( Раздел 4 )
- Пагинация на основе прокрутки для эффективной навигации по большим наборам результатов ( Раздел 5 )
Мы также обсудим их реализацию как через SQL, так и через интерфейсы HTTP JSON, соображения по производительности и практические применения.
Настройка тестовой среды
Перед тем как углубиться в примеры пагинации, давайте создадим тестовую среду с образцовыми данными, используя инструмент Manticore Load. Этот инструмент упрощает генерацию и загрузку тестовых данных для бенчмаркинга и экспериментов:
# Create a products table and populate it with 10,000 records containing "smartphone" in the title
manticore-load --quiet \
--batch-size=1000 \
--threads=4 \
--total=10000 \
--drop \
--init="CREATE TABLE products(title text, description text, price int, category string, rating float, stock int)" \
--load="INSERT INTO products(id, title, description, price, category, rating, stock) VALUES(<increment>, '<text/3/5> smartphone', '<text/20/50>', <int/10/1000>, '<string/5/10>', <float/1/5>, <int/0/100>)"
Вывод:
С этой тестовой средой мы теперь можем исследовать различные методы пагинации.
Традиционная пагинация на основе смещения
Самый простой метод пагинации в Manticore Search использует оператор LIMIT с параметрами смещения и количества. Этот подход знаком любому, кто работал с SQL базами данных.
Основной синтаксис
SELECT ... FROM ... [LIMIT [offset,] row_count]
SELECT ... FROM ... [LIMIT row_count][ OFFSET offset]
Примеры
-- Return the first 5 results (page 1)
SELECT id, title, price, weight() FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5;
Вывод:
+------+----------------------------------------------+-------+----------+
| id | title | price | weight() |
+------+----------------------------------------------+-------+----------+
| 1179 | Weak spoke? fall. smartphone | 10 | 1272 |
| 1388 | 3; her day of. smartphone | 10 | 1272 |
| 1636 | Positively bad winter clean. smartphone | 10 | 1272 |
| 5628 | Foolish from went heard low. smartphone | 10 | 1272 |
| 8561 | Left sent. Infrequently, try lay. smartphone | 10 | 1272 |
+------+----------------------------------------------+-------+----------+
-- Return results 6-10 (page 2)
SELECT id, title, price, weight() FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5, 5;
Вывод:
+------+----------------------------------------------+-------+----------+
| id | title | price | weight() |
+------+----------------------------------------------+-------+----------+
| 246 | Soft technically took. smartphone | 11 | 1272 |
| 1105 | Dirty up are! temporarily called. smartphone | 11 | 1272 |
| 3293 | Instantly thick ran that hurt. smartphone | 11 | 1272 |
| 3736 | Work her wrong locally. smartphone | 11 | 1272 |
| 6978 | Stale loud passively sweet clean. smartphone | 11 | 1272 |
+------+----------------------------------------------+-------+----------+
-- Alternative syntax with separate LIMIT and OFFSET
SELECT id, title, price, weight() FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5 OFFSET 10;
-- Results 11-15 (page 3)
Вывод:
+------+----------------------------------------+-------+----------+
| id | title | price | weight() |
+------+----------------------------------------+-------+----------+
| 7318 | Her spent at. smartphone | 11 | 1272 |
| 8436 | His? felt work. Angry fast. smartphone | 11 | 1272 |
| 9699 | Feel spend funny. smartphone | 11 | 1272 |
| 2326 | Quietly wet drew found. smartphone | 12 | 1272 |
| 4171 | Set perhaps new send soon. smartphone | 12 | 1272 |
+------+----------------------------------------+-------+----------+
Этот метод прост в реализации и хорошо работает для навигации по начальным страницам результатов. Однако он становится менее эффективным для глубокой пагинации из-за того, как Manticore обрабатывает запросы внутренне. Для получения подробной информации об этих ограничениях см. Раздел 8: Ограничения и соображения по производительности .
Окно набора результатов и max_matches
По умолчанию Manticore Search ограничивает количество совпадений, которые могут быть возвращены, до 1000. Если вы попытаетесь пагинировать за пределами этого лимита, запрос приведет к ошибке. Это ограничение можно настроить с помощью параметра max_matches.
Понимание max_matches
Параметр max_matches контролирует, сколько совпадений Manticore будет хранить в ОЗУ во время поиска. Он предназначен для ограничения использования памяти на запрос. Значение по умолчанию — 1000, что достаточно для большинства распространенных сценариев поиска, но вы можете увеличить его, когда вам нужно получить доступ к более глубоким страницам результатов.
-- Increase max_matches to allow deeper pagination (results 1001-1005)
SELECT id, title, price FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 1000, 5
OPTION max_matches=1500;
Вывод:
+------+-----------------------------------------+-------+
| id | title | price |
+------+-----------------------------------------+-------+
| 3550 | Open sold being late wide. smartphone | 111 |
| 4896 | Grew. Wrote as hungry. smartphone | 111 |
| 647 | Went seen had. smartphone | 112 |
| 883 | Hold lose; have thought. smartphone | 112 |
| 1774 | Get! began sick. Gone, wild. smartphone | 112 |
+------+-----------------------------------------+-------+
-- For very deep pagination (results 5000-5005)
SELECT id, title, price FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5000, 5
OPTION max_matches=5500;
Вывод:
+------+------------------------------------------------+-------+
| id | title | price |
+------+------------------------------------------------+-------+
| 4894 | Subtly? inside for spend evening. smartphone | 507 |
| 5203 | Bad; artistically from yearly. smartphone | 507 |
| 7446 | Empty probably clever! universally. smartphone | 507 |
| 8053 | In! rich daily irregularly. smartphone | 507 |
| 8055 | Short cold fall; keep physically. smartphone | 507 |
+------+------------------------------------------------+-------+
Имейте в виду, что увеличение max_matches связано с затратами на память. Каждое совпадение потребляет память, поэтому установка этого значения слишком высоким может повлиять на производительность сервера, особенно при высокой нагрузке. Для альтернативного подхода к глубокой пагинации, который более эффективно использует память, см.
Пагинация на основе прокрутки
.
Пагинация на основе прокрутки
Пагинация на основе прокрутки предоставляет эффективный способ навигации по большим наборам результатов. В отличие от традиционной пагинации на основе смещения, она использует токен для отслеживания текущей позиции в наборе результатов, что помогает эффективно перемещаться по последовательным страницам результатов.
Как это работает
- Выполните начальный запрос с критериями сортировки (должен включать
idв ORDER BY) - Получите токен прокрутки, который инкапсулирует текущую позицию
- Используйте этот токен в последующих запросах, чтобы получить следующую партию результатов
Примеры
-- Initial query with sorting criteria (must include id in ORDER BY)
SELECT id, title, price, weight() FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5; SHOW SCROLL\G
Вывод:
+------+----------------------------------------------+-------+----------+
| id | title | price | weight() |
+------+----------------------------------------------+-------+----------+
| 1179 | Weak spoke? fall. smartphone | 10 | 1272 |
| 1388 | 3; her day of. smartphone | 10 | 1272 |
| 1636 | Positively bad winter clean. smartphone | 10 | 1272 |
| 5628 | Foolish from went heard low. smartphone | 10 | 1272 |
| 8561 | Left sent. Infrequently, try lay. smartphone | 10 | 1272 |
+------+----------------------------------------------+-------+----------+
*************************** 1. row ***************************
scroll_token: eyJvcmRlcl9ieV9zdHIiOiJ3ZWlnaHQoKSBERVNDLCBwcmljZSBBU0MsIGlkIEFTQyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI3MiwidHlwZSI6ImludCJ9LHsiYXR0ciI6InByaWNlIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjoxMCwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjo4NTYxLCJ0eXBlIjoiaW50In1dfQ==
-- Subsequent paginated query using the scroll token
SELECT id, title, price, weight() FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5
OPTION scroll='eyJvcmRlcl9ieV9zdHIiOiJ3ZWlnaHQoKSBERVNDLCBwcmljZSBBU0MsIGlkIEFTQyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI3MywidHlwZSI6ImludCJ9LHsiYXR0ciI6InByaWNlIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjo1MiwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjo0NCwidHlwZSI6ImludCJ9XX0=';
Вывод:
+------+----------------------------------------------+-------+----------+
| id | title | price | weight() |
+------+----------------------------------------------+-------+----------+
| 1179 | Weak spoke? fall. smartphone | 10 | 1272 |
| 1388 | 3; her day of. smartphone | 10 | 1272 |
| 1636 | Positively bad winter clean. smartphone | 10 | 1272 |
| 5628 | Foolish from went heard low. smartphone | 10 | 1272 |
| 8561 | Left sent. Infrequently, try lay. smartphone | 10 | 1272 |
+------+----------------------------------------------+-------+----------+
Пагинация на основе прокрутки особенно хорошо подходит для реализации функциональности "Загрузить больше" или бесконечной прокрутки в веб-приложениях. Для полного примера реализации см. Практические случаи использования .
Пагинация через HTTP JSON
В дополнение к SQL, Manticore Search предлагает пагинацию через HTTP JSON. Это особенно полезно для веб-приложений или архитектур микросервисов. Как традиционная пагинация на основе смещения, так и пагинация на основе прокрутки поддерживаются через JSON API.
Традиционная пагинация на основе смещения через HTTP JSON
HTTP JSON API использует параметры offset и limit для управления пагинацией. Это эквивалентно синтаксису SQL LIMIT offset, count.
Основной синтаксис
{
"table": "table_name",
"query": { "match": { ... } },
"limit": number_of_results,
"offset": starting_position
}
Пример
# First page (results 1-5)
curl -s 0:9308/search -d '{
"table": "products",
"query": { "match": { "*": "smartphone" } },
"limit": 5,
"offset": 0,
"sort": [
{ "_score": "desc" },
{ "price": "asc" },
{ "id": "asc" }
]
}'|jq .
Вывод:
{
"took": 0,
"timed_out": false,
"hits": {
"total": 10000,
"total_relation": "eq",
"hits": [
{
"_id": 1179,
"_score": 1272,
"_source": {
"title": "Weak spoke? fall. smartphone",
"description": "Made down never long 3 angry are went asked closed! cold historically got take can to commonly emotionally; socially asked get tame frequently think nowhere? carefully? scientifically small.",
"price": 10,
"category": "hkadwpwwk",
"rating": 2.300000,
"stock": 63
}
},
// ... more results ...
]
}
}
# Second page (results 6-10)
curl -s 0:9308/search -d '{
"table": "products",
"query": { "match": { "*": "smartphone" } },
"limit": 5,
"offset": 5,
"sort": [
{ "_score": "desc" },
{ "price": "asc" },
{ "id": "asc" }
]
}' | jq .
Вывод:
{
"took": 0,
"timed_out": false,
"hits": {
"total": 10000,
"total_relation": "eq",
"hits": [
{
"_id": 246,
"_score": 1272,
"_source": {
"title": "Soft technically took. smartphone",
"description": "This sometimes empty short normally! been send. Locally kind! quickly might infrequently culturally softly became tried quietly good gradually; inside dead loud.",
"price": 11,
"category": "wuiymrjdp",
"rating": 1.600000,
"stock": 87
}
},
// ... more results ...
]
}
}
Альтернативный синтаксис
The HTTP JSON API также поддерживает альтернативный синтаксис, используя from и size вместо offset и limit:
{
"table": "table_name",
"query": { "match": { ... } },
"size": number_of_results,
"from": starting_position
}
Это эквивалентно предыдущему формату, но соответствует соглашению Elasticsearch, которое может быть более знакомо некоторым пользователям.
Пагинация на основе прокрутки через HTTP JSON
HTTP JSON API также поддерживает пагинацию на основе прокрутки для более эффективной глубокой пагинации. Это требует настройки правильных критериев сортировки и использования токена прокрутки.
Начальный запрос
curl -s 0:9308/search -d '{
"table": "products",
"query": { "match": { "*": "smartphone" } },
"limit": 5,
"track_scores": true,
"sort": [
{ "_score": "desc" },
{ "id": "asc" }
],
"options": {
"scroll": true
}
}' | jq .
Вывод:
{
"took": 0,
"timed_out": false,
"hits": {
"total": 10000,
"total_relation": "eq",
"hits": [
{
"_id": 1,
"_score": 1272,
"_source": {
"title": "Incorrectly heavy soft. smartphone",
"description": "Carefully late sit; put draw afraid; gave hardly been vaguely 1000 this at understood gave always east fake, dull internationally sent. At cold; hot.",
"price": 540,
"category": "ogqejby",
"rating": 2.800000,
"stock": 52
}
},
// ... more results ...
]
},
"scroll": "eyJvcmRlcl9ieV9zdHIiOiJAd2VpZ2h0IGRlc2MsIGlkIGFzYyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI3MiwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjo1LCJ0eXBlIjoiaW50In1dfQ=="
}
Обратите внимание на значение scroll в ответе, которое является закодированным в base64 токеном, представляющим ваше текущее положение в наборе результатов.
Последующие запросы
curl -s 0:9308/search -d '{
"table": "products",
"query": { "match": { "*": "smartphone" } },
"limit": 5,
"track_scores": true,
"options": {
"scroll": "eyJvcmRlcl9ieV9zdHIiOiJAd2VpZ2h0IGRlc2MsIGlkIGFzYyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI3MiwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjo1LCJ0eXBlIjoiaW50In1dfQ=="
}
}' | jq .
Вывод:
{
"took": 0,
"timed_out": false,
"hits": {
"total": 9995,
"total_relation": "eq",
"hits": [
{
"_id": 6,
"_score": 1272,
"_source": {
"title": "Negatively! it become. smartphone",
"description": "Be quiet cold nightly poor hourly had thin got dry, informally work, 100 50 needed specifically serious do bring below began! rich loud.",
"price": 602,
"category": "hjpwt",
"rating": 2.500000,
"stock": 47
}
},
// ... more results ...
]
},
"scroll": "eyJvcmRlcl9ieV9zdHIiOiJAd2VpZ2h0IGRlc2MsIGlkIGFzYyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI3MiwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjoxMCwidHlwZSI6ImludCJ9XX0="
}
Каждый ответ включает новый токен прокрутки для следующей страницы, что позволяет продолжать пагинацию.
Лучшие практики для пагинации HTTP JSON
- Включите критерии сортировки: Для предсказуемых результатов пагинации всегда включайте явную сортировку, например:
"sort": [ { "_score": "desc" }, { "price": "asc" }, { "id": "asc" } ] - Правильно обрабатывайте токены прокрутки: Сохраняйте токен прокрутки из каждого ответа и используйте его для следующего запроса.
- Используйте соответствующую обработку ошибок: Проверяйте наличие ответов с ошибками, особенно при глубокой пагинации.
- Учитывайте размер ответа: Контролируйте объем возвращаемых данных, выбирая только необходимые поля с помощью параметра
_source:"_source": ["title", "price", "rating"] - Мониторьте производительность: Для очень больших наборов результатов следите за производительностью сервера и рассмотрите возможность использования пагинации на основе прокрутки.
Методы пагинации HTTP JSON следуют тем же принципам, что и их SQL-аналоги (описанные в Разделах 3 и 5 ), но с синтаксисом JSON. Это делает их идеальными для современных веб-приложений и REST API.
Лучшие практики сортировки для пагинации
Правильная сортировка имеет решающее значение для эффективной пагинации, особенно для пагинации на основе прокрутки. Вот ключевые моменты:
1. Включите уникальный идентификатор
Для последовательных результатов пагинации всегда включайте уникальный идентификатор (обычно поле id) в ваш оператор ORDER BY. Это гарантирует, что даже если несколько документов имеют одинаковое значение для других критериев сортировки, пагинация все равно будет давать последовательные результаты.
-- Good: Includes id as the tie-breaker
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY weight() DESC, price ASC, id ASC;
-- Bad: No unique identifier, may lead to inconsistent pagination
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY price ASC;
2. Включите weight() для полнотекстового поиска
При использовании MATCH() в вашем запросе всегда включайте weight() в ваши критерии сортировки, чтобы гарантировать, что наиболее релевантные результаты появляются первыми:
-- Good: Includes weight() for relevance sorting
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY weight() DESC, price ASC, id ASC;
-- Less optimal: Missing relevance sorting
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY price ASC, id ASC;
3. Поддерживайте последовательность порядка сортировки
При использовании традиционной пагинации на основе смещения всегда поддерживайте один и тот же порядок сортировки во всех пагинированных запросах. Изменение порядка сортировки между страницами может привести к пропущенным или дублированным результатам.
-- First page (correct)
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY weight() DESC, price ASC, id ASC LIMIT 10;
-- Second page (correct - same sort order)
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY weight() DESC, price ASC, id ASC LIMIT 10, 10;
-- Second page (incorrect - different sort order)
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY rating DESC, id ASC LIMIT 10, 10;
4. Используйте детерминированную сортировку
Для пагинации на основе прокрутки всегда используйте детерминированные критерии сортировки. Недетерминированные функции, такие как RAND(), следует избегать, так как они будут давать непоследовательные результаты между запросами.
-- Good: Deterministic sorting
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY weight() DESC, price ASC, id ASC;
-- Bad: Non-deterministic sorting, will break scroll pagination
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY RAND();
5. Направление сортировки с ID
При использовании поля id в качестве критерия для разрешения споров в сортировке вы можете использовать либо порядок ASC, либо DESC, но он должен применяться последовательно:
-- These are both valid for scroll pagination
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY weight() DESC, price ASC, id ASC;
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY weight() DESC, price ASC, id DESC;
6. Оптимизация производительности сортировки
Для лучшей производительности сортировки рассмотрите возможность использования параметра sort_method:
-- For pre-sorted data (e.g., by id)
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY id ASC
LIMIT 5 OPTION sort_method=kbuffer;
-- For other sorting criteria
SELECT * FROM products WHERE MATCH('smartphone') ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5 OPTION sort_method=pq;
Выбор подхода к сортировке может значительно повлиять на производительность и последовательность пагинации. Например, детерминированная сортировка имеет решающее значение для пагинации на основе прокрутки, в то время как включение уникального идентификатора критично для последовательных результатов во всех методах пагинации. Для получения дополнительной информации о том, как сортировка влияет на производительность, см. Ограничения и соображения по производительности .
Ограничения и соображения по производительности
Понимание ограничений различных методов пагинации поможет вам выбрать правильный подход для вашего конкретного случая использования.
Ограничения пагинации на основе смещения
- Производительность ухудшается с увеличением смещения: По мере увеличения значения смещения производительность запроса снижается. Это связано с тем, что Manticore все равно должен обработать все записи до значения смещения, прежде чем вернуть запрашиваемую страницу.
- Ограничение max_matches: По умолчанию вы можете пагинировать только через первые 1000 результатов. Чтобы выйти за пределы этого, вы должны увеличить
max_matches, что увеличивает использование памяти. - Использование памяти: Более крупные значения
max_matchesтребуют больше ОЗУ на запрос, что может повлиять на производительность сервера при высокой нагрузке. - Последовательные результаты не гарантированы: Если документы добавляются или удаляются между запросами страниц, вы можете увидеть дубликаты или пропустить результаты.
Для сценариев глубокой пагинации или реализации функции "Загрузить еще" рассмотрите возможность использования Пагинации на основе прокрутки , как описано в Разделе 5 .
Ограничения пагинации на основе прокрутки
- Требуется ID в критериях сортировки: Вы должны включить поле
idв ваш оператор ORDER BY, что может не всегда соответствовать вашей желаемой логике сортировки. - Управление токенами: Вам необходимо хранить и управлять токенами прокрутки между запросами, что добавляет сложности в ваше приложение.
- Нет гарантии последовательности: Пагинация на основе прокрутки не гарантирует согласованности в определенный момент времени. Если документы добавляются, удаляются или изменяются между запросами, результаты могут все равно измениться.
- Нет случайного доступа: В отличие от пагинации на основе смещения, вы не можете перейти непосредственно на конкретную страницу; вам нужно перемещаться последовательно.
Фасетный поиск с пагинацией
Фасетный поиск позволяет пользователям фильтровать и навигировать по результатам поиска, используя несколько измерений. В сочетании с пагинацией важно понимать, как пагинация влияет на результаты фасетов.
-- Faceted search with pagination (first page)
SELECT id, title, price, weight()
FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 0, 5
FACET category ORDER BY COUNT(*) DESC;
Вывод:
+------+----------------------------------------------+-------+----------+
| id | title | price | weight() |
+------+----------------------------------------------+-------+----------+
| 1179 | Weak spoke? fall. smartphone | 10 | 1272 |
| 1388 | 3; her day of. smartphone | 10 | 1272 |
| 1636 | Positively bad winter clean. smartphone | 10 | 1272 |
| 5628 | Foolish from went heard low. smartphone | 10 | 1272 |
| 8561 | Left sent. Infrequently, try lay. smartphone | 10 | 1272 |
+------+----------------------------------------------+-------+----------+
+-----------+----------+
| category | count(*) |
+-----------+----------+
| ogqejby | 1 |
| unmfujgqr | 1 |
| ttefm | 1 |
| hceihdy | 1 |
| sicjr | 1 |
| hjpwt | 1 |
| tvfqyj | 1 |
| mvdjhbexo | 1 |
| scayuo | 1 |
| esmlh | 1 |
| fvbhplj | 1 |
| lcphmiqmv | 1 |
| lnjfhb | 1 |
| qexfdulub | 1 |
| tbswa | 1 |
| eekarf | 1 |
| airjuod | 1 |
| ozkbuvgj | 1 |
| yafbhr | 1 |
| duccr | 1 |
+-----------+----------+
-- Faceted search with pagination (second page)
SELECT id, title, price, weight()
FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5, 5
FACET category ORDER BY COUNT(*) DESC;
Вывод:
+------+-----------------------------------------------------------+-------+----------+
| id | title | price | weight() |
+------+-----------------------------------------------------------+-------+----------+
| 246 | Soft technically took. smartphone | 11 | 1272 |
| 1105 | Dirty up are! temporarily called. smartphone | 11 | 1272 |
| 3293 | Instantly thick ran that hurt. smartphone | 11 | 1272 |
| 3736 | Work her wrong locally. smartphone | 11 | 1272 |
| 6978 | Stale loud passively sweet clean. smartphone | 11 | 1272 |
+------+-----------------------------------------------------------+-------+----------+
+-----------+----------+
| category | count(*) |
+-----------+----------+
| ogqejby | 1 |
| unmfujgqr | 1 |
| ttefm | 1 |
| hceihdy | 1 |
| sicjr | 1 |
| hjpwt | 1 |
| tvfqyj | 1 |
| mvdjhbexo | 1 |
| scayuo | 1 |
| esmlh | 1 |
| fvbhplj | 1 |
| lcphmiqmv | 1 |
| lnjfhb | 1 |
| qexfdulub | 1 |
| tbswa | 1 |
| eekarf | 1 |
| airjuod | 1 |
| ozkbuvgj | 1 |
| yafbhr | 1 |
| duccr | 1 |
+-----------+----------+
Важное примечание: Результаты фасетов рассчитываются на основе всего набора результатов, соответствующего запросу, а не только на основе пагинированной части. Это означает, что независимо от того, какую страницу вы просматриваете, количество фасетов представляет распределение по всем соответствующим документам. Условие LIMIT влияет только на то, какие документы возвращаются в основном наборе результатов, а не на расчеты фасетов. Как видно из приведенных выше примеров, результаты фасетов идентичны для обеих страниц, что подтверждает, что они рассчитываются на основе всего набора результатов.
Пагинация в результатах фасетов
В дополнение к пагинации основных результатов поиска, Manticore Search также позволяет пагинировать сами результаты фасетов. Это особенно полезно при работе с большим количеством значений фасетов, когда отображение всех из них может быть непрактичным.
Вы можете использовать условие LIMIT в операторе FACET, чтобы контролировать количество возвращаемых значений фасетов.
-- Get only the first 5 categories ordered by count
SELECT id, title FROM products
WHERE MATCH('smartphone')
LIMIT 3
FACET category ORDER BY COUNT(*) DESC, category asc LIMIT 0,5;
Вывод:
+------+---------------------------------------------+
| id | title |
+------+---------------------------------------------+
| 1 | Incorrectly heavy soft. smartphone |
| 2 | Know of make afraid foolish. smartphone |
| 3 | Poor spring evening drove young. smartphone |
+------+---------------------------------------------+
+------------+----------+
| category | count(*) |
+------------+----------+
| aaaabzwfzn | 1 |
| aabswb | 1 |
| aacla | 1 |
| aaejmtubv | 1 |
| aaethytj | 1 |
+------------+----------+
Вы можете предоставить разные параметры пагинации для разных фасетов в одном запросе:
-- Multiple facets with different pagination parameters
SELECT id, title FROM products
WHERE MATCH('smartphone')
LIMIT 3
FACET category ORDER BY COUNT(*) DESC, category asc LIMIT 0,5
FACET category ORDER BY category ASC LIMIT 3,5
FACET price ORDER BY FACET() ASC LIMIT 5;
Вывод:
+------+---------------------------------------------+
| id | title |
+------+---------------------------------------------+
| 1 | Incorrectly heavy soft. smartphone |
| 2 | Know of make afraid foolish. smartphone |
| 3 | Poor spring evening drove young. smartphone |
+------+---------------------------------------------+
+------------+----------+
| category | count(*) |
+------------+----------+
| aaaabzwfzn | 1 |
| aabswb | 1 |
| aacla | 1 |
| aaejmtubv | 1 |
| aaethytj | 1 |
+------------+----------+
+------------+----------+
| category | count(*) |
+------------+----------+
| aaejmtubv | 1 |
| aaethytj | 1 |
| aaktjgaa | 1 |
| aalfwcvwil | 1 |
| aaqmumofe | 1 |
+------------+----------+
+-------+----------+
| price | count(*) |
+-------+----------+
| 10 | 5 |
| 11 | 8 |
| 12 | 10 |
| 13 | 9 |
| 14 | 8 |
+-------+----------+
Этот пример демонстрирует несколько техник пагинации фасетов:
- Первый фасет возвращает 5 лучших категорий по количеству (смещение 0, лимит 5)
- Второй фасет возвращает категории в алфавитном порядке, пропуская первые 3 (смещение 3, лимит 5)
- Третий фасет возвращает первые 5 ценовых точек, упорядоченных по возрастанию значения
Пагинация фасетов особенно полезна для:
- Обработки большого количества значений фасетов (например, тысяч категорий продуктов)
- Реализации функции "Показать больше" для значений фасетов
- Создания динамических интерфейсов фильтрации с наиболее популярными фильтрами, отображаемыми первыми
- Оптимизации производительности за счет ограничения количества возвращаемых значений фасетов
Примечание: В отличие от пагинации основных результатов, которая имеет последствия для производительности при глубоких смещениях, пагинация фасетов, как правило, эффективна даже с большими смещениями, поскольку расчеты фасетов происходят после этапа сопоставления документов.
Пагинация фасетов через HTTP JSON
Пагинация фасетов также доступна при использовании интерфейса HTTP JSON. Вы можете ограничить количество возвращаемых значений фасетов, используя параметр size в спецификации агрегации:
{
"table": "products",
"query": { "match": { "*": "smartphone" } },
"limit": 3,
"aggs": {
"category_counts": {
"terms": {
"field": "category",
"size": 5
}
}
}
}
Этот пример ограничивает результаты фасета категории 5 лучшими значениями.
Важно: В отличие от SQL фасетов, интерфейс HTTP JSON в настоящее время поддерживает только ограничение количества значений фасетов с помощью параметра size. Он не поддерживает параметр OFFSET для пагинации внутри фасетов. Вы можете только указать, сколько результатов вернуть, а не какие пропустить.
Для получения дополнительной информации о пагинации фасетов через HTTP JSON смотрите документацию Manticore Search .
Практические случаи использования
Пагинация с подсветкой
-- Pagination with highlighting
SELECT id, title, price, weight(),
HIGHLIGHT({limit=100}) as highlight
FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5, 5;
Вывод:
+------+----------------------------------------------+-------+----------+-----------------------------------------------------+
| id | title | price | weight() | highlight |
+------+----------------------------------------------+-------+----------+-----------------------------------------------------+
| 246 | Soft technically took. smartphone | 11 | 1272 | Soft technically took. <b>smartphone</b> |
| 1105 | Dirty up are! temporarily called. smartphone | 11 | 1272 | Dirty up are! temporarily called. <b>smartphone</b> |
| 3293 | Instantly thick ran that hurt. smartphone | 11 | 1272 | Instantly thick ran that hurt. <b>smartphone</b> |
| 3736 | Work her wrong locally. smartphone | 11 | 1272 | Work her wrong locally. <b>smartphone</b> |
| 6978 | Stale loud passively sweet clean. smartphone | 11 | 1272 | Stale loud passively sweet clean. <b>smartphone</b> |
+------+----------------------------------------------+-------+----------+-----------------------------------------------------+
Реализация кнопки "Загрузить больше" с пагинацией по прокрутке
Пагинация на основе прокрутки идеально подходит для реализации функции "Загрузить больше", так как она обеспечивает эффективную навигацию по большим наборам результатов. Вот как это реализовать:
-- Initial query with SHOW SCROLL to get the scroll token
SELECT id, title, price, weight() FROM products
WHERE MATCH('smartphone')
ORDER BY weight() DESC, price ASC, id ASC
LIMIT 5; SHOW SCROLL\G
Вывод:
+------+------------------------------------------------+-------+----------+
| id | title | price | weight() |
+------+------------------------------------------------+-------+----------+
| 1179 | Weak spoke? fall. smartphone | 10 | 1272 |
| 1388 | 3; her day of. smartphone | 10 | 1272 |
| 1636 | Positively bad winter clean. smartphone | 10 | 1272 |
| 5628 | Foolish from went heard low. smartphone | 10 | 1272 |
| 8561 | Left sent. Infrequently, try lay. smartphone | 10 | 1272 |
+------+------------------------------------------------+-------+----------+
*************************** 1. row ***************************
scroll_token: eyJvcmRlcl9ieV9zdHIiOiJ3ZWlnaHQoKSBERVNDLCBwcmljZSBBU0MsIGlkIEFTQyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI3MiwidHlwZSI6ImludCJ9LHsiYXR0ciI6InByaWNlIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjoxMCwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjo4NTYxLCJ0eXBlIjoiaW50In1dfQ==
1 row in set (0.00 sec)
-- When user clicks "Load More", use the scroll token to get the next batch
SELECT id, title, price, weight() FROM products
WHERE MATCH('smartphone')
LIMIT 5
OPTION scroll='eyJvcmRlcl9ieV9zdHIiOiJ3ZWlnaHQoKSBERVNDLCBwcmljZSBBU0MsIGlkIEFTQyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI3MiwidHlwZSI6ImludCJ9LHsiYXR0ciI6InByaWNlIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjoxMCwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjo4NTYxLCJ0eXBlIjoiaW50In1dfQ=='; SHOW SCROLL\G
Вывод:
+------+---------------------------------------------+-------+----------+
| id | title | price | weight() |
+------+---------------------------------------------+-------+----------+
| 246 | Soft technically took. smartphone | 11 | 1272 |
| 1105 | Dirty up are! temporarily called. smartphone| 11 | 1272 |
| 3293 | Instantly thick ran that hurt. smartphone | 11 | 1272 |
| 3736 | Work her wrong locally. smartphone | 11 | 1272 |
| 6978 | Stale loud passively sweet clean. smartphone| 11 | 1272 |
+------+---------------------------------------------+-------+----------+
*************************** 1. row ***************************
scroll_token: eyJvcmRlcl9ieV9zdHIiOiJ3ZWlnaHQoKSBERVNDLCBwcmljZSBBU0MsIGlkIEFTQyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI3MiwidHlwZSI6ImludCJ9LHsiYXR0ciI6InByaWNlIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjoxMSwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjo2OTc4LCJ0eXBlIjoiaW50In1dfQ==
Для каждого последующего нажатия "Загрузить больше" вы будете использовать новый токен прокрутки, возвращаемый предыдущим запросом. Этот подход имеет несколько преимуществ по сравнению с традиционной пагинацией на основе смещения:
- Лучшая производительность: Нет ухудшения производительности при глубокой пагинации
- Нет ограничения max_matches: Вы можете эффективно пагинировать через миллионы результатов
- Последовательный доступ: Эффективно перемещаться по последовательным страницам результатов
Советы по реализации:
- Храните токен прокрутки в состоянии вашего приложения (на стороне клиента или сервера)
- Включайте токен в каждый последующий запрос, когда пользователь нажимает "Загрузить больше"
- Всегда используйте самый последний токен, так как каждый токен представляет текущее положение в наборе результатов
- Помните, что токены прокрутки временные и в конечном итоге истекут
Этот подход к реализации решает многие ограничения традиционной пагинации на основе смещения, описанные в Разделе 8 , особенно для сценариев глубокой пагинации.
Заключение
Manticore Search предлагает гибкие варианты пагинации, чтобы соответствовать различным случаям использования. Традиционная пагинация на основе смещения хорошо работает для простых интерфейсов с ограниченной навигацией по страницам, в то время как пагинация на основе прокрутки обеспечивает лучшую производительность для сценариев глубокой пагинации, таких как бесконечная прокрутка или экспорт данных.
При реализации пагинации в Manticore Search:
- Для мелкой пагинации (первые несколько страниц): Используйте традиционную пагинацию на основе смещения с последовательной сортировкой.
- Для глубокой пагинации (много страниц или большие наборы данных): Используйте пагинацию на основе прокрутки с правильными критериями сортировки на основе идентификаторов.
- Для последовательных результатов: Всегда включайте поле
idв ваш оператор ORDER BY и поддерживайте последовательные критерии сортировки в запросах. - Для полнотекстового поиска: Включайте
weight()или_scoreв ваши критерии сортировки, чтобы гарантировать, что наиболее релевантные результаты появляются первыми.
Понимая сильные и слабые стороны, а также лучшие практики каждого подхода, вы можете реализовать наиболее эффективную стратегию пагинации для ваших конкретных потребностей приложения. Помните, что лучший метод пагинации зависит от вашего случая использования, объема данных и требований к пользовательскому опыту.
