Collection 沿用 Elasticsearch 标准文档和查询 API 的主要调用方式,通过 _slice 指定业务数据范围。应用开发中最常用的操作包括写入、读取、可见性控制和查询范围指定。
写入和读取
|
访问方式 |
适用场景 |
|
单文档 API |
已知文档 ID 和所属 Slice 的实时增删改查。 |
|
Bulk |
批量写入日志或知识库内容,或者在一个批次中写入多个 Slice。 |
|
MGet |
已知多组文档 ID,需要一次读取相同或不同 Slice 中的文档。 |
|
Reindex |
普通索引与 Collection 之间,或不同 Collection 之间的数据迁移。 |
单文档 API:
|
操作 |
API |
|
写入或覆盖文档 |
|
|
自动生成文档 ID |
|
|
仅创建文档 |
|
|
获取文档 |
|
|
判断文档是否存在 |
|
|
获取 |
|
|
更新文档 |
|
|
删除文档 |
|
使用时请遵循以下规则:
-
单文档请求只能指定一个 Slice,不能使用逗号分隔或
_all。 -
index、create和update在auto_create_slice=true时可以自动注册不存在的 Slice;读取和删除不会自动注册,指定不存在的 Slice 时返回 HTTP 404。 -
文档以 Collection、业务 Slice 名和
_id共同定位。不同 Slice 可以使用相同_id;应用读取、更新和删除时必须带上对应 Slice,不能只按_id区分租户。 -
每次 Bulk 最多自动注册 512 个缺失 Slice,已存在的 Slice 不计入该限制。
-
wait_for_active_shards在 Agent 引擎版写入链路中不作为等待副本的条件。查询可见性通常由后台刷新保障;确需在写入返回前等待可搜索时,按下文的适用条件使用refresh=wait_for。 -
默认不返回向量值。常规读取和检索只返回业务需要的字段;确需核对或导出向量时,见按需读取向量值。
响应中的 _index 和 _routing 可能分别是底层索引名和系统生成的 Slice 内部标识(slice_uid),不等于请求中使用的 Collection 名和业务 Slice 名。后续请求继续使用业务名称,不要直接回填这些内部值,见请求目标与响应标识。
Refresh 与查询可见性
常规写入不应传 refresh,应等待后台自动刷新。 写入成功表示数据已经持久化;按 ID 读取文档和按条件搜索数据的可见性不同,应先根据需要选择读取方式。
按 ID 确认写入,无需刷新
只需确认刚写入的文档时,使用 GET 或 Multi Get。两者默认启用实时读取(realtime=true),无需显式传参,也不需要调用 Refresh。例如,在写入请求成功后按相同的 Slice 和文档 ID 读取:
GET /knowledge-chunks/_doc/chunk-1001?_slice=tenant-a
检查返回的 found 和业务字段;MGet 应逐项检查结果。实时读取不是所有故障窗口下的强一致保证:主分片不可用、迁移或重启导致实时读取源暂不可用时,GET/MGet 可能退回已提交的数据视图,返回旧版本,或对尚未进入该视图的文档返回 found=false。此时应结合写入结果、集群状态和有限重试核对,不能仅凭一次未找到就认定写入丢失。
按条件搜索,等待后台自动刷新
Search、Count、KNN 等查询需要等待数据在查询节点可搜索。Agent 引擎版的默认自动刷新间隔为 5s,创建普通索引或 Collection 时无需重复设置;传统有状态 Elasticsearch 的默认值是 1s。实际可搜索时间还受数据发布、查询节点加载和负载影响,5s 不是可见性时限保证。
可通过 GET /{collection}/_settings 查看显式设置,查询默认值时加 include_defaults=true;通过 PUT /{collection}/_settings 调整。线上业务保留自动刷新,建议间隔不低于 5s。缩短间隔会增加索引节点的数据发布、对象存储 I/O 和查询节点刷新开销;需要控制写入负载时可适当增大间隔,并评估数据可见性延迟。
受限使用 refresh=wait_for
refresh=wait_for 只用于单次、低频的业务同步点,并须同时满足:确实要等待本批数据可搜索、按 Bulk 批次使用、限制并发等待、保持自动刷新开启,且已经评估等待时间对业务延迟和吞吐的影响。按 ID 确认写入请使用 GET/MGet;持续导入和常规写入不应传该参数。
它会等待刷新并协调查询副本可见。并发等待过多、刷新监听器耗尽时还可能触发强制刷新,可通过响应中的 forced_refresh: true 识别。即使触发强制刷新,仍可能继续等待查询侧可见,不能保证立即返回。 客户端超时也不表示写入未发生,不要通过增加并发等待来催促刷新。
手动刷新仅限隔离验证或运维窗口
不要在应用代码路径中添加 refresh=true 或调用 _refresh,也不要在每批导入完成后自动刷新。 refresh=true 会触发即时分布式刷新,增加数据发布、对象存储 I/O 和查询节点刷新开销;后台自动刷新是常规替代方案。
POST /{collection}/_refresh 影响整个 Collection 的所有 Backing、全部租户,不能按调用者自己的 Slice 数据量估算开销;随着 Backing 和数据增长,同一请求的影响也会扩大。无法通过 _slice 缩小范围,携带该参数会返回 HTTP 400;Collection 也不提供面向业务调用的单 Backing 刷新入口。
手动刷新仅用于单独创建、只含少量演示数据的验证 Collection,或由管理员评估整个 Collection 规模后安排的低频运维窗口。后者包括下文的一次性离线导入。执行后应检查 _shards.failed;常规在线导入应等待后台自动刷新,需要预热时等数据可搜索后再执行。
关闭自动刷新仅限一次性离线导入
线上 Collection 不要设置 index.refresh_interval=-1。它会关闭自动刷新,使搜索无法及时看到新增数据;与 refresh=wait_for 组合时,请求可能长时间等待甚至超时。
唯一例外是整个目标 Collection 处于明确的一次性离线导入窗口,所有相关租户都不执行查询。导入期间省略 refresh,完成后先恢复 5s 或原有的不低于 5s 的间隔,再由导入任务在该窗口内统一执行一次 _refresh,检查分片结果并验证查询;对冷查询延迟敏感时,先预热再恢复线上流量。不要把这一流程用于仍在服务其他租户的 Collection。
Refresh 只解决查询可见性,不代表全部查询副本已经可用,也不能替代查询探针和高可用检查。
Bulk
每个 Bulk item 可以在 action metadata 中提供自己的 _slice(见 快速入门的批量写入示例)。一个批次全部写入同一 Slice 时,也可以在 URL 上提供默认值:
POST /knowledge-chunks/_bulk?_slice=tenant-a
{ "index": { "_id": "chunk-2001" } }
{ "tenant_id": "tenant-a", "document_id": "doc-account-security", "title": "账号安全设置", "content": "管理员可以在安全设置页面启用多因素认证。" }
item 中的 _slice 可以覆盖 URL 默认值。命名空间模式不会从文档字段推导 Slice,即使文档体中包含 tenant_id 等字段,实际写入位置仍由 _slice 决定。错误处理方式见 API 通用约定。
Multi Get
MGet 适合一次读取多个已知 ID,每个 item 可以访问不同的 Slice:
POST /knowledge-chunks/_mget
{
"docs": [
{ "_id": "chunk-1001", "_slice": "tenant-a" },
{ "_id": "chunk-1001", "_slice": "tenant-b" }
]
}
上述两项读取不同租户的同 ID 文档;使用快速入门的数据时,标题分别为“退款与退货政策”和“查询物流状态”。逐项检查 found、业务字段和错误。URL 上的 _slice 可以作为默认值,每个 item 可以覆盖该默认值。每个 item 最终只能解析到一个 Slice。
Reindex
调用前请核对Collection Reindex 的 API 支持范围,特别是脚本、目标 pipeline 和远程源端的限制。
Reindex 适合在普通索引与 Collection 之间,或不同 Collection 之间迁移数据。在同一个 Collection 内复制一个 Slice 时,使用 Copy Slice。
当源端是 Collection 时,必须在请求体中显式指定 source._slice,否则返回 HTTP 400。当目标端是 Collection 时,只能指定一个目标 Slice,并且目标值必须采用 ={slice} 格式。
执行前先创建目标 Collection、配置可接收源文档的 Mapping,并按 预创建 Backing 准备容量、注册目标 Slice。确认要迁移的源数据已可搜索;Reindex 不持续同步后续写入,正式切流前还需处理增量数据。
Reindex 默认保留文档 _id,并可能覆盖目标中同 ID 的文档。把多个源 Slice 合并到一个目标 Slice 前,必须确认文档 ID 在这些 Slice 之间也唯一;否则应分别迁移到不同目标 Slice,或由应用重新生成唯一 ID 后导入。
以下示例采用异步执行、单任务、每批 500 条、目标速率 500 条/秒,先控制迁移对在线业务的影响,再根据负载调整。requests_per_second 按文档数在批次间节流,不是每秒 HTTP 请求数:
POST /_reindex?wait_for_completion=false&slices=1&requests_per_second=500
{
"source": {
"index": "source-knowledge-chunks",
"_slice": "tenant-a",
"size": 500
},
"dest": {
"index": "target-knowledge-chunks",
"_slice": "=tenant-archive"
}
}
保存响应的 task,通过 GET /_tasks/<task_id> 间隔查询,直到 completed=true,并检查 error 以及结果中的 failures、version_conflicts。任务完成不等于目标数据已全部可搜索;切流前等待后台刷新、验证目标结果,并预热即将访问的 Slice。
规则:
-
source._slice支持一个、多个或_all;Reindex 请求体不接受source.routing,传入会返回 HTTP 400; -
目标端可以使用
"_slice": "=slice-name"或"routing": "=slice-name",不能同时提供,前导=必须保留; -
目标 Slice 不存在时,仅在
auto_create_slice=true时自动注册; -
顶层
slices参数表示 Elasticsearch Reindex 的并行度,与业务 Slice 数量无关; -
从 Collection 写入普通索引时,如不需要保留 routing,可设置
"dest": { "routing": "discard" }。
指定查询范围
本节集中说明 Agent 引擎版新增的 Slice 查询范围;接口的通用参数沿用 Elasticsearch API 语义,已知限制见使用限制。
|
查询范围 |
适用场景 |
示例 |
|
单个 Slice |
单租户在线查询、在指定命名空间内检索 |
|
|
多个 Slice |
已知少量租户的汇总查询、跨少量命名空间查询 |
|
单次查询最多指定 1024 个 Slice。除数量上限外,还需要注意 HTTP 请求行长度限制:使用较长的 Slice 名时,可能在达到数量上限之前先返回 too_long_http_line_exception。此时可以缩短 Slice 名或拆分为多次查询。
Collection 查询默认启用查询与预热亲和性。开启时,请求中的 preference 会被亲和性规则覆盖,响应不会额外提示;如果需要用 preference 控制节点选择,管理员必须关闭该设置,而且关闭后对所有 Collection 生效。
线上查询默认不要使用 _slice=_all。 它会搜索整个 Collection,查询节点的分片请求、聚合与对象存储读取开销随 Backing 和分片数量增长。应用应指定已知的一个或少量 Slice;仅在专门的分析、审计或运维任务确实需要全部数据,并已评估整个 Collection 的负载、限制并发和设置超时后,才使用 GET /knowledge-chunks/_search?_slice=_all。
如果使用了 Beta 阶段的 Branch Slice(Beta),多 Slice 查询和 _slice=_all 在范围包含尚未转为普通 Slice 的 Branch 时会返回 HTTP 409。未使用该能力时不受影响。
查询列表中可能包含不存在的 Slice 时,可以使用 ignore_missing_slice:
GET /knowledge-chunks/_search?_slice=tenant-a,tenant-b&ignore_missing_slice=true
对可能不存在的可选 Slice,可设置 ignore_missing_slice=true,避免因单个缺失 Slice 重试整个批次。不带该参数时,只要有一个 Slice 不存在,整个请求返回 HTTP 404。该参数只影响具名 Slice;与 _slice=_all 同时使用时会被忽略且不报错。
以下查询接口支持相同的 Slice 范围参数:
-
Search 和 Count
-
Multi search
-
Search template
-
Async search
-
Validate query
-
Search shards
-
Update by query 和 Delete by query
Explain 用于解释某一文档为什么匹配查询,只能指定一个 Slice,不能使用逗号列表或 _all:
POST /knowledge-chunks/_explain/chunk-1001?_slice=tenant-a
{
"query": {
"match": { "content": "退款" }
}
}
对以 Collection 为目标的 Update by query、Delete by query 和 Reindex,必须显式指定目标 Slice,未指定时请求会被拒绝并返回 HTTP 400。
未指定 _slice 时的默认行为
在命名空间模式(exact)下,Search、Count、Search Template、Async Search、Validate Query 和 Search Shards 默认要求提供 _slice;缺少时请求会失败。少量专门的任务满足上文全量查询条件时,在这些请求中显式使用 _slice=_all 即可,无需改变全局默认行为。向量簇召回模式可根据查询向量自动选择候选 Slice,具体见向量簇召回模式。
默认保持以下开关关闭。 该设置影响所有 Collection:命名空间模式未指定 _slice 时,查询会回退到全部 Slice;向量簇模式仅在未指定范围且配置路径中缺少查询向量时回退全量,提供有效查询向量时仍正常选择候选 Slice。全量回退会增加分片请求、聚合和对象存储读取开销。
确需全量查询的专门任务应在单次请求中显式指定范围,不要通过这个全局开关保证全量。仅在应用明确依赖全量回退、管理员已评估所有受影响 Collection 的负载并配置并发与超时控制后,才开启:
PUT /_cluster/settings
{
"persistent": {
"apack.slice_collection.search.default_to_all_slices": true
}
}
开启后,命名空间模式中的 GET /knowledge-chunks/_search 等价于显式传入 _slice=_all。向量簇模式的非法路径、query_vector_builder 和向量维度错误仍会被拒绝,详见自动选择候选 Slice。
该设置只适用于上述只读查询接口,不适用于 GET、MGet、Explain、Reindex、Update by query 和 Delete by query。
routing 兼容参数
对 Collection 或 Collection Alias 使用以下文档读写与查询 API 时,可以用 Elasticsearch 标准 routing 代替 _slice,两者表示同一个逻辑 Slice,语义等价。该写法用于兼容已有客户端,新应用仍建议使用语义更明确的 _slice。
-
同一个 URL 或同一个 Bulk、MGet item 不能同时提供
_slice和routing; -
该兼容方式不适用于 Reindex 请求体的
source.routing、Collection 和 Slice 管理接口、缓存预热、Copy Slice、CAT 和显式 Refresh; -
该兼容方式不改变普通 Elasticsearch 索引的 routing 语义。
混合请求中的普通索引
Search 类请求同时包含普通索引与 Collection 时,集群设置 apack.slice_collection.rewrite.mixed_collection_targets 决定行为:
|
取值 |
Search 类请求的行为 |
|
|
跳过 Collection 改写并返回 Warning。精确指定已存在的普通索引与 Collection、不带 |
|
|
拒绝混合请求,返回 HTTP 400。 |
|
|
该配置值仅供支持展开的操作使用;当前 Search 类请求不支持混合展开,返回 HTTP 400。 |
routing 仍按普通索引的路由规则处理,此时不表示 Collection 内的 Slice。即使混合请求中的所有名称都存在、请求成功,也不能据此认为结果包含 Collection 数据。
请求同时包含 Collection 与远端目标时也按混合请求处理。实例存在 Collection 时,不指定索引的 GET /_search 同样适用上述规则。默认跳过的是 Collection 逻辑入口的改写;全量或过宽的通配符查询仍会直接命中可见的 Backing,不能用它代替按 Collection 和 Slice 限定范围的查询。
需要同时读取两类数据时,请分开请求并由应用合并结果。