Skip to content

feat(dataset): add synonym management and search enhancement - #7558

Merged
c121914yu merged 3 commits into
labring:mainfrom
lean-zone:feat/dataset-synonyms
Sep 7, 2026
Merged

feat(dataset): add synonym management and search enhancement#7558
c121914yu merged 3 commits into
labring:mainfrom
lean-zone:feat/dataset-synonyms

Conversation

@lean-zone

@lean-zone lean-zone commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

This PR adds dataset-level synonym management and integrates synonym normalization into data indexing, retrieval, reranking, and citation metadata.

Each dataset can maintain one active synonym configuration. Synonym mappings are stored as versioned MongoDB snapshots and can be managed through JSON mappings or uploaded files.

Main changes

  • Add dataset synonym upload, update, download, delete, detail, and paginated mapping APIs.
  • Support CSV, XLSX, and XLS files:
    • The first column contains the standardized term.
    • Remaining columns contain its synonyms.
  • Add a synonym management page with configuration details, mapping search, pagination, and rebuild progress.
  • Add OpenAPI schemas and Simplified Chinese, Traditional Chinese, and English translations.
  • Preserve the original chunk content and indexes.text values.
  • Apply synonym replacement only to derived vector and full-text index inputs.
  • Normalize synonyms during:
    • Data creation
    • Data editing
    • System index rebuilding
    • Synonym configuration rebuilds
  • Expand retrieval queries without increasing the number of recall calls.
  • Include synonym mapping context in reranking inputs.
  • Include matched chunk-level synonymMappings in existing knowledge-base citation metadata.
  • Preserve existing behavior for datasets without an active synonym configuration.

Rebuild and consistency behavior

  • Store immutable, versioned mapping snapshots in MongoDB.
  • Use fileVersion to associate mappings with a complete configuration snapshot.
  • Only the current configuration snapshot is used at runtime; historical mapping versions are removed after a successful update.
  • A synonym update or deletion triggers a full text-scoped rebuild of existing dataset data.
  • Synonym rebuilds reuse the existing dataset rebuild queue and training structure.
  • Text-scoped rebuilds regenerate text indexes and full-text derived data while preserving existing image indexes and image embeddings.
  • The active synonym configuration becomes available immediately after the configuration transaction commits.
  • Rebuild processing is asynchronous, so mixed old/new vectors may exist temporarily. The system converges to the current synonym configuration after rebuild completion.
  • Mapping writes are split into bounded batches.
  • Existing dataset data is marked for rebuild in bounded batches outside the configuration transaction to avoid oversized transactions on large datasets.
  • If seed task creation fails after configuration commit, the affected data remains marked as rebuilding so the existing queue recovery and retry flow can continue.
  • If a rebuild queue encounters data whose collection no longer exists, it skips that item without deleting the underlying dataset data.
  • Concurrent synonym updates use configuration version checks and reject stale update requests.
  • Data writes retain synonym snapshot checks before committing derived indexes, but do not use dataset.updateTime as a dataset-wide write lock.

Permissions and billing

  • Read operations require dataset read permission.
  • Upload, update, and delete operations require dataset write permission.
  • Embedding work caused by synonym changes uses the existing dataset training billing pipeline.
  • Synonym rebuilds use the existing text rebuild scope and training task model.

Migration

A Mongo-only migration script is included:

pnpm --filter @fastgpt/app migrate:dataset-synonym-mongo-only

The script runs in dry-run mode by default. Pass --execute to apply changes.

The migration converts legacy synonym configuration and mapping data into the current schemaVersion=2 snapshot format and is designed to be safely rerunnable.

The migration should be run during downtime with application and worker processes stopped. Legacy S3 files are not deleted.

The new synonym APIs no longer use legacy S3 fileId or pendingFileId fields. Existing synonym data must be migrated before enabling the new implementation.

Limits and matching behavior

  • Maximum file size: 10 MiB
  • Maximum mappings: 10,000
  • Maximum terms: 50,000
  • Maximum term length: 128 Unicode code points
  • Maximum total term length: 500,000 Unicode code points
  • Longest matching term takes precedence.
  • English and numeric terms use case-insensitive word-boundary matching.
  • Chinese terms support continuous substring matching.
  • Replacement results are not matched recursively.
  • Conflicting mappings, cycles, and cross-group term reuse are rejected during normalization.

Verification

  • App TypeScript typecheck passed.
  • ESLint and Prettier checks passed.
  • Targeted Vitest suites cover:
    • Synonym parsing and normalization
    • Dataset search and reranking integration
    • Data creation and index rebuilding
    • Rebuild queue behavior
    • Synonym mutation and migration behavior

The local targeted Vitest run may require access to download the MongoDB binary used by mongodb-memory-server.

Design document

The detailed data model, matching rules, rebuild flow, migration strategy, and compatibility constraints are documented in:

.agents/design/core/dataset/synonym-feature-design.md

@cla-assistant

cla-assistant Bot commented Aug 20, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@cla-assistant

cla-assistant Bot commented Aug 20, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


zhanglin seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@c121914yu c121914yu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

混杂了知识库队列优化和同义词两个需求,需要单独拆分。并且现在改的队列方式也不是完全可靠的。
如果只是单独做同义词的话,简单复用现在队列就行,可以接受重构期间搜索有问题。

export const DatasetSynonymMappingCollectionName = 'dataset_synonym_mappings';
export const DatasetSynonymJobCollectionName = 'dataset_synonym_jobs';
export const DatasetSynonymOperationCollectionName = 'dataset_synonym_operations';
export const DatasetMutationLockCollectionName = 'dataset_mutation_locks';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不复用 training 表来预处理么

@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown

Build and publish successful - Preview fastgpt Image:

ghcr.io/labring/fastgpt-pr:fastgpt_07e6b763519c02b4ac038be996fb345a98d5e8e7

🕒 Time: 2026-09-07 10:16:33 (UTC+8)

@c121914yu

Copy link
Copy Markdown
Collaborator

这期建议先收敛范围,只实现同义词能力,不在这个 PR 里同时建设一套新的训练/重构队列。

具体调整建议:

  1. 同义词规则更新后直接生效,允许重构期间知识库中存在新旧 embedding 混合、召回短暂不一致。
  2. 复用现有 dataset_trainings 作为重构任务队列:遍历 data 的 q/a 和所有非图片 index,命中本次变化词的数据写入 training,由现有 worker 原地更新 embedding。
  3. 本期不引入同义词专用的幂等 saga、自动回退、active/pending 双版本和独立 mutation lock;失败任务继续使用 trainings 现有的重试/人工重触发能力。
  4. 重构期间先禁止再次修改同义词,避免两次规则更新互相覆盖。这个状态可以直接放在同义词配置记录里,不需要额外的 job/lock 集合。
  5. 原始 q/a/index text 保持不变,同义词转换只用于 embedding 输入,确保后续仍可按最新规则重新生成。

因此数据结构可以先简化为同义词配置/映射集合,加已有的 dataset_trainings。当前的 dataset_synonym_jobsdataset_synonym_operationsdataset_mutation_locks,以及版本切换和自动 rollback 逻辑建议从本期移除。

训练/重构队列的通用可靠性问题——例如任务幂等、租约续期、崩溃恢复、向量写入补偿、计费去重和统一进度模型——后续单独开需求统一优化,避免只为同义词做一套专用实现。

@c121914yu

Copy link
Copy Markdown
Collaborator

补充本次 review 发现的其他问题。即使按上一条建议简化方案,下面第一组仍需要处理。

简化后仍需修复

  1. 多知识库搜索可能丢失原始 query,导致未配置同义词的知识库召回下降

    packages/service/core/dataset/search/utils.ts:112 目前只在某个知识库存在 pending 时设置 preserveOriginal。例如同时搜索 A、B,只有 A 配置“退钱 -> 退款”时,最终会把“退钱”直接替换成“退款”,B 中只包含“退钱”的数据就无法按原词召回。

    多知识库联合搜索时,需要确认所有目标知识库都适合替换后才能删除原词;更简单的做法是只要搜索多个知识库就始终保留原词。按本期允许新旧 embedding 混合的方案,重构期间也必须保留原词。

  2. 直接 JSON API 接受纯空白词条

    packages/global/core/dataset/synonym.ts:210-212 的 schema 只使用 z.string()。文件上传路径会先 trim/filter,但 JSON mappings 可以传入 standardizedTerm: " " 或空白 synonym;之后 normalize 会得到空字符串,可能形成“词条映射为空输出”。

    建议在 API schema 和 normalize 后都保证 trim().min(1),synonym 数组中的每一项也需要校验。

  3. 标准词仅修改大小写时被误判为 unchanged

    packages/service/core/dataset/synonym/utils.ts:296-298 的 fingerprint 只包含 normalizedStandardizedTerm。例如标准输出从 OpenAI 改为 openai,实际 embedding/fulltext 输入已经变化,但 fingerprint 不变,不会标记相关数据重构。

    fingerprint 需要包含最终实际输出的 standardizedTerm;或者明确规定标准词大小写不影响输出并统一输出规范。

  4. 映射管理页最多只显示前 100 条

    projects/app/src/pageComponents/dataset/detail/Synonym/index.tsx:88-94 固定请求 pageNum: 1, pageSize: 100,但后端允许最多 10000 组,页面也没有翻页或继续加载,剩余映射不可见。需要接入分页组件或滚动加载,并使用接口返回的 total

  5. 动态 i18n key 无法被静态扫描

    projects/app/src/pageComponents/dataset/detail/Synonym/index.tsx:295 使用 t(\dataset:synonym.status_${currentJob.status}` as any)`,绕过了类型和静态 key 扫描。建议建立显式的 status -> i18n key 映射。

如果仍保留当前复杂队列方案,还存在以下阻塞问题

  1. 独占租约过期后 processing job 无法恢复

    projects/app/src/service/core/dataset/queues/synonym.ts:182-188 只会 renew,renew 又要求旧租约尚未过期。进程暂停超过 5 分钟后,所有 training 会持续失败;现有启动恢复只恢复 marking,不会为 processing/rollingBack job 重新 acquire 锁,最终 rollback 也会因旧锁失效而无法完成。

  2. rollback 与在途正向 worker 存在提交竞态

    packages/service/core/dataset/synonym/controller.ts:756-770 切换到 rollingBack 时没有撤销/递增 fencing token;而正向 worker 的 beforeCommit 只检查锁和 token,不检查 job 仍为 processing。已经领取任务的 worker 可以在 rollback 扫描之后继续提交 pendingVersion,导致回退遗漏数据。

  3. operation 信息落库失败会遗失新向量

    projects/app/src/service/core/dataset/data/data.ts:337-343onVectorsPrepared 位于向量写入之后、清理 try/catch 之外。如果 operation update 失败,刚写入的新 vector id 和 token 既不会被回收,也没有记录可供 reconciler 对账。

  4. collection sync 绕过 mutation gate

    projects/app/src/pages/api/core/dataset/collection/sync.ts:32 直接调用 syncCollection,而同步过程会替换 collection 并删除旧 data/training/vector。当前其他修改/删除入口增加了 mutation gate,但这里没有,可能与同义词扫描或 worker 并发破坏锁假设。

如果按上一条评论删除专用 operation、rollback 和 mutation lock,上述第二组不需要逐项修补;应随相关实现一起移除。

@lean-zone
lean-zone force-pushed the feat/dataset-synonyms branch 3 times, most recently from 707a1fd to 2bcc980 Compare August 28, 2026 01:39
@ctlaltlaltc

Copy link
Copy Markdown
Collaborator

导入和 rebuild 尽量简单、复用原结构。

但当前mutation 自己实现了配置锁、版本快照、全量扫描、批量入队、失败清理和 matcher 缓存。尤其训练队列方面,当前没有充分处理与原有训练任务并存的情况。mutation 复用了旧训练队列 worker,但没有完全复用旧的训练任务创建/rebuild 编排结构,保持精简

@lean-zone
lean-zone force-pushed the feat/dataset-synonyms branch 2 times, most recently from 1612d88 to 9e48fff Compare August 28, 2026 09:56
@c121914yu c121914yu self-assigned this Aug 28, 2026
@lean-zone
lean-zone force-pushed the feat/dataset-synonyms branch 6 times, most recently from 37726d7 to 6caadd7 Compare September 2, 2026 07:01
Comment thread packages/global/core/dataset/synonym.ts
Comment thread packages/global/core/dataset/constants.ts Outdated
Comment thread packages/global/openapi/core/dataset/synonym/api.ts
@lean-zone
lean-zone force-pushed the feat/dataset-synonyms branch 2 times, most recently from b73cfc9 to 66f9a46 Compare September 3, 2026 03:05
ctlaltlaltc
ctlaltlaltc previously approved these changes Sep 3, 2026
@lean-zone
lean-zone force-pushed the feat/dataset-synonyms branch 2 times, most recently from 6d52fad to 59322ef Compare September 4, 2026 03:15
@DigHuang
DigHuang force-pushed the feat/dataset-synonyms branch from 59322ef to 9e5cb33 Compare September 4, 2026 06:26
@DigHuang
DigHuang force-pushed the feat/dataset-synonyms branch 4 times, most recently from 56fd751 to fd0786e Compare September 4, 2026 09:39
@lean-zone
lean-zone force-pushed the feat/dataset-synonyms branch from fd0786e to d7c5d15 Compare September 5, 2026 03:07
@DigHuang
DigHuang force-pushed the feat/dataset-synonyms branch from d7c5d15 to c7232e8 Compare September 6, 2026 14:48
c121914yu
c121914yu previously approved these changes Sep 6, 2026

Copy link
Copy Markdown
Collaborator

风险点与推荐方案:隔离同义词重建和现有模型重建

基于当前提交 c7232e8f88427b689ca1bd9e6cdf28d73351b622,与 upstream/main 的共同基线对比。当前评审前提是:本期只保留后端能力,不正式上线,同义词开关默认关闭。页面等未交付内容不作为本次阻塞项;重点是不能回归已有业务。

已确认的现有逻辑回归

以下两个问题均为本 PR 新引入,并且关闭 DATASET_SYNONYM_ENABLED 也会触发。

1. [P1] 纯图片模型重建丢弃新的 VLM 描述

位置:generateVector.ts L270-L279

现有模型切换流程会将纯图片送入 imageParse。上游把 VLM 新描述写入 training.q,不会写入 imageDescMap。修改前使用 trainingData.q || datasetData.q;修改后只有存在 imageDescMap 才透传训练 Q/A,因此纯图片重建继续使用旧描述,并删除训练任务。

已对修改前后真实函数做隔离对比:同样传入“training.q 为新描述、data.q 为旧描述、无 imageDescMap”,基线向下游传新描述,PR 不传 q,最终使用旧描述,两者均删除任务。结果是 VLM 已执行并计费,但新描述没有生效。该问题影响已有数据的重建,不是首次图片入库。

2. [P2] 图文重建期间新生成的问题、摘要索引被遗漏

位置:generateVector.ts L281-L293

图文集合启用 autoIndexes 时,原有重建可以经过 image → auto → chunk,auto 阶段会往 training.indexes 追加新的 question/summary。修改前优先采用非空的训练索引;修改后从数据库当前索引出发,只补回训练结果里的 image,遗漏本次新生成的 question/summary

隔离对比确认基线透传新问题、摘要索引,PR 不再透传。保留数据库当前的用户编辑是合理的,但不能因此丢弃本次训练的新产物。

上游字段和流程已按本 PR 固定的 pro 子模块版本 14fe60ccd23df4264f2d88467fc207999db60715 核对,未用本地不同子模块版本推断。

推荐方案

区分两个 rebuild 的业务处理路径,可以复用现有训练队列和底层向量操作,但不要为了同义词需求改变原有模型重建的数据来源、训练产物合并和内容写回语义。

  • 模型切换重建:保留原有 VLM、图片向量、自动索引和训练产物写回行为。公共重构如确有必要,建议独立拆分验证。
  • 同义词重建:增加只重建文本派生索引的操作,不调用“更新 Q/A + 更新索引”的全量内容更新路径。

同义词重建的具体边界:

  1. 读取原始 indexes.text,在内存中做同义词转换,然后重新生成文本 embedding。
  2. 读取原始 Q/A,在内存中做同义词转换,然后按当前全文存储实现重新生成 fullText(Milvus 按现有向量行文本路径处理)。
  3. 不修改 Q/A、indexes.text、图片描述、内容历史;不重新执行 VLM、自动索引生成或图片 embedding。
  4. 仅更新派生向量、全文索引、新向量引用(如 indexes.dataId)及必要的重建版本/领取状态。不要把转换后的标准词文本覆盖回原始索引文本,否则删除规则后无法基于原文恢复。
  5. 并发校验和失败清理在这条独立路径内保证:不能覆盖并发编辑;不能把只完成部分索引更新的数据标成整条重建完成。

另外,当前普通数据更新的 CAS、重建种子任务事务边界、续接失败策略、训练 TTL 索引等修改也不受功能开关隔离。这些不都等于缺陷,但不能以“同义词未上线”为由认定无影响;建议尽量收窄公共链路改动。

验证与验收建议

已运行两轮定向测试,共 11 个文件、163 条用例通过;另通过只读函数隔离对比确认上述两处回归。未运行全量测试或真实外部模型端到端测试。

合并前至少补充:

  • 同义词关闭时,纯图片模型重建仍使用新 VLM 描述。
  • 同义词关闭时,图文 + autoIndexes 重建保留本次新生成的问题、摘要索引。
  • 同义词重建前后 Q/A、原始索引文本、图片描述及图片向量保持不变,只有文本派生索引和必要状态更新。
  • 普通无同义词配置的数据入库、编辑、搜索和模型重建行为保持兼容。

此前发现的同义词专属风险(部分更新提前推进版本、队列为空后的版本差异恢复、转换后超 token 上限导致截断)可作为未上线能力的后续验收项,但上述两处已有业务回归建议本 PR 内解决。

@DigHuang
DigHuang force-pushed the feat/dataset-synonyms branch from eb46587 to 9806a4a Compare September 7, 2026 02:04
@DigHuang
DigHuang force-pushed the feat/dataset-synonyms branch from 9806a4a to 07e6b76 Compare September 7, 2026 02:08
@c121914yu
c121914yu merged commit a4891c8 into labring:main Sep 7, 2026
16 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants