Пагинация является важной функцией для любой поисковой системы, позволяющей пользователям эффективно навигировать по большим наборам результатов. 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 используетClause 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 ...
]
}
}