AI 数据清洗接口.md 35 KB

AI 数据清洗接口

**本文引用的文件 **

  • AiCleanController.java
  • AiCleanSynonymController.java
  • CleanErrorLogController.java
  • AiCleanService.java
  • AiCleanSynonymService.java
  • AiCleanTemplateVectorIndex.java
  • AiCleanStatusEnum.java
  • AiCleanExitEnum.java
  • AiCleanStageEnum.java
  • AiRejectReason.java
  • CleanErrorLog.java
  • CleanErrorLogQuery.java
  • ai_clean.sql
  • ai_clean_synonym_init.sql

目录

  1. 简介
  2. 项目结构与接口范围
  3. 核心组件与数据流
  4. 接口总览
  5. /aiClean 智能清洗接口
  6. /aiClean/synonym 同义词接口
  7. /cleanLog CleanErrorLogController 错误日志接口
  8. 清洗流程与 pgvector、DuckDB 的关系
  9. 失败定位与排查指南
  10. 性能与限制
  11. 结论

简介

本文件说明 AI 数据清洗链路的 REST 接口,覆盖:

  • /aiClean:AI 清洗任务提交、执行、撤销、行拒绝明细、动态表分页、模板向量索引状态与重建。
  • /aiClean/synonym:表头同义词库的查询、新增、修改、删除、启用/停用。
  • /cleanLog(由 CleanErrorLogController 暴露):清洗错误日志分页查询。

这些接口共同支撑以下能力:

  • 上传 CSV/Excel 后,对未匹配既有模板的 sheet 进行 AI 判定和清洗。
  • 将命中既有模板的数据走原有清洗链路,把没有合适模板的数据写入 AI 动态表。
  • 用 pgvector 维护模板语义向量索引,辅助模板候选召回。
  • 用 DuckDB 临时数据源完成结构探测、列类型推断、规则试跑与批量清洗。
  • 记录每行的清洗拒绝原因,并通过错误日志表辅助定位问题。

项目结构与接口范围

AI 清洗相关接口集中在三个控制器中:

  • AiCleanController:挂在 /aiClean,是独立于 /dm、/govern 的新链路。
  • AiCleanSynonymController:挂在 /aiClean/synonym,管理评分归一用的词对。
  • CleanErrorLogController:挂在 /cleanLog,提供清洗错误日志分页查询。

    graph TB
    Client["前端或外部调用方"] --> AC["AiCleanController<br/>/aiClean/*"]
    Client --> ASC["AiCleanSynonymController<br/>/aiClean/synonym/*"]
    Client --> CEL["CleanErrorLogController<br/>/cleanLog/list"]
    
    AC --> ACS["AiCleanService"]
    AC --> TVI["AiCleanTemplateVectorIndex"]
    AC --> JOB["AiCleanJobMapper<br/>ai_clean_job"]
    
    ASC --> ASS["AiCleanSynonymService"]
    ASS --> DB["PostgreSQL<br/>ai_clean_synonym"]
    
    CEL --> ELQ["CleanErrorLogQuery"]
    ELQ --> ELM["CleanErrorLogMapper<br/>clean_error_log"]
    
    subgraph "AI 清洗存储"
        JOB
        DB
        ELM
    end
    

图示来源

  • AiCleanController.java:1-138
  • AiCleanSynonymController.java:1-70
  • CleanErrorLogController.java:1-30

章节来源

  • AiCleanController.java:1-138
  • AiCleanSynonymController.java:1-70
  • CleanErrorLogController.java:1-30

核心组件与数据流

控制器层

组件 职责
AiCleanController 暴露智能清洗任务提交、同步执行、任务列表、撤销、拒绝明细、动态表分页、模板向量索引状态与重建接口。
AiCleanSynonymController 暴露同义词词条列表、创建、更新、删除、启用/停用接口。
CleanErrorLogController 暴露清洗错误日志分页查询接口。

服务层

组件 职责
AiCleanService 实现 S1→S7 主流程:探测结构、匹配模板、生成规则、校验置信度、走既有链路或写 AI 动态表、记录任务与拒绝明细。
AiCleanSynonymService 管理 ai_clean_synonym 表,校验“同一归一化词全局唯一”“不做链式传递”,并在事务提交后重建全局缓存。
AiCleanTemplateVectorIndex 把既有模板和 AI 模板的结构元数据嵌入为向量,写入 pgvector 表,供模板语义召回与 Agent 选表使用。

数据层

表 用途
ai_clean_template AI 模板定义,含中文名、物理表名、表头指纹、分类、版本、置信度等。
ai_clean_field AI 模板字段,决定 DuckDB 动态表 DDL 与前端展示列。
ai_clean_rule 清洗函数链快照,以枚举 hint JSON 形式保存。
ai_clean_job 单个 sheet/block 的清洗任务轨迹,含状态、出口、token 成本、行统计、失败原因。
ai_clean_batch 智能清洗批次状态机:JUDGING → CLEANING_EXISTING → LOADING_AI → DONE/PARTIAL。
ai_clean_synonym 表头同义词库,用于评分归一和绑定域映射。
clean_error_log 清洗失败的错误日志,按 batchId/fileId/sheetId 等过滤。

章节来源

  • AiCleanService.java:1-260
  • AiCleanSynonymService.java:1-178
  • AiCleanTemplateVectorIndex.java:1-220
  • ai_clean.sql:1-214
  • ai_clean_synonym_init.sql:1-42

接口总览

/aiClean

HTTP 方法 URL 主要参数 响应体 说明
POST /aiClean/submit fileId Result<Integer> 为未匹配模板的 sheet 建 AI 清洗任务,幂等。
POST /aiClean/run jobId Result<AiCleanJob> 同步执行一个清洗任务。
GET /aiClean/jobs fileId(可选) Result<List<AiCleanJob>> 当前案件下的任务列表。
POST /aiClean/revert jobId Result<Long> 撤销该 job 在 AI 动态表中的数据。
GET /aiClean/job/rejections jobId、reason(可选)、page、size Result<Map<String,Object>> 分页返回行级拒绝明细。
GET /aiClean/data/page aiTemplateId、orderKey(可选)、asc、page、size Result<Map<String,Object>> 分页读取 AI 动态表数据。
POST /aiClean/refreshTree 无或任意 body Result<Void> 刷新当前案件的 AI 治理树节点。
GET /aiClean/templateVector/status 无 Result<IndexStatus> 查看向量索引是否可用、维度、文档数。
POST /aiClean/templateVector/rebuild 无 Result<Integer> 全量重建模板向量索引。

/aiClean/synonym

HTTP 方法 URL 请求体 响应体 说明
GET /aiClean/synonym/list 无 Result<List<AiCleanSynonym>> 列出全部词条,含停用。
POST /aiClean/synonym/create AiCleanSynonym Result<AiCleanSynonym> 新增词对。
POST /aiClean/synonym/update AiCleanSynonym Result<AiCleanSynonym> 修改词对。
POST /aiClean/synonym/delete {id} Result<Void> 删除词对。
POST /aiClean/synonym/toggle {id, status} Result<Void> 启用或停用词条。

/cleanLog

HTTP 方法 URL 查询参数 响应体 说明
GET /cleanLog/list id、batchId、fileId、sheetId、page、limit Result<Page<CleanErrorLog>> 分页查询清洗错误日志。

章节来源

  • AiCleanController.java:39-138
  • AiCleanSynonymController.java:26-70
  • CleanErrorLogController.java:15-30

/aiClean 智能清洗接口

POST /aiClean/submit

为上传文件中尚未匹配到既有模板的 sheet 创建 AI 清洗任务。

  • HTTP 方法:POST
  • URL:/aiClean/submit
  • 请求参数:
    • fileId:必填,Long,表示已上传文件的根记录 id。
  • 请求方式:表单参数。
  • 响应体:Result<Integer>,表示新建的任务数量。
  • 行为:

    • 查找 pid=fileId 且未绑定模板的 sheet。
    • 若某个 sheet 已有对应任务,则跳过;并发重复提交会因唯一键冲突被忽略。
    • 新任务初始状态为 PENDING。

      sequenceDiagram
      participant FE as "前端"
      participant Ctrl as "AiCleanController"
      participant Svc as "AiCleanService"
      participant Job as "ai_clean_job"
      
      FE->>Ctrl: POST /aiClean/submit?fileId=xxx
      Ctrl->>Svc: submitUnmatched(caseId, fileId)
      Svc->>Job: 插入 PENDING 任务
      Job-->>Svc: 成功或唯一键冲突
      Svc-->>Ctrl: 新建任务数
      Ctrl-->>FE: Result<Integer>
      

图示来源

  • AiCleanController.java:52-63
  • AiCleanService.java:118-156
  • ai_clean.sql:110-148

调用示例

  • curl:

    curl -X POST "http://host/aiClean/submit?fileId=123"
    
  • 前端 FormData:

    const fd = new FormData()
    fd.append('fileId', '123')
    fetch('/aiClean/submit', { method: 'POST', body: fd })
    

常见错误

  • fileId 不存在:不会创建任务,返回新建数为 0。
  • 并发重复提交:只记录一次任务,不重复计数。

章节来源

  • AiCleanController.java:52-63
  • AiCleanService.java:118-156
  • ai_clean.sql:110-148

POST /aiClean/run

同步执行一个 AI 清洗任务。模型调用可能耗时数秒,批量场景应轮询任务列表而非逐个等待。

  • HTTP 方法:POST
  • URL:/aiClean/run
  • 请求参数:
    • jobId:必填,Long。
  • 响应体:Result<AiCleanJob>,包含状态、出口、置信度、token 成本、行统计、失败原因等。
  • 权限:内部通过 caseAccessGuard 校验任务归属当前案件。

    sequenceDiagram
    participant FE as "前端"
    participant Ctrl as "AiCleanController"
    participant Svc as "AiCleanService"
    participant Job as "ai_clean_job"
    
    FE->>Ctrl: POST /aiClean/run?jobId=xxx
    Ctrl->>Svc: run(jobId)
    Svc->>Svc: 探测结构、匹配模板、生成规则、校验
    alt 命中既有模板
        Svc->>Svc: 走既有 doClean
        Svc->>Job: 标记 DISPATCHED_A 或 A2/A3
    else 无模板
        Svc->>Svc: 写 AI 动态表
        Svc->>Job: 标记 LOADING/SUCCESS
    end
    Svc-->>Ctrl: AiCleanJob
    Ctrl-->>FE: Result<AiCleanJob>
    

图示来源

  • AiCleanController.java:65-71
  • AiCleanService.java:198-230
  • AiCleanExitEnum.java:1-56

调用示例

  • curl:

    curl -X POST "http://host/aiClean/run?jobId=456"
    

失败处理

  • 异常时任务状态设为 FAIL,并记录最多 900 字符的失败原因。

章节来源

  • AiCleanController.java:65-71
  • AiCleanService.java:198-230
  • AiCleanStatusEnum.java:1-76

GET /aiClean/jobs

查询当前案件下的 AI 清洗任务列表,可按 fileId 过滤。

  • HTTP 方法:GET
  • URL:/aiClean/jobs
  • 请求参数:
    • fileId:可选,Long。
  • 响应体:Result<List<AiCleanJob>>。
  • 排序:按创建时间倒序。
  • 权限:跨案件读取会被拒绝。

章节来源

  • AiCleanController.java:73-82
  • ai_clean.sql:110-148

POST /aiClean/revert

撤销某个 job 对应的 AI 动态表数据。

  • HTTP 方法:POST
  • URL:/aiClean/revert
  • 请求参数:
    • jobId:必填,Long。
  • 响应体:Result<Long>。

章节来源

  • AiCleanController.java:84-87

GET /aiClean/job/rejections

分页获取某个 job 的行级失败明细。

  • HTTP 方法:GET
  • URL:/aiClean/job/rejections
  • 请求参数:
    • jobId:必填,Long。
    • reason:可选,String,按拒绝原因过滤。
    • page:默认 1。
    • size:默认 20。
  • 响应体:Result<Map<String, Object>>,结构包含分页字段 records、total、size、current;每条记录包含行号、阻塞列、原因、原值预览、该行全部列错误信息。
  • 权限:跨案件查询会被拒绝。

拒绝原因枚举 | 原因 | 含义 | 是否整行拒绝 | |---|---|---| | REQUIRED_EMPTY | 必填列为空 | 是 | | REQUIRED_TYPE_INVALID | 必填列类型解析失败 | 是 | | REQUIRED_FUNC_ERROR | 必填列清洗函数执行异常 | 是 | | REQUIRED_LENGTH_OVERFLOW | 必填列超长或精度溢出 | 是 | | OPTIONAL_TYPE_INVALID | 非必填列类型不合法,单元格置空 | 否 | | OPTIONAL_FUNC_ERROR | 非必填列函数执行失败,单元格置空 | 否 | | OPTIONAL_LENGTH_OVERFLOW | 非必填列超长或精度溢出,单元格置空 | 否 | | WRITER_ERROR | 写入数据库失败 | 是 |

flowchart TD
    Start["进入 rejections"] --> LoadJob["加载 job"]
    LoadJob --> CheckCase["校验案件归属"]
    CheckCase --> BuildQuery["构建分页查询"]
    BuildQuery --> FilterReason{"是否指定 reason?"}
    FilterReason -->|是| ApplyReason["按 AiRejectReason 过滤"]
    FilterReason -->|否| SkipReason["不过滤"]
    ApplyReason --> Page["分页取数"]
    SkipReason --> Page
    Page --> MapRows["映射为 records + total + size + current"]
    MapRows --> Return["返回 Result<Map<String,Object>>"]

图示来源

  • AiCleanController.java:89-100
  • AiRejectReason.java:1-49

调用示例

  • curl:

    curl "http://host/aiClean/job/rejections?jobId=456&reason=REQUIRED_TYPE_INVALID&page=1&size=20"
    

章节来源

  • AiCleanController.java:89-100
  • AiRejectReason.java:1-49

GET /aiClean/data/page

分页读取 AI 动态表数据,治理树上 id<0 的节点通常走此接口。

  • HTTP 方法:GET
  • URL:/aiClean/data/page
  • 请求参数:
    • aiTemplateId:必填,Long,指向 ai_clean_template.id。
    • orderKey:可选,String,排序列键。
    • asc:默认 true,Boolean,升序或降序。
    • page:默认 1。
    • size:默认 20。
  • 响应体:Result<Map<String, Object>>,结构类似治理树分页,包含 records、total、size、current。

章节来源

  • AiCleanController.java:102-110

POST /aiClean/refreshTree

手动重建当前案件的 AI 治理节点,幂等。

  • HTTP 方法:POST
  • URL:/aiClean/refreshTree
  • 请求体:可选,任意字符串 body。
  • 响应体:Result<Void>。

章节来源

  • AiCleanController.java:112-116

GET /aiClean/templateVector/status

查看 AI 模板向量索引状态。

  • HTTP 方法:GET
  • URL:/aiClean/templateVector/status
  • 响应体:Result<IndexStatus>,可观测是否可用、使用的嵌入模型、向量维度、当前文档数。

章节来源

  • AiCleanController.java:118-123
  • AiCleanTemplateVectorIndex.java:1-220

POST /aiClean/templateVector/rebuild

全量重建 AI 模板向量索引。

  • HTTP 方法:POST
  • URL:/aiClean/templateVector/rebuild
  • 响应体:Result<Integer>,表示实际写入的文档数。
  • 说明:
    • 适用于存量模板补建、更换嵌入模型后维度变化导致旧向量表不可用。
    • 同步执行;模板量级通常为几百到几千,首次或换模型时才需要。
    • 调用方应按接口超时预期处理。

章节来源

  • AiCleanController.java:125-138
  • AiCleanTemplateVectorIndex.java:1-220

/aiClean/synonym 同义词接口

GET /aiClean/synonym/list

列出全部同义词词条,包括停用的,按标准词排序。

  • HTTP 方法:GET
  • URL:/aiClean/synonym/list
  • 响应体:Result<List<AiCleanSynonym>>。

章节来源

  • AiCleanSynonymController.java:37-41
  • AiCleanSynonymService.java:47-63

POST /aiClean/synonym/create

新增词对。

  • HTTP 方法:POST
  • URL:/aiClean/synonym/create
  • 请求体:AiCleanSynonym,至少包含 stdWord、aliasWord、remark,可选 status。
  • 响应体:Result<AiCleanSynonym>。
  • 校验规则:

    • 标准词与别名不能为空。
    • 标准词与别名不能相同。
    • 同一归一化词在全表只能出现一次,避免歧义。
    • 不做链式传递:别名必须直接指向标准词。
    • 若无 createBy,自动填充当前用户。

      flowchart TD
      Start["接收 AiCleanSynonym"] --> Trim["去除首尾空白"]
      Trim --> Validate["校验 stdWord/aliasWord 非空且不等于"]
      Validate --> Unique{"全局唯一?"}
      Unique -->|否| Error["抛出 ServerException"]
      Unique -->|是| Insert["插入 ai_clean_synonym"]
      Insert --> Refresh["事务提交后重建 GlobalCache"]
      Refresh --> Return["返回 Result<AiCleanSynonym>"]
      

图示来源

  • AiCleanSynonymController.java:43-51
  • AiCleanSynonymService.java:65-86

调用示例

  • curl:

    curl -X POST "http://host/aiClean/synonym/create" \
    -H "Content-Type: application/json" \
    -d '{"stdWord":"交易金额","aliasWord":"发生额","remark":"自定义映射"}'
    
  • 前端 FormData:

    const fd = new FormData()
    fd.append('stdWord', '交易金额')
    fd.append('aliasWord', '发生额')
    fd.append('remark', '自定义映射')
    fetch('/aiClean/synonym/create', { method: 'POST', body: fd })
    

章节来源

  • AiCleanSynonymController.java:43-51
  • AiCleanSynonymService.java:65-86
  • ai_clean_synonym_init.sql:1-42

POST /aiClean/synonym/update

修改词对。

  • HTTP 方法:POST
  • URL:/aiClean/synonym/update
  • 请求体:AiCleanSynonym,id 必填,其他字段按需更新。
  • 响应体:Result<AiCleanSynonym>。
  • 行为:更新后重建全局缓存,改词即时生效,无需重启。

章节来源

  • AiCleanSynonymController.java:53-59
  • AiCleanSynonymService.java:88-114

POST /aiClean/synonym/delete

删除词对。

  • HTTP 方法:POST
  • URL:/aiClean/synonym/delete
  • 请求体:{id}。
  • 响应体:Result<Void>。

章节来源

  • AiCleanSynonymController.java:61-66
  • AiCleanSynonymService.java:116-123

POST /aiClean/synonym/toggle

启用或停用词条。

  • HTTP 方法:POST
  • URL:/aiClean/synonym/toggle
  • 请求体:{id, status}。
  • 响应体:Result<Void>。
  • 说明:停用词条仍保留在表中,但不再参与评分和绑定域。

章节来源

  • AiCleanSynonymController.java:68-70
  • AiCleanSynonymService.java:125-142

/cleanLog CleanErrorLogController 错误日志接口

GET /cleanLog/list

分页查询清洗错误日志。

  • HTTP 方法:GET
  • URL:/cleanLog/list
  • 查询参数:
    • id:可选,Long,按日志主键过滤。
    • batchId:可选,Long,按智能清洗批次过滤。
    • fileId:可选,Long,按文件过滤。
    • sheetId:可选,Long,按 sheet 过滤。
    • page、limit:来自父类 Query,MyBatis-Plus 分页参数。
  • 响应体:Result<Page<CleanErrorLog>>。
  • 排序:按 createDateTime 升序。

实体字段 | 字段 | 类型 | 说明 | |---|---|---| | id | Long | 主键。 | | fileId | Long | 文件 id。 | | sheetId | Long | sheet id。 | | batchId | Long | 智能清洗批次 id。 | | fileName | String | 文件名。 | | sheetName | String | sheet 名称。 | | content | String | 错误内容。 | | createDateTime | LocalDateTime | 创建时间。 |

classDiagram
    class CleanErrorLogController {
        +list(query)
    }

    class CleanErrorLogQuery {
        +id
        +batchId
        +fileId
        +sheetId
    }

    class CleanErrorLog {
        +id
        +fileId
        +sheetId
        +batchId
        +fileName
        +sheetName
        +content
        +createDateTime
    }

    CleanErrorLogController --> CleanErrorLogQuery : "接收查询参数"
    CleanErrorLogController --> CleanErrorLog : "返回分页结果"

图示来源

  • CleanErrorLogController.java:15-30
  • CleanErrorLogQuery.java:1-14
  • CleanErrorLog.java:1-41

调用示例

  • curl:

    curl "http://host/cleanLog/list?batchId=100&fileId=123&page=1&limit=20"
    

章节来源

  • CleanErrorLogController.java:15-30
  • CleanErrorLogQuery.java:1-14
  • CleanErrorLog.java:1-41

清洗流程与 pgvector、DuckDB 的关系

整体流程

AI 清洗主流程由 AiCleanService 驱动,大致分为:

  1. 探测 sheet 结构,提取表头、表块。
  2. 使用指纹、打分、同义词和 LLM 匹配既有模板或生成 AI 模板。
  3. 根据出口决定数据去向:
    • 出口 A/A2:走既有 doClean,写入业务表。
    • 出口 A3/B:新建 AI 模板和 DuckDB 动态表,写入 ai_clean_{id}。
  4. 记录任务状态、token 成本、行统计、拒绝原因。
  5. 通过 /aiClean/job/rejections 和 /cleanLog/list 暴露失败细节。

    flowchart TD
    Upload["上传 CSV/Excel"] --> Probe["结构探测<br/>SheetProbe"]
    Probe --> Match["模板匹配<br/>HeaderScorer + HeaderFingerprint + LLM"]
    Match --> Decision{"命中既有模板?"}
    Decision -->|是| Existing["出口 A/A2/A3<br/>既有业务表或降级 AI 表"]
    Decision -->|否| NewTpl["出口 B<br/>新建 AI 模板 + DuckDB 动态表"]
    Existing --> Stats["记录任务统计"]
    NewTpl --> Stats
    Stats --> Rejects["记录行级拒绝"]
    Rejects --> Log["写入 clean_error_log"]
    

图示来源

  • AiCleanService.java:1-260
  • AiCleanExitEnum.java:1-56
  • ai_clean.sql:1-214

pgvector 的作用

AiCleanTemplateVectorIndex 负责把既有模板和 AI 模板的结构元数据嵌入为向量,写入 pgvector 表。它的作用是:

  • 为模板语义召回提供候选集合。
  • 为 Agent 的 search_table_schema 工具提供自然语言选表能力。
  • 启动时可自举重建;也可通过 /aiClean/templateVector/rebuild 手动触发。
  • 向量索引不可用时走 fail-open:不阻断模板指纹、打分、LLM 主链路。

    graph TB
    Tpl["ai_clean_template / table_info"] --> Embed["EmbeddingProvider"]
    Embed --> PgVec["pgvector 表<br/>rag_tpl_d{dims}"]
    PgVec --> Recall["模板候选召回"]
    PgVec --> Agent["Agent 选表"]
    

图示来源

  • AiCleanTemplateVectorIndex.java:1-220
  • ai_clean.sql:1-60

DuckDB 的作用

DuckDB 作为本地临时数据源,承担:

  • 结构探测:读取原始 CSV/Excel,识别表头、合并单元格、多表块。
  • 列类型推断:根据采样数据推断字段类型。
  • 规则试跑:用清洗函数链验证模板可信度。
  • 批量清洗:将清洗后的数据写入 AI 动态表或既有业务表。

    graph TB
    File["CSV/Excel 文件"] --> Loader["AiDuckDb / 数据加载器"]
    Loader --> Schema["推断 DuckDB 表结构"]
    Schema --> Verify["规则校验与置信度评估"]
    Verify --> Writer["写入 AI 动态表或既有表"]
    

图示来源

  • AiCleanService.java:1-260

章节来源

  • AiCleanService.java:1-260
  • AiCleanTemplateVectorIndex.java:1-220
  • ai_clean.sql:1-214

失败定位与排查指南

模板不匹配

现象

  • 任务状态长期停留在 MATCHING 或 NEED_REVIEW。
  • 出口不是 A/A2,而是 B 或待人工确认。

排查步骤

  1. 调用 /aiClean/templateVector/status,确认向量索引是否可用。
  2. 若向量索引不可用,调用 /aiClean/templateVector/rebuild 重建。
  3. 检查同义词配置是否遗漏必要映射。
  4. 观察 detail、confidence、model_name、llm_calls 字段,判断是否需要人工调整模板。

章节来源

  • AiCleanController.java:118-138
  • AiCleanTemplateVectorIndex.java:1-220
  • AiCleanStatusEnum.java:1-76

字段映射错误

现象

  • 行级拒绝中出现 REQUIRED_TYPE_INVALID、OPTIONAL_TYPE_INVALID、REQUIRED_LENGTH_OVERFLOW 等。
  • 部分列被置空,或整行被拒绝。

排查步骤

  1. 调用 /aiClean/job/rejections?jobId=xxx,查看具体行号和列错误。
  2. 根据 AiRejectReason.label() 理解中文错误描述。
  3. 检查 ai_clean_field 中的 field_type、field_len、required 是否与真实数据一致。
  4. 如需修正字段映射,重新生成模板或人工确认。

章节来源

  • AiCleanController.java:89-100
  • AiRejectReason.java:1-49
  • ai_clean.sql:60-110

任务失败

现象

  • 任务状态为 FAIL,failReason 有失败原因。
  • 智能清洗批次最终为 PARTIAL 或 FAILED。

排查步骤

  1. 查看 /aiClean/jobs 中该 job 的 status、exit_code、fail_reason。
  2. 查看智能清洗批次阶段:JUDGING、CLEANING_EXISTING、LOADING_AI。
  3. 若失败发生在既有链路,检查业务表写入逻辑。
  4. 若失败发生在 AI 动态表写入,检查 DuckDB 临时数据和 clean_error_log。

章节来源

  • AiCleanStatusEnum.java:1-76
  • AiCleanStageEnum.java:1-52
  • ai_clean.sql:148-214

向量索引异常

现象

  • /aiClean/templateVector/status 显示不可用。
  • 模板语义召回结果为空。
  • 重建接口长时间无响应或报错。

排查步骤

  1. 确认 pgvector 扩展已安装,向量模型已配置。
  2. 调用 /aiClean/templateVector/status 查看 unavailable 原因。
  3. 调用 /aiClean/templateVector/rebuild 全量重建。
  4. 观察应用日志,向量索引构建过程是 fail-open,失败不会阻断上传和清洗主流程。

章节来源

  • AiCleanTemplateVectorIndex.java:1-220
  • AiCleanController.java:118-138

错误日志定位

建议顺序

  1. 先通过 /aiClean/job/rejections 定位具体 job 的具体行。
  2. 再通过 /cleanLog/list 按 batchId、fileId、sheetId 拉取更宽的错误日志。
  3. 结合 ai_clean_job 的状态、出口、token 成本和失败原因综合判断。
  4. 如果是同义词影响评分,检查 /aiClean/synonym/list 是否缺少必要映射。

章节来源

  • CleanErrorLogController.java:15-30
  • CleanErrorLogQuery.java:1-14
  • CleanErrorLog.java:1-41

性能与限制

  • /aiClean/run 是同步接口,模型调用可能耗时数秒,批量场景应轮询 /aiClean/jobs。
  • /aiClean/templateVector/rebuild 是全量重建,适合首次上线或换嵌入模型时使用。
  • 同义词变更通过事务提交后重建全局缓存,避免重启,但缓存重建失败仅记日志,不影响主流程。
  • 向量索引构建失败采用 fail-open,不会阻断上传、模板匹配和数据清洗。
  • 行级拒绝默认只打前 N 条应用日志,完整明细在 ai_clean_reject 表和 /aiClean/job/rejections 中。

[本节为通用性能说明,不直接分析特定代码文件]

结论

AI 数据清洗接口通过 /aiClean、/aiClean/synonym 和 /cleanLog 三条路径,分别承担智能清洗任务控制、表头同义词管理和清洗错误日志查询职责。系统以 PostgreSQL 作为持久化主库,以 DuckDB 作为临时计算引擎,以 pgvector 作为模板语义索引后端。对外暴露的分页字段统一遵循 records、total、size、current 约定,错误定位则依赖 AiCleanJob、ai_clean_batch、ai_clean_reject 和 clean_error_log 四类数据。