搜索结果的分页

Manticore Search 默认返回结果集中排名前20的匹配文档。

SQL

在 SQL 中,可以使用 LIMIT 子句来导航结果集。

LIMIT 可以接受一个数字作为返回集的大小(偏移量为零),也可以接受一对偏移量和大小的值。

HTTP JSON

使用 HTTP JSON 时,节点 offsetlimit 控制结果集的偏移量和返回集的大小。或者,也可以使用 sizefrom 这对参数。

‹›
  • SQL
  • JSON
📋
SELECT  ... FROM ...  [LIMIT [offset,] row_count]
SELECT  ... FROM ...  [LIMIT row_count][ OFFSET offset]

结果集窗口

默认情况下,Manticore Search 使用一个包含1000个最佳排名文档的结果集窗口,这些文档可以返回在结果集中。如果结果集分页超出此值,查询将以错误结束。

此限制可以通过查询选项 max_matches 进行调整。

只有在需要导航到如此深的位置时,才应将 max_matches 增加到非常高的值。较高的 max_matches 值需要更多内存,并可能增加查询响应时间。处理深度结果集的一种方法是将 max_matches 设置为偏移量和限制的总和。

max_matches 降低到1000以下的好处是减少查询使用的内存。它也可以减少查询时间,但在大多数情况下,这种提升可能不明显。

‹›
  • SQL
  • JSON
📋
SELECT  ... FROM ...   OPTION max_matches=<value>

滚动搜索选项

滚动搜索选项提供了一种高效且可靠的方式来分页浏览大型结果集。与传统的基于偏移量的分页不同,滚动搜索在深度分页时性能更好,并且实现分页更简单。 虽然它使用与基于偏移量分页相同的 max_matches 窗口,但滚动搜索可以通过使用滚动令牌在多次请求中检索结果,返回超过 max_matches 值的文档。 使用滚动分页时,无需同时使用 offsetlimit —— 这是多余的,通常被认为是过度设计。只需指定 limitscroll 令牌即可获取每个后续页面。

通过 SQL 滚动

带排序条件的初始查询

首先执行带有所需排序条件的初始查询。唯一要求是 id 必须包含在 ORDER BY 子句中,以确保分页的一致性。查询将返回结果和用于后续页面的滚动令牌。

SELECT ... ORDER BY [... ,] id {ASC|DESC};
‹›
  • Initial Query Example
Initial Query Example
📋
SELECT weight(), id FROM test WHERE match('hello') ORDER BY weight() desc, id asc limit 2;
‹›
Response
+----------+------+
| weight() | id   |
+----------+------+
|     1281 |    1 |
|     1281 |    2 |
+----------+------+
2 rows in set (0.00 sec)

获取滚动令牌

执行初始查询后,通过执行 SHOW SCROLL 命令获取滚动令牌。 必须在滚动序列中的每次查询后调用 SHOW SCROLL,以获取下一页的更新滚动令牌。 每次查询都会生成一个反映最新滚动位置的新令牌。

SHOW SCROLL;

响应:

| scroll_token                       |
|------------------------------------|
| <base64 encoded scroll token>      |
‹›
  • Scroll Token Example
Scroll Token Example
📋
SHOW SCROLL;
‹›
Response
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| scroll_token                                                                                                                                                                                                             |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| eyJvcmRlcl9ieV9zdHIiOiJ3ZWlnaHQoKSBkZXNjLCBpZCBhc2MiLCJvcmRlcl9ieSI6W3siYXR0ciI6IndlaWdodCgpIiwiZGVzYyI6dHJ1ZSwidmFsdWUiOjEyODEsInR5cGUiOiJpbnQifSx7ImF0dHIiOiJpZCIsImRlc2MiOmZhbHNlLCJ2YWx1ZSI6MiwidHlwZSI6ImludCJ9XX0= |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

使用 scroll 的分页查询

要获取下一页结果,在后续查询中将滚动令牌作为选项包含。当提供 scroll 选项时,指定排序条件是可选的。 记得在此查询后再次调用 SHOW SCROLL,以获取下一页所需的新令牌。

SELECT ... [ORDER BY [... ,] id {ASC|DESC}] OPTION scroll='<base64 encoded scroll token>'[, ...];

这确保分页无缝继续,保持初始查询中建立的排序上下文。

‹›
  • Paginated Query Example
Paginated Query Example
📋
SELECT weight(), id FROM test WHERE match('hello') limit 2
OPTION scroll='eyJvcmRlcl9ieV9zdHIiOiJ3ZWlnaHQoKSBkZXNjLCBpZCBhc2MiLCJvcmRlcl9ieSI6W3siYXR0ciI6IndlaWdodCgpIiwiZGVzYyI6dHJ1ZSwidmFsdWUiOjEyODEsInR5cGUiOiJpbnQifSx7ImF0dHIiOiJpZCIsImRlc2MiOmZhbHNlLCJ2YWx1ZSI6MiwidHlwZSI6ImludCJ9XX0=';
‹›
Response
+----------+------+
| weight() | id   |
+----------+------+
|     1281 |    3 |
|     1281 |    4 |
+----------+------+
2 rows in set (0.00 sec)

通过 JSON 滚动

初始请求

在初始请求中,在选项中指定 "scroll": true 和所需的排序条件。注意,id 必须出现在 sort 数组中。响应将包含滚动令牌,可用于后续请求的分页。

POST /search
{
  "table": "<table_names>",
  "options": {
      "scroll": true
  },
  ...
  "sort": [
    ...
    { "id":{ "order":"{asc|desc}"} }
  ]
}

示例输出:

{
    "timed_out": false,
    "hits": {
        ...
    },
    "scroll": "<base64 encoded scroll token>"
}
‹›
  • Initial Request Example
Initial Request Example
📋
POST /search
{
  "table": "test",
  "options":
  {
    "scroll": true
  },
  "query":
  {
    "query_string":"hello"
  },
  "sort":
  [
    { "_score":{ "order":"desc"} },
    { "id":{ "order":"asc"} }
  ],
  "track_scores": true,
  "limit":2
}
‹›
Response
{
  "took": 0,
  "timed_out": false,
  "hits":
  {
    "total": 10,
    "total_relation": "eq",
    "hits":
    [
      {
        "_id": 1,
        "_score": 1281,
        "_source":
        {
          "title": "hello world1"
        }
      },
      {
        "_id": 2,
        "_score": 1281,
        "_source":
        {
          "title": "hello world2"
        }
      }
    ]
  },
  "scroll": "eyJvcmRlcl9ieV9zdHIiOiJAd2VpZ2h0IGRlc2MsIGlkIGFzYyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI4MSwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjoyLCJ0eXBlIjoiaW50In1dfQ=="
}

使用 scroll 的分页请求

要继续分页,在下一次请求的选项对象中包含从上一次响应获得的滚动令牌。指定排序条件是可选的。

POST /search
{
  "table": "<table_names>",
  "options": {
    "scroll": "<base64 encoded scroll token>"
  },
  ...
}
‹›
  • Paginated Request Example
Paginated Request Example
📋
POST /search
{
  "table": "test",
  "options":
  {
    "scroll": "eyJvcmRlcl9ieV9zdHIiOiJAd2VpZ2h0IGRlc2MsIGlkIGFzYyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI4MSwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjoyLCJ0eXBlIjoiaW50In1dfQ=="
  },
  "query":
  {
    "query_string":"hello"
  },
  "track_scores": true,
  "limit":2
}
‹›
Response
{
  "took": 0,
  "timed_out": false,
  "hits":
  {
    "total": 8,
    "total_relation": "eq",
    "hits":
   [
      {
        "_id": 3,
        "_score": 1281,
        "_source":
        {
          "title": "hello world3"
        }
      },
      {
        "_id": 4,
        "_score": 1281,
        "_source":
        {
          "title": "hello world4"
        }
      }
    ]
  },
  "scroll": "eyJvcmRlcl9ieV9zdHIiOiJAd2VpZ2h0IGRlc2MsIGlkIGFzYyIsIm9yZGVyX2J5IjpbeyJhdHRyIjoid2VpZ2h0KCkiLCJkZXNjIjp0cnVlLCJ2YWx1ZSI6MTI4MSwidHlwZSI6ImludCJ9LHsiYXR0ciI6ImlkIiwiZGVzYyI6ZmFsc2UsInZhbHVlIjo0LCJ0eXBlIjoiaW50In1dfQ=="
}
Last modified: August 28, 2025