1. 文档定位
本文说明 DGJ2.0 内部帮助业务的四套能力:用户问答、标准题库、结构化知识库、七鱼机器人知识读取,并补充 Elasticsearch 索引和 Excel 导入。它服务于服务站自助查询、OPS 审核、客服复用和机器人回答。
这里的“知识库”是 DGJ2 产品功能,不等于 jb2ai.ltd 统一知识地图。前者是业务运行数据,后者是项目研发文档入口。
2. 业务边界
2.1 包含
- 老帮助中心兼容入口。
- 新版问题、回答、审核、采纳和删除。
- 已采纳回答转标准题库。
- 题库新增、编辑、启停、FAQ、搜索和 Excel 导入。
- ES 索引创建、增删改同步和搜索回表。
- 知识分类树、列表、详情、收藏。
- 七鱼机器人知识分类和列表读取。
- 状态、权限、表关系、异常、重建索引和回归。
2.2 不包含
- DGJ2 RobotV2 会话、Intent 和 AI 控制台,见第 39 篇。
- Udesk 人工客服接管。
jb2ai.ltd文档发布和统一知识地图治理。- 七鱼后台的生产知识编辑、审核和训练机制。
3. 四套内容模型
| 内容域 | 主表/来源 | 生产者 | 使用者 | 是否进入 DGJ2 ES |
|---|---|---|---|---|
| 用户问答 | t_help_question、t_help_answer | 服务站、OPS 回答者 | 全部/我的问答 | 是,问题索引 |
| 标准题库 | t_help_question_lib | OPS 手工、导入、回答转题库 | 搜索、FAQ | 是,独立题库索引 |
| 结构化知识库 | t_knowledge* | 后台同步/初始化 | 分类、列表、详情、收藏 | 当前 Service 未见复用 Help ES |
| 七鱼机器人知识 | 七鱼外部接口 | 七鱼后台 | DGJ2 读取分类和列表 | 由七鱼负责检索 |
flowchart LR
U[服务站提问] --> Q[用户问题]
A[回答者] --> R[候选回答]
Q --> R
R --> C{审核/采纳}
C -->|采纳| B[最佳答案]
B --> T[转标准题库]
T --> E2[题库ES]
Q --> E1[问题ES]
K[结构化知识库] --> KC[分类/收藏]
Y[七鱼知识] --> YR[机器人读取]
4. 入口地图
| 模块 | Controller | 主要方法 |
|---|---|---|
| 老帮助中心 | help/Dgj.php | commonProblem、productKnowledge、ask、search、questionDetail、myQuestion、myAnswer |
| 新问题 | newhelp/Question.php | allList、myList、info、modules、create、update、delete |
| 新回答 | newhelp/Answer.php | allList、myList、info、create、update、delete、remark、check |
| 题库 | newhelp/QuestionLib.php | search、faq、info、create、update、delete、status、transform、import |
| 结构化知识库 | knowledge/Knowledge.php | getCategoryTree、getKnowledgeList、getCollectKnowledgeList、getKnowledgeInfo、collectKnowledge |
| 旧 QA | qa/Qa.php | 历史问答入口 |
5. Service 地图
| Service | 职责 |
|---|---|
HelpBaseService | 模型初始化、可写字段、状态映射、输出格式 |
HelpQuestionService | 问题列表、创建、编辑、删除、详情 |
HelpAnswerService | 新版回答列表、审核/采纳等 |
AnswerService | 老回答提交兼容 |
HelpLibService | 题库 CRUD、FAQ、启停、转题库 |
HelpCacheEsSer | 问题/题库 ES 增删改查 |
ExcelService | 题库上传、模板、错误文件和下载 |
KnowledgeSer | 分类树、内容、收藏和初始化 |
QiYuRobotKnowledgeSer | 七鱼分类/知识列表适配 |
6. 核心表
| 表 | 关键键 | 作用 | 重要字段 |
|---|---|---|---|
t_help_question | id、sid、uid | 用户问题 | question、module、keyword、status、question_lib_id |
t_help_answer | id、question_id | 问题回答 | answer、is_accept、remark、媒体标记 |
t_help_question_lib | id、answer_id | 标准题库 | 问题、答案、模块、关键词、状态、浏览数 |
t_knowledge | id、分类 ID | 知识内容 | 标题、正文、发布/排序字段待 DDL 确认 |
t_knowledge_category | id、父 ID | 分类树 | 名称、层级、排序 |
t_knowledge_collect | 用户、知识 ID | 收藏关系 | sid/uid、知识 ID |
t_scm_robot_conversation_knowledge | 会话、知识 | 机器人会话引用 | 不属于帮助题库主链 |
erDiagram
HELP_QUESTION ||--o{ HELP_ANSWER : has
HELP_ANSWER ||--o| HELP_QUESTION_LIB : transforms
HELP_QUESTION ||--o| HELP_QUESTION_LIB : links
KNOWLEDGE_CATEGORY ||--o{ KNOWLEDGE_CATEGORY : children
KNOWLEDGE_CATEGORY ||--o{ KNOWLEDGE : contains
KNOWLEDGE ||--o{ KNOWLEDGE_COLLECT : collected
7. 可写字段白名单
HelpBaseService 限制写入:
| 对象 | 允许字段 |
|---|---|
| 问题 | question、attachments、module、not_system_module、keyword |
| 回答 | answer、is_has_img、is_has_video |
| 题库 | 模块、非系统模块、问题、附件、关键词、答案、图片/视频标记 |
Controller 传入的 sid、uid、状态、浏览量、采纳标识等不得由前端任意覆盖,必须由登录上下文或 Service 生成。
8. 问题状态
底层 QuestionEnums:
| 数值 | 底层状态 | API 显示值 |
|---|---|---|
0 | 未解答 | Q_DJD 待解答 |
2 | 已回答待审核 | Q_DSH 待审核 |
1 | 已审核 | Q_YSH 已审核 |
3 | 已解答 | Q_YJD 已解答 |
stateDiagram-v2
[*] --> 待解答: 创建问题
待解答 --> 待审核: 提交回答
待审核 --> 已审核: 后台审核
待审核 --> 已解答: 采纳并完成
已审核 --> 已解答: 确认最佳回答
真实迁移以 HelpAnswerService::check 为准;显示值不是数据库值,排查时不要拿 Q_DJD 直接查整数状态列。
9. 回答状态
回答状态由“问题状态 + 回答 is_accept”动态计算:
| 条件 | API 状态 |
|---|---|
| 问题为待审核 | A_DSH 待审核 |
问题已审核/已解答且 is_accept = 1 | A_YCN 已采纳 |
问题已审核/已解答且 is_accept = 0 | A_WCN 未采纳 |
因此回答表没有必要保存完整显示状态。修复回答状态前应先检查问题主状态和采纳标记。
10. 提问流程
sequenceDiagram
participant U as 服务站用户
participant C as Question Controller
participant S as HelpQuestionService
participant DB as MySQL
participant ES as 问题ES
U->>C: create(question,module,keyword,attachments)
C->>S: 注入sid/uid
S->>S: 字段白名单和业务校验
S->>DB: 新增status=0
S->>DB: 读取完整新行
S->>ES: operationIndex + batchHandle
S-->>U: questionId
10.1 创建副作用
- 新增问题主表。
- 状态固定为未解答。
- 同步创建 ES 文档。
- ES 同步是否与 MySQL 同事务,当前实现不是数据库事务一体化;索引失败可能形成“库有、搜不到”。
10.2 编辑与删除限制
- 普通用户只能处理有权限的问题。
- 问题只有未解答状态允许编辑/删除。
- 编辑后更新 ES 字段。
- 删除数据库行后删除 ES 文档。
11. 问题列表与搜索
HelpQuestionService::list:
- 统计我的问题和我的回答。
- 有关键词/模块时先调用 ES 得到问题 ID。
- 将 ID、状态、站点等条件回表分页。
- 格式化状态、附件、回答数和媒体标记。
flowchart LR
Q[关键词/模块] --> E[ES searchQuestionIds]
E --> I[命中ID列表]
I --> M[MySQL状态和权限过滤]
M --> F[格式化列表]
F --> U[页面]
ES 只负责召回,MySQL 是业务状态真值。索引中的旧状态不应绕过回表权限和删除过滤。
12. 回答流程
flowchart TD
A[选择问题] --> B[提交回答]
B --> C{问题允许回答?}
C -- 否 --> X[拒绝]
C -- 是 --> D[新增回答]
D --> E[问题进入待审核]
E --> F[OPS审核]
F --> G{采纳?}
G -- 是 --> H[is_accept=1并完成问题]
G -- 否 --> I[未采纳/继续回答]
H --> J[可转题库]
回答详情区分 my_answer、best_answer 和全部回答。前端不应把“我的回答”误当最佳答案。
13. 回答审核与采纳
审核必须保证:
- 问题存在且未删除。
- 回答属于该问题。
- 同一问题最多一个采纳回答。
- 审核人具备 OPS 权限。
- 重复审核不会重复增加统计或覆盖最佳回答。
- 问题和回答状态变更要在同一数据库事务内完成。
14. 回答转题库
HelpLibService::transform(answerId) 的硬性条件:
- 回答存在。
answer_id尚未在题库出现。- 根据问题状态和
is_accept计算结果必须是A_YCN。 - 复制问题的模块、问题、附件、关键词。
- 复制回答正文、媒体标记和备注。
- 事务中创建题库并回写问题
question_lib_id。
sequenceDiagram
participant O as OPS
participant L as HelpLibService
participant DB as MySQL
participant ES as 题库ES
O->>L: transform(answerId)
L->>DB: 查回答、问题、重复answer_id
L->>L: 必须为已采纳
L->>DB: BEGIN
L->>DB: 新增题库
L->>ES: 新增题库索引
L->>DB: 回写question_lib_id
L->>DB: COMMIT
ES 调用发生在题库 create 内,数据库事务无法回滚外部 ES。若事务后半段失败,可能出现孤立 ES 文档。
15. 题库生命周期
| 动作 | 权限 | MySQL | ES |
|---|---|---|---|
| 创建 | OPS | 新增 | operationIndex |
| 批量创建 | OPS/导入 | 多行新增 | operationBatchCreate |
| 更新 | OPS | 白名单字段更新 | operationUpdateFields |
| 删除 | OPS | 软删/模型删除 | operationDelete |
| 启停 | OPS | 批量更新 status | 逐条更新状态 |
| 查看详情 | 有访问权 | view_num + 1 | 不更新浏览量 |
FAQ 只查询 status = 1,按 view_num desc 取前 10 条。
16. 题库 ES 索引
HelpCacheEsSer 默认问题索引可被 ES_INDEX_DGJ_HELP 配置覆盖;题库索引固定逻辑名 dgj_help_question_lib。
| 索引 | 搜索字段 | 用途 |
|---|---|---|
| 问题索引 | question | 用户问题搜索 |
| 题库索引 | question、keyword | 标准答案搜索 |
searchQuestionIds(keyword, modules) 返回 ID,再回 MySQL。索引文档 ID 必须与表 ID 一致。
17. 索引一致性窗口
| 操作 | 可能差异 | 用户表现 |
|---|---|---|
| MySQL 新增成功、ES 失败 | 库有索引无 | 列表可见,搜索不到 |
| MySQL 更新成功、ES 失败 | ES 旧内容 | 搜旧词能命中,详情是新内容 |
| MySQL 删除成功、ES 失败 | ES 孤立 ID | 搜索召回后回表为空 |
| ES 成功、数据库事务回滚 | ES 孤立文档 | 搜索命中无详情 |
| 批量启停部分 ES 失败 | 状态不一致 | 停用题仍被召回后回表过滤 |
18. 索引重建策略
flowchart TD
A[确定问题或题库索引] --> B[导出MySQL有效全量]
B --> C[创建新索引/校验mapping]
C --> D[分批bulk写入]
D --> E[核对总数和抽样关键词]
E --> F[切别名或替换索引]
F --> G[观察无结果率和错误]
G --> H[保留旧索引回滚窗口]
当前 createIndex 是否会删除旧索引需先读 Provider 实现;生产禁止在未备份和未确认别名机制时直接执行。
19. 题库 Excel 导入
QuestionLib::import 使用 ExcelService 和题库批量创建。完整链:
- 下载固定模板。
- 上传文件并校验扩展名/大小。
- 读取首个 Sheet 和表头。
- 逐行转换模块、问题、关键词、答案、媒体标记。
- 校验必填、枚举和重复。
- 合法行批量创建。
- 错误行生成错误文件。
- 成功数据批量写 ES。
20. ExcelService 文件域
ExcelService 支持:
uploadcreateExcelcreateErrorcreateTemplatedownloaddownloadTemplate- 按
sid和时间生成文件名 - 可选保存到 OSS
导入安全:禁止公式注入、路径穿越和超大压缩文件;导出以 = + - @ 开头的用户文本应按纯文本处理。
21. 导入原子性
批量创建代码逐行写 MySQL,再统一构造 ES bulk。需要确认失败策略:
- 全量失败:任一错误整批不落库。
- 合法行成功:错误行输出错误文件。
- MySQL 部分成功后 ES bulk 失败:需按导入批次补索引。
文档和页面必须明确采用哪一种,不能只返回“导入成功”而不带成功/失败数量。
22. 结构化知识库
KnowledgeSer:
| 方法 | 作用 |
|---|---|
getCategoryTree | 返回多级分类树 |
getKnowledgeList | 按分类/关键词分页 |
getCollectKnowledgeList | 当前用户收藏列表 |
getKnowledgeInfo | 详情并处理展示字段 |
createKnowledgeCategory | 初始化/同步分类 |
createKnowledge | 初始化/同步内容 |
collectKnowledge | 收藏或取消收藏 |
flowchart LR
C[知识分类树] --> L[分类内容列表]
L --> D[知识详情]
D --> F{收藏/取消}
F --> R[knowledge_collect关系]
R --> M[我的收藏]
23. 收藏幂等
收藏关系应以“用户 + 知识 ID”唯一:
- 重复收藏不新增重复行。
- 取消不存在关系应视为幂等成功或明确无变化。
- 不同服务站/用户收藏隔离。
- 知识下线后收藏列表不应泄露不可见正文。
- 数据库唯一索引待环境确认。
24. 七鱼机器人知识
QiYuRobotKnowledgeSer 提供 getCategoryTree 和 getKnowledgeList,构造时接收参数并调用七鱼外部能力。DGJ2 主要是读取/适配层。
sequenceDiagram
participant U as DGJ2页面/机器人
participant S as QiYuRobotKnowledgeSer
participant Q as 七鱼
U->>S: 分类或分页请求
S->>S: 映射分页/过滤参数
S->>Q: 外部请求
Q-->>S: code/data或异常
S-->>U: DGJ2统一结构
七鱼不可用不应破坏本地问题和题库;需有超时、错误提示和降级边界。
25. 权限模型
| 动作 | 服务站用户 | OPS |
|---|---|---|
| 查看可见问题/题库 | 是 | 是 |
| 创建自己的问题 | 是 | 可代操作时需审计 |
| 编辑/删除问题 | 仅本人且待解答 | 可按权限处理 |
| 回答 | 依产品角色 | 是 |
| 审核/采纳 | 否 | 是 |
| 创建/编辑/启停题库 | 否 | 是 |
| 导入题库 | 否 | 是 |
| 收藏知识 | 是 | 依登录上下文 |
HelpBaseService::isOps() 决定多处写权限和列表条件。不能只靠前端隐藏按钮。
26. 附件与媒体
- 问题附件字段与回答图片/视频标记分开。
is_has_img、is_has_video是展示提示,不等于文件真实存在。- 问题列表会从已采纳回答聚合媒体标记。
- 文件 URL 必须有访问控制、有效期和内容类型限制。
- 删除问题/回答后附件的生命周期和物理清理待文件中心确认。
27. 常见故障:搜不到
flowchart TD
A[关键词搜不到] --> B{MySQL有有效记录?}
B -- 否 --> C[查状态/删除/权限/模块]
B -- 是 --> D{正确索引有文档?}
D -- 否 --> E[补索引/重建]
D -- 是 --> F{搜索字段和分词命中?}
F -- 否 --> G[查mapping、关键词、模块过滤]
F -- 是 --> H{回表是否被过滤?}
H -- 是 --> I[查sid/OPS/状态条件]
H -- 否 --> J[查分页和前端展示]
28. 常见故障:回答不能采纳/转题库
| 检查项 | 预期 |
|---|---|
| 问题状态 | 已回答待审核或允许审核状态 |
| 回答关系 | answer.question_id = question.id |
| 权限 | 当前账号为 OPS/审核角色 |
| 采纳唯一性 | 同问题无另一采纳回答 |
| 转题库条件 | 动态回答状态为 A_YCN |
| 重复转化 | question_lib.answer_id 不存在 |
| 事务结果 | 题库行与 question_lib_id 同时存在 |
| ES | 题库索引文档存在 |
29. 常见故障:知识库不同步
先区分数据源:
- 本地
t_knowledge不显示:查分类、内容、发布状态和 Service 过滤。 - 收藏列表不显示:查用户关系和内容可见性。
- 七鱼列表不显示:查外部接口、账号、分类 ID、分页和超时。
- Help 题库搜不到:查
dgj_help_question_lib,与t_knowledge无关。
30. 只读 SQL
SELECT id, sid, uid, question, module, keyword, status,
question_lib_id, ask_num, is_delete, create_time, modify_time
FROM t_help_question
WHERE id = 10001;
SELECT id, question_id, sid, uid, is_accept, is_has_img,
is_has_video, is_delete, create_time, modify_time
FROM t_help_answer
WHERE question_id = 10001
ORDER BY id;
SELECT id, answer_id, module, question, keyword, status,
view_num, is_delete, create_time, modify_time
FROM t_help_question_lib
WHERE id = 20001 OR answer_id = 30001;
SELECT question_id, SUM(is_accept = 1) AS accepted_count
FROM t_help_answer
WHERE is_delete = 0
GROUP BY question_id
HAVING accepted_count > 1;
SELECT c.id, c.parent_id, c.name, COUNT(k.id) AS knowledge_count
FROM t_knowledge_category c
LEFT JOIN t_knowledge k ON k.category_id = c.id
GROUP BY c.id, c.parent_id, c.name;
收藏表字段需以线上 DDL 为准:
SELECT * FROM t_knowledge_collect
WHERE knowledge_id = 10001
ORDER BY id DESC;
31. ES 只读排查模板
GET dgj_help_question_lib/_search
{
"query": {
"bool": {
"must": [{"multi_match": {"query": "采购入库", "fields": ["question", "keyword"]}}]
}
},
"_source": ["id", "question", "keyword", "module", "status"]
}
索引名应先从运行环境配置确认;禁止在生产直接执行删除索引。
32. 代码定位
rg -n "QUESTION_STATUS|ANSWER_STATUS|ABLE_WRITE_FIELDS" application/Services/Help/HelpBaseService.php
rg -n "function (create|update|delete|info|list)" application/Services/Help/HelpQuestionService.php
rg -n "function (check|remark|transform|status|batchCreate)" application/Services/Help
rg -n "operationIndex|operationDelete|operationUpdateFields|createIndex|searchQuestionIds" application/Services/Help/HelpCacheEsSer.php
rg -n "createError|downloadTemplate|upload" application/Services/Help/ExcelService.php application/controllers/newhelp/QuestionLib.php
rg -n "getCategoryTree|getKnowledgeList|collectKnowledge" application/Services/Knowledge application/controllers/knowledge
33. 补偿 SOP
33.1 MySQL 有、ES 无
- 按表 ID 确认记录有效且可见。
- 生成与
operationIndex相同的文档。 - 使用原 ID 写入正确索引。
- 按关键词检索并回表验证。
33.2 ES 有、MySQL 无
- 确认数据库是否软删、分环境或事务回滚。
- 不恢复无来源业务数据。
- 删除孤立 ES 文档。
- 观察是否有持续同步任务再次写入。
33.3 转题库部分成功
- 查
answer_id对应题库行。 - 查问题
question_lib_id。 - 查题库 ES 文档。
- 以 MySQL 事务最终状态为准补回写或删孤立 ES。
- 不重新生成第二条题库。
34. 禁止动作
- 为了让搜索命中只改 ES、不改 MySQL 真值。
- 将未采纳回答直接转题库。
- 直接改问题显示状态字符串。
- 删除整个 ES 索引后再考虑备份。
- 把七鱼知识故障当成本地题库故障处理。
- 导入文件含用户公式时原样输出到 Excel。
- 在知识正文和附件中暴露客户隐私或内部密钥。
35. 监控建议
| 指标 | 维度 | 作用 |
|---|---|---|
| 问题创建量/待解答时长 | 模块、站点 | 客服负载 |
| 待审核回答量 | 审核队列 | 防止积压 |
| 问题与 ES 数量差 | 索引 | 一致性 |
| 题库与 ES 数量差 | 状态 | 一致性 |
| 搜索无结果率 | 关键词、模块 | 内容覆盖/分词 |
| 搜索回表空 ID 数 | 索引 | 孤立文档 |
| 导入成功/失败行 | 批次 | 数据质量 |
| 重复采纳回答 | 问题 | 数据约束 |
| 收藏重复关系 | 用户、知识 | 唯一性 |
| 七鱼错误率/延迟 | API | 外部 SLA |
36. 回归清单:问答
- [ ] 普通用户创建问题,登录上下文不能伪造。
- [ ] 系统模块和非系统模块。
- [ ] 关键词、空格、长文本和特殊字符。
- [ ] 图片/视频/普通附件。
- [ ] 待解答可编辑删除,其他状态不可。
- [ ] 我的列表和全量列表权限。
- [ ] 单个/多个回答。
- [ ] 审核通过、拒绝、采纳和未采纳。
- [ ] 同问题只能一个最佳答案。
- [ ] 重复审核和并发采纳。
- [ ] 状态显示值与整数映射。
37. 回归清单:题库与搜索
- [ ] 手工创建、更新、删除题库。
- [ ] 启用/停用批量操作。
- [ ] FAQ 只取启用且按浏览量排序。
- [ ] 已采纳回答转题库。
- [ ] 未采纳和重复回答拒绝转化。
- [ ] 转化事务失败后的 ES 清理。
- [ ] 问题索引和题库索引隔离。
- [ ] 中文、英文、数字、短词和组合关键词。
- [ ] 模块过滤和空关键词。
- [ ] MySQL/ES 新增、更新、删除失败窗口。
- [ ] 全量重建和增量补索引。
38. 回归清单:导入与知识库
- [ ] 正确模板、错误表头、空文件和多 Sheet。
- [ ] 重复问题、缺少答案、非法模块。
- [ ] 超长文本、公式注入、科学计数法。
- [ ] 部分成功策略和错误文件。
- [ ] MySQL 成功、ES bulk 失败恢复。
- [ ] 分类树多级、空分类和排序。
- [ ] 列表、详情和不可见内容。
- [ ] 收藏、重复收藏、取消和用户隔离。
- [ ] 七鱼成功、超时、非零错误和空数据。
- [ ] 七鱼故障不影响本地题库。
39. 改动风险
| 级别 | 改动 | 最低回归 |
|---|---|---|
| P0 | 问题/回答状态和采纳事务 | 全状态、并发、转题库 |
| P1 | HelpCacheEsSer 索引/mapping/bulk | 两索引 CRUD、重建、回表 |
| P1 | 题库导入 | 文件安全、原子性、错误文件 |
| P1 | 权限和 isOps | 用户/OPS 全入口 |
| P1 | 知识收藏唯一性 | 多用户、重复、下线 |
| P2 | FAQ 排序、列表格式 | 页面和兼容字段 |
40. 已确认与待确认
40.1 已确认
- 问题、回答、题库可写字段白名单。
- 四个问题显示状态和三个回答显示状态。
- 问题创建/编辑/删除同步 ES。
- 题库使用独立索引
dgj_help_question_lib。 - 题库搜索字段含
question、keyword。 - 已采纳回答才能转题库,且按
answer_id防重复。 - 转题库事务回写
question_lib_id。 - FAQ 查询启用题并按浏览量排序。
- 知识库有分类、内容和收藏三表。
- 七鱼 Service 只提供分类和列表读取。
40.2 待确认
- 生产 ES mapping、分词器、别名和副本配置。
batchHandle的失败重试、超时和部分失败结果。- 问答表生产唯一索引和软删字段约束。
- 审核/采纳的完整权限矩阵。
- Excel 最大行数、文件保留和 OSS 生命周期。
- 知识库发布状态和初始化数据来源。
- 收藏表唯一索引。
- 七鱼鉴权、限流、缓存和降级 SLA。
41. 证据来源
application/controllers/help/Dgj.phpapplication/controllers/newhelp/Question.phpapplication/controllers/newhelp/Answer.phpapplication/controllers/newhelp/QuestionLib.phpapplication/controllers/knowledge/Knowledge.phpapplication/controllers/qa/Qa.phpapplication/Services/Help/HelpBaseService.phpapplication/Services/Help/HelpQuestionService.phpapplication/Services/Help/HelpAnswerService.phpapplication/Services/Help/HelpLibService.phpapplication/Services/Help/HelpCacheEsSer.phpapplication/Services/Help/ExcelService.phpapplication/Services/Knowledge/KnowledgeSer.phpapplication/Services/Knowledge/QiYuRobotKnowledgeSer.phpapplication/KzData/Enums/QuestionEnums.phpapplication/config/tables.php
42. 一页式交接结论
- 用户问题、标准题库、结构化知识库和七鱼知识是四套数据源。
- 问题/题库 ES 只做召回,MySQL 是状态、权限和删除真值。
- 问题显示状态是整数枚举的 API 映射;回答状态由问题状态和采纳标记动态得出。
- 只有已采纳回答可转题库,题库用
answer_id防重复。 - 转题库事务不能回滚已成功的 ES 调用,必须处理孤立索引。
- 题库启停要同时更新 MySQL 和 ES,但回表仍要过滤。
- 导入需明确全失败还是合法行成功,并输出成功/失败数量。
- 本地知识库收藏应以用户和知识 ID 唯一。
- 七鱼故障与 DGJ2 题库故障分开排查。
- 修复搜索时以表 ID 为幂等键补索引,不直接修改业务状态。
请求-日志-数据变更追踪卡
多入口请求链路
| 场景 | 调用方与入口 | 请求载荷/上下文 | Controller/Consumer | Service/Provider | 汇合点 | 最终业务事实 |
|---|---|---|---|---|---|---|
| 用户提问/回答 | help/newhelp 页面 | 用户、问题、分类、内容 | help/Dgj.php、newhelp/Question.php/Answer.php | HelpQuestion/Answer Service | question/answer ID | 问答保存并进入审核状态 |
| 题库/知识维护 | 管理页 | 题目、答案、分类、上下架 | QuestionLib/Knowledge Controller | Help/Knowledge Service | content ID | 题库和知识文章版本落库 |
| 审核发布 | OPS/任务 | 对象 ID、审核动作、意见 | 管理 Controller/Task | Help Service | 对象 ID | 状态从待审核到发布/拒绝 |
| 搜索 | help/knowledge/qa 搜索入口 | 关键词、分类、分页 | knowledge/Knowledge.php、qa/Qa.php | Search/ES Service | 表 ID/ES doc ID | 返回已发布内容 |
日志证据矩阵
| 链路段 | 日志来源 | 可检索锚点 | 成功信号 | 失败信号 | 与下一段关联方式 | | --- | --- | --- | --- | --- | --- | --- | | 内容提交 | Controller/Service | request_id、用户、question/content ID | 主记录 commit | 敏感词/分类/权限失败 | 表 ID 查状态与正文 | | 审核 | Help Service | 对象 ID、oldStatus、action、操作人 | Q_DJD -> Q_YSH 等合法迁移 | 并发审核、非法回退 | 对象 ID 触发索引刷新 | | 索引同步 | ES Service/Task | ES_INDEX_DGJ_HELP、doc ID、更新时间 | 文档写入/删除成功 | mapping/连接失败、旧版本覆盖 | doc ID = 表 ID 回查 DB | | 搜索查询 | Search Service | request ID、关键词、index、doc ID | 仅返回发布态且内容新 | DB 有、ES 无/旧/未过滤 | doc ID 对比 DB 状态/更新时间 |
环节数据变更台账
| 步骤 | 代码位置 | 事务 | 读取事实 | 写入表/缓存/MQ | 字段或数量变化 | 回查证据 |
|---|---|---|---|---|---|---|
| 创建内容 | HelpQuestion/Answer/Knowledge Service | 内容事务 | 用户、分类、重复内容 | 问题/答案/知识表 | insert;status=待审核;版本/正文初始化 | 表 ID、创建人、时间 |
| 审核发布 | Help Service | 审核事务 | 当前状态和审核动作 | 主表/审核记录 | 待审 -> 已审/已拒;发布态可检索 | 状态、操作人、审核时间 |
| 建索引 | Search/ES Service | DB 外部边界 | 已发布 DB 记录和更新时间 | ES_INDEX_DGJ_HELP | doc insert/update;下架则 delete/不可搜 | doc ID、DB/ES update time |
| 搜索 | Search Controller | 只读 | ES 文档、筛选条件 | 无 | DB 不变;返回排序分页结果 | request ID、doc ID 列表 |
| 修复 | 索引补偿 task | 分批幂等 | DB 发布态与 ES 集合差 | ES | 以表 ID upsert/delete,不改业务 status | 修复前后集合差、重跑 0 变化 |
子模块追踪:help-question 用户提问
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 创建问题 | 用户提交标题/正文/分类 | request ID、user/sid、question ID | application/controllers/newhelp/Question.php -> application/Services/Help/HelpQuestionService.php | 用户、分类、重复/敏感内容和权限 | 内容本地事务 insert,status none -> pending、版本初始化 | request ID + question/user ID | 校验/重复失败零写入;正文日志脱敏/摘要化 |
| 编辑回查 | 用户修改未发布问题 | question ID、version | application/Services/Help/HelpQuestionService.php | 所有权、当前态、乐观版本和已有回答 | 本地事务 content/version old -> new;已发布按规则重新待审 | request ID + question + before/after version | 并发版本冲突零覆盖;索引更新仅在发布后 |
子模块追踪:help-answer 回答与采纳
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 回答 | 用户/运营提交答案 | question/answer ID、user | application/controllers/newhelp/Answer.php -> application/Services/Help/HelpAnswerService.php | 问题可答态、重复内容和用户权限 | 回答本地事务 insert,status none -> pending/published | request ID + question/answer/user | 问题关闭或无权零写入;失败不改变问题状态 |
| 采纳 | 提问者/运营采纳答案 | question/answer ID、action | application/Services/Help/HelpAnswerService.php | 回答属于问题、当前采纳项和状态 | 同一本地事务旧采纳 true -> false、目标 false -> true | request ID + question/answer + affected rows | 并发仅一个采纳;索引/统计 commit 后异步刷新 |
子模块追踪:help-library 题库维护
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 题库配置 | 运营新增/编辑/分类/停用题目 | lib/question ID、category、operator | application/controllers/newhelp/QuestionLib.php -> application/Services/Help/HelpLibService.php | 原题、分类、重复和引用使用 | 配置本地事务 content/status/order old -> new | request ID + lib/question + operator | 停用不物理删除历史引用;批量失败按事务回滚 |
| 导入导出 | 题库 Excel 维护 | file/task ID、rowNo、business key | application/Services/Help/ExcelService.php | 表头、字段、重复集合和现有题库 | 校验不写;通过后每批本地事务 upsert | task + row/error/affected counts | 只重跑失败键;模板版本明确且错误带行号 |
子模块追踪:help-knowledge 知识文章维护
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 保存文章 | 运营新建/编辑知识内容 | article ID、category、version | application/controllers/knowledge/Knowledge.php -> application/Services/Knowledge/KnowledgeSer.php | 分类、重复标题、正文和当前发布态 | 内容本地事务 insert/update,version old -> new、status draft/pending | request ID + article/category/version | 并发版本冲突不覆盖;敏感正文不完整写日志 |
| 机器人同步 | 发布内容同步七鱼/机器人知识 | article ID、external ID | application/Services/Knowledge/QiYuRobotKnowledgeSer.php | 本地发布快照、外部映射和同步态 | 外部调用事务外;本地 sync pending -> success/failed | request ID + local/external ID + code | 失败只补外部同步,不重复发布本地文章 |
子模块追踪:help-audit 内容审核与发布
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 审核发布 | 审核问题/回答/知识文章 | content type/ID、action、operator | application/Services/Help/HelpBaseService.php | 当前待审态、内容版本、审核权限 | 审核本地事务 pending -> published/rejected,写审核记录 | request ID + content type/ID + action | 旧版本审核不得覆盖新稿;终态重复请求 0 变化 |
| 下架 | 运营撤回已发布内容 | content ID、reason | application/Services/Knowledge/KnowledgeSer.php | 发布态、引用和外部/ES 同步 | 本地事务 published -> offline;索引删除 commit 后 | request ID + content ID + index task | DB 已下架只补索引/外部删除,不恢复业务状态 |
子模块追踪:help-search 知识库搜索
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 搜索请求 | 用户按关键字/分类查询 | request ID、query、filters/page | application/controllers/qa/Qa.php -> application/Services/Help/HelpCacheEsSer.php | ES 已发布文档、权限、分类和排序 | 查询只读 不写;仅返回可发布态 | request ID + query + doc IDs/hit count | DB 有 ES 无定位同步;空 query 和超页码不写业务数据 |
| 结果核对 | 搜索到下架/搜不到发布内容 | content ID、ES doc/version | application/Services/Help/HelpCacheEsSer.php | DB 状态/更新时间与 ES 文档 | 查询只读;比较 status/version/update time | content/doc ID + both timestamps | DB 为业务真值;只修目标索引文档 |
子模块追踪:help-index-repair ES 索引同步与修复
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 增量同步 | 内容发布/下架后 | content type/ID、version、task/message ID | application/Services/Help/HelpCacheEsSer.php | DB 发布态、ES 旧 doc 和更新时间 | DB 事务外 upsert/delete old doc -> DB snapshot | task + content/doc ID + index result | 旧事件不覆盖新版本;失败保留业务键重试 |
| 差异修复 | 批量对比 DB 与 ES_INDEX_DGJ_HELP | batch、ID range | application/Services/Help/HelpCacheEsSer.php | DB published 集合与 ES ID/version 集合 | 分批事务外 upsert/delete;业务 status 不变 | batch + scanned/upsert/delete/error counts | 先 dry-run/小批,重跑差异 0;索引环境待确认 |