本文引用的文件
本文件面向调查分析场景,汇总 person、call、trans、track、govern、search、dm、otg、external 等模块的职责与协作方式。这些模块共同围绕“案件数据源”组织数据:以 CaseInfo 描述案件元信息,通过 CaseDataSourceRegistry 和 CaseRoutingDataSource 把当前用户打开的案件路由到对应 DuckDB 库;同时由 dm 模块负责文件解析、清洗并落库,govern 提供治理树统一入口,search 提供全文检索增强,otg 提供时序和特殊日期能力,external 映射外部表。底层 MyBatis-Plus 访问 PostgreSQL/pgvector(平台、向量索引)以及各案件的 DuckDB 数据。
后端代码集中在 ai-server 中,按领域划分为多个 module:
common 下包含案件上下文、数据源路由、缓存、常量、异常、基础实体等。person、call、trans、track、govern、search、dm、otg、external。plat 提供案件管理、系统配置、用户、健康检查等。AI 和数据清洗相关:aiclean、agent、knowledge 等作为辅助能力。
graph TB
subgraph "公共基础设施"
CaseInfo["案件元信息<br/>CaseInfo"]
Registry["案件数据源注册表<br/>CaseDataSourceRegistry"]
Routing["动态数据源路由<br/>CaseRoutingDataSource"]
Context["案件上下文<br/>CaseContextHolder"]
end
subgraph "业务模块"
Person["人员模块<br/>person"]
Call["通话模块<br/>call"]
Trans["交易模块<br/>trans"]
Track["轨迹模块<br/>track"]
Govern["治理模块<br/>govern"]
Search["搜索模块<br/>search"]
Dm["数据管理模块<br/>dm"]
Otg["时序模块<br/>otg"]
External["外部表模块<br/>external"]
end
subgraph "数据存储"
PG["PostgreSQL / pgvector"]
DuckDB["DuckDB 案件库"]
ES["Elasticsearch"]
end
Person --> Governance["治理树<br/>GovernTreeService"]
Call --> Governance
Trans --> Governance
Track --> Governance
External --> Governance
Governance --> DuckDB
Person --> DuckDB
Call --> DuckDB
Trans --> DuckDB
Track --> DuckDB
External --> DuckDB
Dm --> DuckDB
Dm --> Search
Otg --> DuckDB
Search --> ES
Platform["平台服务<br/>plat"] --> PG
Platform --> DuckDB
Registry --> DuckDB
Routing --> DuckDB
Context --> Routing
图表来源
章节来源
CaseInfo:记录案件名称、密码、数据库名、数据库路径、类型、备注、创建时间、初始化状态、归属用户和工作空间路径。它是“案件”的业务标识,也是数据隔离的根。CaseDataSourceRegistry:管理已打开 DuckDB 数据源的生命周期,按案件物理键 case{caseId} 注册,限制最大打开数,校验数据库文件存在且非空,并在开案时补建 file_ai_profile 表。CaseRoutingDataSource:将注解或直连使用的逻辑 key slave 映射到当前案件的物理 key,未开案或未注册时返回明确错误,防止串库。PersonBasicInfoService:维护人员基本信息、照片、手动编号、自动识别编号,并与 CaseDataCache 联动刷新人员关联。CallRecordService:基于治理配置选择通话表名,支持分页、时间范围、对方号码过滤。TransRecordService:根据治理配置在 trans_record 与 trans_record_all 之间切换,构建金额、卡号、对手、摘要等多条件查询。GovernTreeService:构建治理树、加载治理节点表格数据、按人员筛选交易、处理自定义条件 SQL。SearchQueryService:使用 Elasticsearch 对当前案件文档进行关键词模糊匹配和高亮,最多返回 500 条。SearchDocIndexService:按案件批量写入、熔断降级、刷新索引、按文件删除、按案件清理。DmService:文件预览、上传、预处理、清洗任务调度、AI 识别档案、与治理树和搜索索引集成。TimeSeriesService:查询时间序列、跳转查询、详情展示,结合治理配置表头。章节来源
调查场景中,数据从外部文件进入 dm 模块,经清洗后落到 DuckDB 案件库;人员、通话、交易、轨迹、外部表等业务模块通过 MyBatis-Plus 访问 DuckDB;治理树聚合多表数据并提供统一查询入口;搜索模块用 Elasticsearch 提供全文检索;时序模块提供时间维度分析和跳转;平台服务用 PostgreSQL/pgvector 管理用户、模型、知识库、系统信息等。
sequenceDiagram
participant User as "用户"
participant Plat as "平台服务 plat"
participant Registry as "CaseDataSourceRegistry"
participant Routing as "CaseRoutingDataSource"
participant DM as "DmService"
participant DuckDB as "DuckDB 案件库"
participant Govern as "GovernTreeService"
participant Search as "SearchDocIndexService"
participant ES as "Elasticsearch"
User->>Plat: "打开案件 caseId"
Plat->>Registry: "open(caseId, dbPath)"
Registry->>Routing: "注册物理 key case{caseId}"
Registry->>DuckDB: "建立连接并补建 file_ai_profile"
User->>DM: "上传并清洗文件"
DM->>DuckDB: "写入清洗结果"
DM->>Search: "批量写入全文索引"
Search->>ES: "bulk 写入"
User->>Govern: "查询治理树"
Govern->>DuckDB: "按治理配置表名查询"
User->>Search: "关键词搜索"
Search->>ES: "wildcard + caseId 过滤"
图表来源
案件是数据隔离的最小单元。CaseInfo 保存案件元信息,包括数据库路径;CaseDataSourceRegistry.open 会校验 DuckDB 文件存在且非空,按 case{caseId} 注册数据源,并限制最大打开数量。CaseRoutingDataSource.getDataSource 将逻辑 key slave 转为物理 key,若未打开则返回“请先打开案件”错误。
flowchart TD
Start(["打开案件"]) --> CheckContext["获取 caseId"]
CheckContext --> ValidateDb["校验 DuckDB 文件存在且非空"]
ValidateDb --> CreateDS["创建 DuckdbUnpooledDataSource"]
CreateDS --> RegisterKey["注册物理 key case{caseId}"]
RegisterKey --> EnsureTable["补建 file_ai_profile 表"]
EnsureTable --> Done(["可被 slave 路由访问"])
图表来源
章节来源
PersonBasicInfoService 提供人员基本信息的增删改查,并维护人员电话、银行卡等关联编号。其更新和批量排序操作标注 @DS(StrConsts.DS_KEY_SLAVE),确保写入 DuckDB 而非 PostgreSQL。它还依赖 CaseDataCache 合并自动识别出的人员和编号,避免重复。
classDiagram
class PersonBasicInfoService {
+create(dto)
+delete(personName)
+update(dto)
+getPersons()
+getPersonNames()
+personOrder(list)
+flushPerson(set)
}
class PersonBasicInfoMapper
class PersonLibNoMapper
class CaseDataCache
PersonBasicInfoService --> PersonBasicInfoMapper : "MyBatis-Plus"
PersonBasicInfoService --> PersonLibNoMapper : "维护编号"
PersonBasicInfoService --> CaseDataCache : "读取自动编号"
图表来源
章节来源
CallRecordService 通过治理配置决定实际通话表名,支持分页、时间范围、对方号码过滤,并对“未知号码”做特殊处理。它依赖 GovernConfService 获得动态表名,最终交给 Mapper 执行分页查询。
flowchart TD
Query["接收 CallRecordQuery"] --> ResolveTable["调用 GovernConfService 获取通话表名"]
ResolveTable --> NormalizeOtherPhones["规范化 otherPhones"]
NormalizeOtherPhones --> PageQuery["调用 baseMapper.selectCallRecordPage"]
PageQuery --> Return(["返回分页结果"])
图表来源
章节来源
TransRecordService 根据治理配置在 trans_record 与 trans_record_all 之间切换查询目标,支持金额比较符、卡号、对手姓名、摘要、分行、备注、文件编号、工作表编号等条件。当查询来源为现金关键字时,还会先拉取现金关键字列表并拼接 like 条件。
flowchart TD
Start(["接收 TransRecordQuery"]) --> DecideTable{"治理配置表名"}
DecideTable -->|trans_record| BuildWrapper1["构建 TransRecord 查询包装器"]
DecideTable -->|trans_record_all| BuildWrapper2["构建 TransRecordAll 查询包装器"]
BuildWrapper1 --> ApplyConditions["应用金额、对手、卡号、时间等条件"]
BuildWrapper2 --> ApplyConditions
ApplyConditions --> CashKeys{"是否按现金关键字过滤"}
CashKeys -->|是| LoadKeys["加载 TransCashKey 列表"]
LoadKeys --> LikeExt1["拼接 ext1 like 条件"]
CashKeys -->|否| Execute["执行分页查询"]
LikeExt1 --> Execute
Execute --> Convert{"是否需要转换"}
Convert -->|是| MapToEntity["TransRecordAllConvert 转换"]
Convert -->|否| Return(["返回 Page<TransRecord>"])
MapToEntity --> Return
图表来源
章节来源
GovernTreeService 承担治理树构建、治理节点表格分页、按人员筛选交易等职责。它组合了人员、通话、交易、账户等多个 Mapper,并通过 GovernConfService 获取动态表名。对于治理树节点,还支持注入 AI 模板 ID,以便前端渲染动态表。
classDiagram
class GovernTreeService {
+getTree()
+getTreeTablePage(dto)
+getTreeTransPersonPage(dto)
}
class PersonBasicInfoMapper
class TransRecordMapper
class TransRecordAllMapper
class CallRecordMapper
class CallRecordAllMapper
class AcctOpenInfoMapper
class GovernConfService
class GovernTreeMapper
GovernTreeService --> PersonBasicInfoMapper
GovernTreeService --> TransRecordMapper
GovernTreeService --> TransRecordAllMapper
GovernTreeService --> CallRecordMapper
GovernTreeService --> CallRecordAllMapper
GovernTreeService --> AcctOpenInfoMapper
GovernTreeService --> GovernConfService
GovernTreeService --> GovernTreeMapper
图表来源
章节来源
搜索模块分为查询侧和写入侧:
SearchQueryService:对 Elasticsearch 发起 wildcard 查询,按 content 字段匹配小写关键词,并按 dateTime 降序返回最多 500 条,同时对 content 高亮。SearchDocIndexService:按案件批量攒批写入,失败熔断降级,完成后 flush 并 refresh;支持按文件删除和按案件清理。
sequenceDiagram
participant Client as "客户端"
participant QuerySvc as "SearchQueryService"
participant ES as "Elasticsearch"
participant IndexSvc as "SearchDocIndexService"
Client->>QuerySvc: "keyword"
QuerySvc->>QuerySvc: "读取 CaseContextHolder.caseId"
QuerySvc->>ES: "wildcard(content) + filter(caseId)"
ES-->>QuerySvc: "搜索结果"
QuerySvc-->>Client: "SearchDTO 列表(含高亮)"
Note over IndexSvc: "清洗流程写入"
IndexSvc->>IndexSvc: "按 caseId 攒批"
IndexSvc->>ES: "bulk 写入"
IndexSvc->>ES: "refresh"
图表来源
章节来源
DmService 是数据入湖和清洗的核心:
SearchDocIndexService.add/flush 同步全文索引。AI 识别:非表格文件抽取样本并提交 FileAiProfileService 识别。
flowchart TD
Upload["上传文件"] --> Preview["预解析文件"]
Preview --> PreTask["PreTask 解析链路"]
PreTask --> CleanTask["CleanTask 清洗任务"]
CleanTask --> DuckDB["写入 DuckDB 案件库"]
CleanTask --> SearchIndex["SearchDocIndexService.add"]
SearchIndex --> Flush["全量完成 flush+refresh"]
NonTable["非表格文件"] --> AiProfile["FileAiProfileService 建档识别"]
图表来源
章节来源
TimeSeriesService 提供时间序列数据的查询、跳转和详情展示。它支持按时间范围和类型过滤,并通过 GovernConfService 获取表头映射。跳转查询走特定 Mapper SQL,适合复杂时序分析。
flowchart TD
Query["TimeSeriesQuery"] --> Range["计算起止时间"]
Range --> Types["收集类型集合"]
Types --> Select["baseMapper.selectTimeSeriesList"]
Select --> Jump["jumpTimeSeries 跳转查询"]
Jump --> Detail["detailTimeSeries 详情"]
图表来源
章节来源
external 模块主要暴露外部数据的 Mapper,如户籍、暂住、车辆违章、刑事人员、证件信息等。这些数据通常由 dm 模块的 ExternalCleaner 清洗入库,供治理树和分析工具查询。该模块本身更多是数据访问接口,业务逻辑多在 dm 清洗器和 govern 查询中体现。
[本节为概念性说明,不直接分析具体文件]
业务模块之间的耦合主要体现在:
person、call、trans、track、external 都通过 MyBatis-Plus 访问 DuckDB,受 CaseRoutingDataSource 控制。
graph LR
Govern["GovernTreeService"] --> Person["PersonBasicInfoService"]
Govern --> Call["CallRecordService"]
Govern --> Trans["TransRecordService"]
Govern --> External["External Mappers"]
Govern --> Track["Track Services"]
Dm["DmService"] --> Govern
Dm --> Search["SearchDocIndexService"]
Dm --> Person
Search --> ES["Elasticsearch"]
Otg["TimeSeriesService"] --> Govern
AllModules["person/call/trans/track/external"] --> DuckDB["DuckDB"]
DuckDB --> Govern
图表来源
章节来源
PersonBasicInfoService 获取人员信息及自动/手动关联的电话、卡号。CallRecordService.getCallRecord 传入对方号码或本人号码过滤,分页返回通话记录。如需结合治理树,可通过 GovernTreeService 获取通话节点并应用自定义条件。
sequenceDiagram
participant UI as "前端"
participant Person as "PersonBasicInfoService"
participant Call as "CallRecordService"
participant DuckDB as "DuckDB"
UI->>Person: "获取人员及关联号码"
Person-->>UI: "电话、卡号集合"
UI->>Call: "按号码过滤通话记录"
Call->>DuckDB: "selectCallRecordPage"
DuckDB-->>Call: "通话记录分页"
Call-->>UI: "通话列表"
图表来源
章节来源
TransRecordService.getTransRecord 按卡号、对手姓名、时间范围过滤交易。若需要全局视角,可通过 GovernTreeService.getTreeTransPersonPage 按人员筛选交易。
flowchart TD
CallResult["通话结果"] --> Extract["提取对方卡号/姓名"]
Extract --> TransQuery["TransRecordService 查询"]
TransQuery --> GovernView["GovernTreeService 人员交易视图"]
GovernView --> DuckDB["DuckDB 交易表"]
图表来源
章节来源
GovernTreeService.getTree 获取治理树,定位轨迹相关节点。GovernTreeService.getTreeTablePage 加载轨迹表格分页数据,并可传入自定义条件 SQL。结合 TimeSeriesService.jumpTimeSeries 进行时间维度跳转分析,定位关键时间点。
sequenceDiagram
participant Analyst as "调查员"
participant Govern as "GovernTreeService"
participant Track as "Track Services/Mappers"
participant Time as "TimeSeriesService"
Analyst->>Govern: "获取治理树"
Govern-->>Analyst: "轨迹节点"
Analyst->>Govern: "加载轨迹表格"
Govern->>Track: "按条件查询轨迹数据"
Analyst->>Time: "时间序列跳转"
Time-->>Analyst: "关键时间点序列"
图表来源
章节来源
GovernConfService 获取动态表名,避免硬编码,便于在不同数据源间切换。SearchDocIndexService 的批量缓冲和熔断机制,避免单条写入造成延迟。DmService.preProcessFile 已有并发上限和超时保护,注意合理设置预览并发度。DuckdbBudgetProperties 控制每案件内存和线程数,避免内存溢出。[本节为通用性能建议,不直接分析具体文件]
CaseDataSourceRegistry.open,以及 CaseContextHolder 是否携带了 caseId。CaseDataSourceRegistry 中的 opened 映射是否存在。@DS(StrConsts.DS_KEY_SLAVE) 或显式走 CaseRoutingDataSource,不要绕过路由。SearchDocIndexService 是否因熔断丢弃文档。dataCount > 0,以及 AI 模板 ID 是否正确注入。SearchDocIndexService 的熔断计数和丢弃文档累计,确认 ES 故障未影响清洗主流程。章节来源
业务数据模块以案件为核心,通过 dm 模块完成数据入湖和清洗,person/call/trans/track/external 等模块围绕 DuckDB 案件库提供业务能力,govern 提供统一治理树入口,search 提供全文检索增强,otg 提供时序分析能力。MyBatis-Plus 作为统一数据访问层,配合 CaseRoutingDataSource 实现按案件路由到 DuckDB,平台服务则继续使用 PostgreSQL/pgvector 管理元数据和向量索引。调查分析的关键在于合理使用治理配置、分页查询、搜索索引和时序跳转,并结合人员、通话、交易、轨迹进行交叉验证。
[本节为总结性内容,不直接分析具体文件]