Files
border-red-post-nalati/docs/INDEX_API.md
T

82 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 文本切分与索引版本接口(T05)
本阶段保存可复核的已审核语料切分及发布指针,为后续检索索引提供版本边界。这里的“索引版本”是文本语料快照,不包含 Embedding、pgvector 向量字段/ANN 索引或 RRF。现有 `POST /api/retrieval` 仍运行原关键词基线,不读取这些 chunks;不能把本阶段称为向量检索已完成。
## 依赖、迁移与权限
分支 `feat/backend-chunk-index-versions` 叠加待审 PR #7(认证),并继承 PR #6(关键词)。三项须分别跟踪审阅;本分支不自行合并其他请求。升级时停止旧后端实例,安装依赖、备份并执行 `alembic upgrade head`,再启动新实例。所有实例必须使用当前版本,才能让目录写入遵守同一发布锁。
新增迁移 `0005_chunk_indexes`,依赖 `0004_auth_sessions`,创建:
- `index_versions`:切分配置、语料指纹、目录修订号、条目/chunk 数、构建人、构建时间及发布状态。
- `chunks`:所属版本、知识 ID、从 0 开始的片序、原文起止偏移、正文、UTF-8 内容 SHA-256 与出处快照。
- `index_state`:单例发布指针、发布代数 `generation`、目录修订号 `catalog_revision`。
- `index_publications`:每次发布的前后版本、代数、操作人和时间;重复发布当前版本不会新增记录。
迁移不改写既有知识、审核、用户、会话或检索记录,不创建初始发布版本。所有 `/api/indexes` 接口均要求 `admin`;POST 还必须携带有效 Cookie、明确 Origin 与 `X-CSRF-Token`,与 [认证契约](AUTH_API.md) 相同。
## 构建与原文切分
`POST /api/indexes` 创建一个 `ready` 版本,返回 201,不切换当前发布指针。请求可用默认值 `{}` 或:
```json
{"chunk_size": 500, "overlap": 80}
```
`chunk_size` 为 100–2000 个 Python Unicode 字符,默认 500;`overlap` 默认 80,非负且不得超过切分长度一半。自定义较短长度时也须指定兼容的重叠,例如 `{"chunk_size":100,"overlap":20}`。未知字段拒绝,不支持按类别单独发布。
固定算法 `unicode-window-v1` 从知识条目原正文位置 0 开始(不是关联文档或原网页的偏移),以 `chunk_size-overlap` 前进,末片到正文结束即停止。保留空白、全半角、组合字符和 Emoji,不标准化或截断原文。`start_offset` 包含起点,`end_offset` 不包含终点;每片 `text == 原文[start_offset:end_offset]`。标题放在出处信息中,不拼进正文偏移。客户端若使用 JavaScript 字符串偏移,须注意其 UTF-16 索引与 Python Unicode 字符偏移的区别。
- 语料条件与关键词基线共用:只读取未删除、审核及采集信息完整的 `verified` 知识,关联来源/文档须有效、归属及来源网址一致;pending/rejected 不进入构建。
- 语料指纹与关键词基线使用同一规范 JSON/算法,涵盖实际正文、标题、类别、出处及知识/父记录版本;切分参数独立保存在 `config`。
- 出处快照包含 `knowledge_id/knowledge_version`、可空 `document_id/document_version`、可空 `source_id/source_version/source_name`、`source_url/title/category`。以后原资料修改或失效,不改写旧 chunk 内容及出处。
- chunk ID 在一个版本内由版本 UUID、知识 ID 与顺序确定;新构建使用新版本 ID。相同资料及参数可重现偏移/正文/内容哈希,但新旧版本的 chunk ID 不相同。
- 本阶段同步构建,沿用最多 5000 条及标题/正文总计 200 万字符的语料限制,每版本另限 20000 个 chunks。超限返回 503;事务写入失败也完整回滚,不保留半个版本,不改变旧发布指针。
- 可以构建空语料版本,以便所有依据撤回后发布空快照;这不表示存在可用知识。
## 发布、过期与并发
先通过 `GET /api/indexes/active` 读取当前代数,再提交:
```text
POST /api/indexes/{version_id}/publish
```
```json
{"expected_generation": 0}
```
发布时锁定 `index_state`,检查代数、目录修订号及当前有效语料指纹;资料或审核已变化、代数过期均返回 409,要求重新构建或刷新。成功后同一事务把旧版本设为 `superseded`、新版本设为 `published`、切换指针、增加代数并追加发布记录。校验失败或写入失败保留此前全部发布状态。持有当前代数重复发布当前版本是无变化的 200;仍有效的历史版本可用最新代数重新发布,发布记录保留每次转换。
知识、来源、文档的应用写入在修改父记录前持有同一状态锁,事务内将 `catalog_revision` 增加一次;失败写入一起回滚修订号。构建、发布和这些写入串行,避免校验到提交之间发生目录修改。为首批小规模资料选择此保守策略,长构建会暂时阻塞管理写入;尚无后台任务或大规模增量索引。
任一成功目录写入都会使旧快照过期,包括尚未核验的新条目;此规则比只比较有效语料更保守。`GET /active` 同时核对修订号与实际语料指纹,返回:
```json
{"generation": 1, "catalog_revision": 2, "is_current": true, "active_version": {"id": "<版本 UUID>", "status": "published", "config": {"splitter":"unicode-window-v1","chunk_size":500,"overlap":80}, "...":"其余版本字段见 OpenAPI"}}
```
初始无发布时 `active_version=null/is_current=false`。资料变化后指针及历史保留,但 `is_current=false`;`published` 只表示仍是发布指针,不表示资料仍有效。历史 chunks 是当时的依据快照,不能绕过 `is_current` 直接用于后续正式检索。任何结果只描述该事务快照,之后的目录写入仍可让它过期。直接改库不属于支持的维护流程;额外指纹检查可发现绕过修订号的正文/出处变化,不能替代应用写锁。
## 查询与交接
| 接口 | 响应 |
|---|---|
| GET `/api/indexes` | 版本分页,构建时间降序,同时间按 ID |
| GET `/api/indexes/active` | 发布代数、目录修订号、当前性与当前版本 |
| GET `/api/indexes/publications` | 发布记录分页,代数降序 |
| GET `/api/indexes/{version_id}` | 版本元数据 |
| GET `/api/indexes/{version_id}/chunks` | chunk 分页;可按 `knowledge_id` 筛选,按知识 ID/片序排列 |
分页沿用 `{items,total,page,page_size}`,默认 20、最大 100。版本元数据完整字段为 `id/status/config/corpus_fingerprint/catalog_revision/item_count/chunk_count/created_by/created_at/published_at`;`published_at` 是最近一次发布的时间,逐次时间保存在发布记录。版本及发布记录时间统一输出 UTC ISO 8601,避免数据库时区让重读结果出现不同表示。chunk 字段为 `id/index_version_id/knowledge_id/ordinal/start_offset/end_offset/text/text_sha256/provenance`。
前端 `src/services/indexes.ts` 提供类型和调用封装,写入共用 Cookie/CSRF;未增加页面或假数据。接口新增需由前端按该契约接入、审阅并验收。独立 T05 Issue 因当前缺少 Gitea 写入认证仍待补建,本 PR 和任务板先保留实现与验证记录。
## 验证及回滚
验证包含真实 PostgreSQL 的原文重建与哈希、审核筛选、重复构建、过期拒绝、来源/文档更新、失败写入、发布历史、数据库锁竞争、失败构建/发布的真实约束回滚、迁移兼容及真实 HTTP 重启后指针/chunks 持久化。这里只使用占位资料,不是论文实验结果。Docker 和浏览器端验收保持待办。
备份后配合旧后端执行 `alembic downgrade 0004_auth_sessions`,只撤回这四张表,保留用户、会话、知识及检索记录;索引历史与 chunks 恢复依赖备份。旧应用不可使用新版本数据库混跑。
并发实现参考 [PostgreSQL 16 行锁说明](https://www.postgresql.org/docs/16/explicit-locking.html) 与 [SQLAlchemy FOR UPDATE](https://docs.sqlalchemy.org/en/20/core/selectable.html#sqlalchemy.sql.expression.Select.with_for_update)。