什么是基于游标的分页?令牌与权衡

什么是基于游标的分页?令牌与权衡

Scrapeless Agent Browser 让你的自动化能够在动态结果界面中导航,同时你的应用程序跟踪分页状态和已收集的记录。

总结

  • 游标标识一个继续的位置。 除非 API 明确文档化其结构,否则要将令牌视为不透明。
  • 稳定排序需要一个确定性的决胜字段。 仅使用时间戳可能无法区分在同一时刻创建的记录。
  • 游标分页并不意味着快照。 并发插入、删除和更新仍然取决于服务的一致性契约。
  • 检查点包括查询以及游标。 在推进已提交的继续状态之前先存储记录。

游标延续特定的有序查询

基于游标的分页将结果集划分为多个页面,并给客户端一个可以继续的位置。客户端不是要求服务器跳过指定数量的记录,而是回传前一个响应中的继续值。服务器在查询的排序和过滤规则之内解释该值。因此,游标是相对于某个特定集合遍历而言才有意义。

“游标”一词并不规定一个通用的参数名或数据结构。REST API 可以暴露一个 next-page token 或 next 链接,而 GraphQL 连接可以暴露边缘游标和分页信息。在编写循环之前应阅读所选 API 的契约。一个猜测参数名为 cursor 的客户端,可能会发送一个有效的 HTTP 请求,但服务会以不同于预期分页操作的方式解释它。

AIP-158 page-token 指南 将页令牌视为不透明,并将继续位置绑定到其他请求参数。该设计使客户端独立于后端的内部表示。令牌可能编码一个位置、引用服务端状态,或携带受保护的查询细节。其外观无法证明服务使用的是哪种机制,而客户端也不应需要这些知识才能正确继续。

为什么确定性排序很重要

确定性排序为每条记录相对于继续边界赋予一个确定的位置。按非唯一时间戳排序可能会让多条记录在页面边缘打成平手。典型的 keyset 设计会在排序中加入一个不可变的唯一标识符,使边界引用的是一个完整的排序键。具体选择取决于数据库和应用的数据模型。

考虑一个按创建时间和记录 ID 排序的假想 feed。下一页在当前页的最后一对键之后开始,并使用相同的排序方向。如果多条记录具有相同的创建时间,则由 ID 决定哪些已经被访问过。这是一个概念性示例,而非对某个 Scrapeless 端点的描述,也不是对特定数据库执行计划的承诺。

参见 PostgreSQL 排序指南 说明了为什么受限查询结果需要可预测的顺序,以及为什么被跳过的偏移行仍然需要服务器工作。合适的索引可以支持高效的 keyset 查找,但仅使用游标分页并不能证明该索引一定存在。在评估自己运维的后端时,要检查实际的查询计划;不要从 API 的参数名称推断性能。

游标、偏移量与 keyset 是相关术语

偏移量分页通过要跳过多少行来标识位置,而游标则通过服务的令牌契约标识继续边界。Keyset 分页是一种常见的数据库技术,用有序字段值实现该边界。API 可能对外暴露不透明游标,但内部采用不同方法。评估性能声明时,应将公共接口与存储算法分开。

偏移量分页可以支持熟悉的页码导航以及直接跳转到选定偏移量。游标遍历通常优先顺序继续,可能不支持任意页面跳转。两种接口都不会自动提供廉价的精确总数。诸如跳到第 20 页、保留已保存位置或向后浏览等产品需求,应根据文档化的 API 行为来评估,而不是想当然。

特性偏移量游标
位置跳过数量或页码服务器提供的位置或链接
直接跳转通常在一定范围内支持仅在服务支持时可用
数据变化位置可能会移动取决于排序和一致性
客户端状态查询和页面位置查询和不透明游标

GraphQL 连接定义了一个特定契约

《 GraphQL Cursor Connections 规范 》定义了 connection 和 edge 结构、向前和向后分页参数以及页面信息。在该模型中,游标属于边缘,而页面信息描述是否还有更多边缘可用。这些字段名是该规范的约定,而不是每个使用游标的 API 都必须采用的名称。

向前遍历通常使用页面大小配合一个 after 游标;向后遍历则使用对应的 before 边界。连接规范要求边缘顺序在这两种方向下保持一致。向后移动的用户不应看到集合业务顺序被莫名其妙地反转。实现和客户端需要就讨论的是显示顺序还是遍历方向达成一致。

使用文档中说明的结束条件,而不是仅根据页面长度来估算。一些 API 即使返回的项目少于请求数量,也仍然可以提供续传。另一些则通过缺失的令牌或为假的续传标志来定义最后一页。对于没有可见记录的响应也需要谨慎解读:权限、过滤条件以及端点特定的分页行为都会影响该页面真正代表的含义。

光标不会冻结一个持续变化的数据集

基于光标的分页并不会自动为所有页面提供同一份数据库快照。服务可以针对每一页使用当前数据来评估。新记录可能会出现在续传边界之前,现有记录可能被删除,可变的排序字段也可能让记录跨越边界移动。这些变化是否会导致遗漏或重复观测,取决于具体实现及其一致性策略。

对于历史导出,应寻找有文档说明的快照、导出任务或稳定的上界。对于实时数据流,要先定义目标是枚举一个固定群体,还是观测当前条目。这是两种不同的任务。高水位标记可以帮助描述采集范围,但前提是数据源在排序与过滤上提供必要的保证时才可以使用。

在目标端保留记录标识,以便识别重复观测。去重可以防止重复行,却无法证明某条未见记录从未被跳过。使用数据源的明确完成信号和采集时的查询边界来报告覆盖范围。完整遍历某个接口与完成一份完整的历史清单并不总是等价的说法。

谨慎保留过滤条件并提交检查点

续传令牌应与生成它的查询一起使用。存储一个查询指纹,涵盖集合本身、过滤条件、排序方式以及其他相关参数。如果用户更改了过滤条件,应重新开始新的遍历,除非服务明确支持将旧令牌与新查询组合使用。将无效令牌视为需要排查的契约问题,而不是集合为空的证据。

先提交当前页面的记录,再提交下一次续传状态。检查点应描述已经写入持久存储的内容。包括已接收记录数、在可用时最后一个完成页面的标识,以及数据源是否报告仍有更多数据。不要在共享日志中记录敏感令牌值;即便客户端被要求不去检查,一个不透明令牌内部仍可能包含信息。

令牌的有效期同样重要。依赖服务端状态的令牌可能会过期,自包含令牌则可能绑定到授权上下文或签名策略。在规划长时间运行的导出前,先阅读文档中的保留期限。 SCIM cursor pagination standard 展示了一种特定的标准化光标契约,包括续传属性;它的规则不应被套用到无关的 API 上。

浏览器界面可能隐藏底层光标

“加载更多”按钮或无限滚动列表可能在内部使用光标,却不会在页面 URL 中暴露该光标。可见的交互是浏览器的分页界面,而网络请求中才携带数据续传信息。从页面和你的授权所允许的行为开始着手。不要凭空制造内部令牌,也不要假定未文档化的端点是稳定的公共契约。

Scrapeless Agent Browser 可以为授权后的结果导航任务提供浏览器环境。使用 Agent Browser 概念 来理解该环境,并通过 浏览器分页模式 区分可见的导航类型。采集端仍然需要记录标识、受限的遍历范围,以及清晰的停止条件。

查看 Scrapeless 价格 以评估会话成本,但要在会话时长之外独立评估数据集质量。一个假设的商品目录采集流程,可能会在页面加载出新卡片后记录每个可见商品 ID,并在界面发出结束信号时停止。该过程可以验证已观测到的浏览器遍历,而不宣称获得了底层目录的事务级快照。

为合适的需求选择光标分页

当按顺序访问有序集合符合产品需求时,光标分页非常有用。在合适的后端设计中,它可以避免大偏移成本,并比页码更清晰地表达稳定的续传边界。当用户需要任意跳页,或耐久导出需要长于令牌生命周期时,它就不那么方便了。

将查询顺序、续传契约、结束标记、令牌生命周期与一致性行为综合评估。在扩展采集规模前,把这些决策写入消费者的验收标准。最终数据集的质量取决于它们所有因素。对不透明令牌的正确处理只是可靠遍历的一部分,而授权、存储和覆盖范围仍然是外围应用的责任。

结论

把光标当作单个有序查询的续传状态,遵循服务的结束条件,并在前进前完成落盘。光标分页可以支持高效的顺序访问,但可辩护的数据集同样需要清晰的一致性边界。在宣布一次长遍历“完成”之前,先建立好这一边界。

构建你的网页数据工作流

使用 Agent Browser 进行动态导航,同时由采集端记录分页状态并验证数据集覆盖率。

立即注册即可获得 $5 免费额度 — 无需信用卡.

领取你的 $5 额度 →

常见问题

基于光标的分页和 keyset 分页是同一回事吗?

基于游标的分页不一定与键集分页相同。游标是 API 的续传接口,而键集分页是一种常用来实现它的数据库技术。该令牌可以隐藏其他后端机制,因此应根据实现证据来评估效率,而不是仅依据接口本身。

客户端可以解码不透明游标吗?

客户端应将不透明游标视为未解释的值。即使其内容看起来可读,对其进行解码并构造替代值会形成对未文档化内部实现的依赖。应严格按照 API 文档返回该令牌,并保留其关联的查询设置。

游标分页能防止所有重复或缺失记录吗?

游标分页不能防止所有重复或缺失记录。可变数据和按请求的一致性仍会影响遍历。应使用确定性的排序、在可用时文档化的快照边界,并在存储中记录记录标识,同时报告采集的实际一致性限制。

游标分页可以直接跳转到任意页面吗?

只有当服务提供该能力时,游标分页才支持任意页面跳转。许多游标接口被设计为顺序遍历。需要直接页面选择的产品应在选型其接口或承诺该行为之前,确认 API 是否支持这样的导航能力。

分页检查点中应该包含什么?

分页检查点应包括已提交的续传状态以及生成该状态的查询定义。还要记录存储进度和来源的完成信号。只有在已接受的记录完成存储之后才推进检查点,并在游标值可能暴露敏感查询上下文时保护它们。

参考资料