通话模块 call.md 39 KB

通话模块 call

本文引用的文件

  • case_table.sql
  • create_table_2.sql
  • CallRecord.java
  • CallRecordAll.java
  • UseOpenInfoCallRecord.java
  • CallOpenInfo.java
  • CallRecordQuery.java
  • CallNightQuery.java
  • CallContinuousQuery.java
  • CallSensitiveQuery.java
  • CallNightDTO.java
  • CallContinuousDTO.java
  • CallSensitiveDTO.java
  • CallRecordController.java
  • CallRecordService.java
  • CallNightService.java
  • CallContinuousService.java
  • CallSensitiveService.java
  • CallOpenInfoService.java
  • CallRecordMapper.java
  • CallNightMapper.java
  • CallContinuousMapper.java
  • CallSensitiveMapper.java
  • CallOpenInfoMapper.java
  • UseOpenInfoCallRecordMapper.java
  • CallRecordAllMapper.java
  • CallAnalysisTool.java
  • CallToolSpecs.java
  • CallAnalysisToolTest.java

目录

  1. 引言
  2. 项目结构与模块边界
  3. 核心数据模型
  4. 查询条件与过滤规则
  5. 业务分析能力
  6. 架构总览
  7. 关键组件详解
  8. 依赖关系分析
  9. 性能与索引优化
  10. 常见问题排查
  11. 结论

引言

通话模块 call 是调查数据模型中的基础通信维度,负责存储和查询与电话、号码相关的调查实体。它主要覆盖以下五类数据:

实体 说明 典型用途
通话记录 一次主叫或被叫的通话明细 查某人通话、查双方关系、时间分布
夜间通话 在设定夜间时段内的通话统计 发现异常作息、隐蔽联络
连续通话 按月份判断两人是否持续保持联系 识别长期稳定关系
敏感通话 高频或重点对象的通话预警 敏感对象预警、关系热点
开放信息 号码开户、归属地、入网销户等元数据 补全号码身份、校验活跃状态

该模块与人员 person 的关系非常直接:通话记录的“本方”通常对应案件中的目标人员,而“对方”可能是同案人、联系人、涉案号码或其他无关号码。通过本方与对方的姓名、证件号、电话号码,可以把通话记录与人、交易、轨迹、治理树串联起来,形成“谁在什么时间、以什么方式、和谁发生了多少次关联”的调查证据链。

项目结构与模块边界

通话模块在后端 Java 项目中采用典型的分层结构:

graph TB
    subgraph "控制器层"
        C1["CallRecordController"]
        C2["CallNightController"]
        C3["CallContinuousController"]
        C4["CallSensitiveController"]
    end

    subgraph "服务层"
        S1["CallRecordService"]
        S2["CallNightService"]
        S3["CallContinuousService"]
        S4["CallSensitiveService"]
        S5["CallOpenInfoService"]
    end

    subgraph "映射层"
        M1["CallRecordMapper"]
        M2["CallNightMapper"]
        M3["CallContinuousMapper"]
        M4["CallSensitiveMapper"]
        M5["CallOpenInfoMapper"]
        M6["UseOpenInfoCallRecordMapper"]
        M7["CallRecordAllMapper"]
    end

    subgraph "公共模型"
        E1["CallRecord"]
        E2["CallRecordAll"]
        E3["UseOpenInfoCallRecord"]
        E4["CallOpenInfo"]
        Q1["CallRecordQuery"]
        Q2["CallNightQuery"]
        Q3["CallContinuousQuery"]
        Q4["CallSensitiveQuery"]
        D1["CallNightDTO"]
        D2["CallContinuousDTO"]
        D3["CallSensitiveDTO"]
    end

    subgraph "数据库表"
        T1["call_record"]
        T2["call_record_all"]
        T3["use_open_info_call_record"]
        T4["call_opening_info"]
    end

    C1 --> S1
    C2 --> S2
    C3 --> S3
    C4 --> S4
    S1 --> M1
    S2 --> M2
    S3 --> M3
    S4 --> M4
    S5 --> M5
    M1 --> T1
    M2 --> T1
    M3 --> T1
    M4 --> T1
    M5 --> T4
    M6 --> T3
    M7 --> T2

图示来源

  • CallRecordController.java:1-38
  • CallRecordService.java
  • CallNightService.java
  • CallContinuousService.java
  • CallSensitiveService.java
  • CallOpenInfoService.java
  • case_table.sql:90-246

从现有代码可见,通话模块包含:

层次 职责
控制器 暴露 HTTP 接口,如通话记录分页查询、夜间通话、连续通话、敏感通话、开放信息等
服务 封装通话分析逻辑,包括时间范围过滤、号码匹配、去重、分页、聚合统计
映射器 对接 MyBatis,访问底层数据库表
公共模型 定义通话实体、查询参数、分析结果 DTO
数据库 定义通话明细、合并记录、使用方通话记录、号码开户信息

此外,通话模块还作为 AI Agent 工具的数据源之一。CallAnalysisTool 通过注入 CallRecordService 等组件,对外暴露获取通话记录、夜间通话、连续通话、敏感通话等工具能力,供智能分析流程调用。

章节来源

  • CallRecordController.java:1-38
  • CallAnalysisTool.java
  • CallToolSpecs.java

核心数据模型

通话记录实体

CallRecord 映射到 call_record 表,表示一条原始通话记录。关键字段可归纳为四类:

字段类别 字段示例 含义
本方身份 personName、personPhone、personCertNo 本方姓名、手机号、证件号
位置信息 personRegionId、personCellId、personStationName、经度、纬度 本方基站大区、小区、名称和坐标
通话事实 callDateTime、callDate、callTime、duration、callDirection、callType 通话时间、时长、主被叫、通话类型
对方身份 otherName、otherPhone、otherPhoneArea、otherCertNo 对方姓名、手机号、归属地、证件号

CallRecord 继承自通用清洗基类,并支持序列化;同时提供字符串化方法,用于日志或导出时拼接关键字段。

章节来源

  • CallRecord.java:1-200

其他通话相关实体

实体 表名 主要用途
CallRecordAll call_record_all 汇总或合并后的通话记录,字段口径与 CallRecord 基本一致
UseOpenInfoCallRecord use_open_info_call_record 与开放信息关联的通话记录视图或中间表
CallOpenInfo call_opening_info 号码开户信息,含运营商、归属省、市、入网销户时间、首次通话时间等

其中,CallOpenInfo 更偏向号码维度的静态档案,而通话记录更偏向行为维度。两者可通过 personPhone 关联,用于判断号码是否有效、是否已销户、归属地是否与通话归属地一致等。

章节来源

  • CallRecordAll.java:1-196
  • UseOpenInfoCallRecord.java:1-165
  • CallOpenInfo.java:1-138

数据库表结构

erDiagram
  CALL_RECORD {
    bigint id PK
    bigint fileId
    bigint sheetId
    varchar personName
    varchar personPhone
    varchar personPhoneArea
    varchar personCertNo
    varchar personRegionId
    varchar personCellId
    varchar personStationName
    varchar personStationLongitude
    varchar personStationLatitude
    varchar operatorId
    timestamp callDateTime
    date callDate
    time callTime
    integer duration
    varchar callDirection
    varchar callType
    varchar otherName
    varchar otherPhone
    varchar otherPhoneArea
    varchar otherCertNo
    varchar remark
    varchar personLibId
    varchar callLocal
  }

  CALL_RECORD_ALL {
    bigint id PK
    bigint fileId
    bigint sheetId
    varchar personName
    varchar personPhone
    varchar personPhoneArea
    varchar personCertNo
    varchar personRegionId
    varchar personCellId
    varchar personStationName
    varchar personStationLongitude
    varchar personStationLatitude
    varchar operatorId
    timestamp callDateTime
    date callDate
    time callTime
    integer duration
    varchar callDirection
    varchar callType
    varchar otherName
    varchar otherPhone
    varchar otherPhoneArea
    varchar otherCertNo
    varchar remark
    varchar personLibId
    varchar callLocal
  }

  USE_OPEN_INFO_CALL_RECORD {
    bigint id PK
    bigint fileId
    bigint sheetId
    varchar personName
    varchar personPhone
    varchar personPhoneArea
    varchar personCertNo
    varchar personRegionId
    varchar personCellId
    varchar personStationName
    varchar personStationLongitude
    varchar personStationLatitude
    varchar operatorId
    timestamp callDateTime
    date callDate
    time callTime
    integer duration
    varchar callDirection
    varchar callType
    varchar otherName
    varchar otherPhone
    varchar otherPhoneArea
    varchar otherCertNo
    varchar remark
    varchar personLibId
    varchar callLocal
  }

  CALL_OPENING_INFO {
    bigint id PK
    bigint fileId
    bigint sheetId
    varchar phoneType
    varchar operatorId
    varchar personPhone
    varchar personType
    varchar personName
    varchar personCertNo
    varchar personCertAddress
    varchar mailingAddress
    varchar province
    varchar city
    varchar phoneStatus
    timestamp activationDateTime
    timestamp closingDateTime
    timestamp firstCallDateTime
    timestamp lastSuspensionDateTime
  }

  PERSON_CALL_STAT {
    varchar personName PK
    integer personPhoneCount
    timestamp firstCallDateTime
    timestamp lastCallDateTime
    integer totalCallCount
    integer totalCallDuration
    integer outCallCount
    integer inCallCount
  }

  PHONE_CALL_STAT {
    varchar personPhone PK
    varchar personName
    varchar personCertNo
    varchar operator
    timestamp firstCallDateTime
    timestamp lastCallDateTime
    integer callContactCount
    integer totalCallDuration
    integer totalCallCount
    integer outCallDuration
    integer outCallCount
    integer inCallDuration
    integer inCallCount
  }

图示来源

  • case_table.sql:90-246
  • create_table_2.sql:1-68

实体关系图

classDiagram
    class CallRecord {
        +String personName
        +String personPhone
        +String operatorId
        +String personPhoneArea
        +String personCertNo
        +String personRegionId
        +String personCellId
        +String personStationName
        +String personStationLongitude
        +String personStationLatitude
        +LocalDateTime callDateTime
        +LocalDate callDate
        +LocalTime callTime
        +Integer duration
        +String callDirection
        +String callType
        +String otherName
        +String otherPhone
        +String otherPhoneArea
        +String otherCertNo
        +String remark
        +String personLibId
        +String callLocal
    }

    class CallRecordAll {
        +String personName
        +String personPhone
        +String operatorId
        +String personPhoneArea
        +String personCertNo
        +String personRegionId
        +String personCellId
        +String personStationName
        +String personStationLongitude
        +String personStationLatitude
        +LocalDateTime callDateTime
        +LocalDate callDate
        +LocalTime callTime
        +Integer duration
        +String callDirection
        +String callType
        +String otherName
        +String otherPhone
        +String otherPhoneArea
        +String otherCertNo
        +String remark
        +String personLibId
        +String callLocal
    }

    class UseOpenInfoCallRecord {
        +String personName
        +String personPhone
        +String operatorId
        +String personPhoneArea
        +String personCertNo
        +String personRegionId
        +String personCellId
        +String personStationName
        +String personStationLongitude
        +String personStationLatitude
        +LocalDateTime callDateTime
        +LocalDate callDate
        +LocalTime callTime
        +Integer duration
        +String callDirection
        +String callType
        +String otherName
        +String otherPhone
        +String otherPhoneArea
        +String otherCertNo
        +String remark
        +String personLibId
        +String callLocal
    }

    class CallOpenInfo {
        +String phoneType
        +String operatorId
        +String personPhone
        +String personType
        +String personName
        +String personCertNo
        +String personCertAddress
        +String mailingAddress
        +String province
        +String city
        +String phoneStatus
        +LocalDateTime activationDateTime
        +LocalDateTime closingDateTime
        +LocalDateTime firstCallDateTime
        +LocalDateTime lastSuspensionDateTime
    }

    CallRecordAll --> CallRecord : "字段口径相近"
    UseOpenInfoCallRecord --> CallRecord : "语义相近"
    CallOpenInfo --> CallRecord : "通过 personPhone 关联"

图示来源

  • CallRecord.java:1-200
  • CallRecordAll.java:1-196
  • UseOpenInfoCallRecord.java:1-165
  • CallOpenInfo.java:1-138

查询条件与过滤规则

通话记录查询

CallRecordQuery 是通话记录分页查询的主要输入对象,继承自通用查询基类,因此除自身字段外,还支持分页、排序等通用能力。其核心过滤条件包括:

条件 类型 说明
id、ids Long、Long 列表 按单条或批量主键过滤
fileId、sheetId Long 按数据来源文件和工作表过滤
personPhones String 列表 按本方号码集合过滤
operatorId String 按运营商过滤
personPhoneArea String 按本方号码归属地过滤
personCertNo String 按本方证件号过滤
personRegionId、personCellId String 按基站大区、小区过滤
duration Integer 按通话时长过滤
callDirection String 按主叫或被叫过滤
callType String 按通话类型过滤
otherName String 按对方姓名模糊或精确过滤
otherPhones、otherPhone String 列表、String 按对方号码集合或单个号码过滤
startTime、endTime String 按时间范围过滤
symbol String 当前查询对象中作为时间比较符号使用

注意:CallRecordQuery 中只定义了 personPhones 列表,没有 personPhone 单值字段;但 personName 等常用字段并未出现在查询对象中。实际工程中如果需要按姓名查询,应优先确认服务层是否对 personName 做了扩展处理,或者改用证件号、号码等唯一性更强的字段。

章节来源

  • CallRecordQuery.java:1-92

夜间通话查询

CallNightQuery 用于夜间通话分析,包含:

字段 含义
nightStart 夜间开始小时
nightEnd 夜间结束小时
monthVal 月份阈值或筛选条件
otherName 对方姓名
otherPhone 对方号码

夜间通话的核心逻辑是以 callTime 的小时区间为基础,结合月份维度做聚合,输出时间段、对方信息、通话次数、跨月跨度等结果。

章节来源

  • CallNightQuery.java:1-16
  • CallNightDTO.java:1-57

连续通话查询

CallContinuousQuery 用于识别两个人之间是否在某段时间内持续保持联系,包含:

字段 含义
monthVal 连续月份阈值,例如超过该值的连续通话才保留
otherName 对方姓名
otherPhone 对方号码

连续通话的关键不是单次通话,而是“按月观察”:如果两人在多个相邻月份都有通话,则认为他们存在连续关系;若中间有断月,则可能拆成多段连续区间。

章节来源

  • CallContinuousQuery.java:1-24
  • CallContinuousDTO.java:1-37

敏感通话查询

CallSensitiveQuery 用于敏感通话预警,包含:

字段 含义
otherPhone 对方号码
otherName 对方姓名

敏感通话通常关注两类场景:一是与重点监控对象的通话;二是与某些号码发生异常高频通话。结果由 CallSensitiveDTO 表达,包括对方信息、通话次数等。

章节来源

  • CallSensitiveQuery.java:1-22
  • CallSensitiveDTO.java:1-30

业务分析能力

通话记录与人员关系

通话记录中的“本方”通常对应案件中的目标人员,而“对方”可能是:

  • 同案人
  • 嫌疑人联系人
  • 普通联系人
  • 空号、停机号、虚拟号
  • 企业号码或客服号码

因此,通话记录不能只看 personPhone,还必须结合:

  1. personName、personCertNo:确认本方真实身份。
  2. otherName、otherPhone、otherCertNo:识别对方是谁。
  3. callDirection:判断是本方拨打还是接听。
  4. callDateTime、callDate、callTime、duration:还原通话时间和强度。
  5. personLibId:关联案件中的卡库或人员库。

在调查分析中,建议将通话记录视为“边”,人员视为“点”。同一案件中,一个人可能既是多条边的起点,也可能是多条边的终点。

与交易、轨迹、治理树的交叉分析价值

关联维度 通话的作用
交易 通话频繁的人往往与资金往来有关联;可用通话频次辅助判断交易对手是否可信
轨迹 通话时的基站位置可与活动轨迹对照,判断通话是否发生在异常地点
治理树 通话关系可作为治理树中的社会关系补充,帮助构建人物关系图谱
账户开户 通过 call_opening_info 校验号码是否实名、是否已销户、归属地是否合理

号码匹配策略

通话数据中的号码可能存在格式不一致问题,例如前缀、空格、分隔符差异。推荐匹配策略:

  1. 先标准化:去除空格、连字符,统一前缀(如国家码)。
  2. 精确匹配优先:完整号码相等。
  3. 后缀匹配次之:当号码长度不一致时,取后若干位匹配。
  4. 姓名+证件号强校验:仅靠号码可能误判,需结合 personName、personCertNo。
  5. 开放信息辅助:用 call_opening_info 验证号码状态、归属地、入网时间。

去重规则

通话记录去重应考虑以下维度:

去重维度 适用场景
主键 id 数据库级唯一标识,最可靠
personPhone + otherPhone + callDateTime 同一天内同一方向通话
personPhone + otherPhone + callDate 忽略分钟级重复,按天去重
personPhone + otherPhone + callTime 同一时刻不同天的重复记录
文件级 fileId + sheetId 同一数据源的重复导入

建议在入库阶段基于 fileId、sheetId、id 做幂等控制;在分析阶段根据业务需要选择不同粒度的去重策略。

分页与聚合统计

通话记录分页由 CallRecordController 暴露 getCallRecord 接口,返回分页结果。服务层通常结合 MyBatis Plus 的分页插件完成分页。

聚合统计方面,系统还定义了预统计表:

统计表 作用
person_call_stat 按人员汇总通话次数、通话时长、主被叫次数
phone_call_stat 按号码汇总通话接触人数、通话时长、主被叫次数

这些表适合做快速概览统计,但要注意它们可能是离线计算结果,不一定实时反映最新通话数据。

章节来源

  • Create_table_2.sql:1-68
  • CallRecordController.java:1-38

架构总览

通话模块的整体请求链路如下:

sequenceDiagram
    participant Client as "调用方"
    participant Controller as "CallRecordController"
    participant Service as "CallRecordService"
    participant Mapper as "CallRecordMapper"
    participant DB as "call_record 表"

    Client->>Controller: POST /cr/getCallRecord
    Controller->>Service: getCallRecord(query)
    Service->>Mapper: 执行分页查询
    Mapper->>DB: 按条件检索通话记录
    DB-->>Mapper: 返回分页数据
    Mapper-->>Service: 返回 Page<CallRecord>
    Service-->>Controller: 返回 Result<Page<CallRecord>>
    Controller-->>Client: 返回 JSON 响应

图示来源

  • CallRecordController.java:1-38
  • CallRecordService.java
  • CallRecordMapper.java
  • case_table.sql:90-128

AI Agent 侧的调用路径类似,只是入口变为工具方法:

sequenceDiagram
    participant Agent as "Agent 工具调用方"
    participant Tool as "CallAnalysisTool"
    participant Service as "CallRecordService"
    participant Night as "CallNightService"
    participant Continuous as "CallContinuousService"
    participant Sensitive as "CallSensitiveService"

    Agent->>Tool: getCallRecords()
    Tool->>Service: getCallRecord(query)
    Agent->>Tool: stat_call_night_summary()
    Tool->>Night: 查询夜间通话统计
    Agent->>Tool: stat_call_continuous_summary()
    Tool->>Continuous: 查询连续通话统计
    Agent->>Tool: stat_call_sensitive_summary()
    Tool->>Sensitive: 查询敏感通话统计

图示来源

  • CallAnalysisTool.java
  • CallAnalysisToolTest.java
  • CallRecordService.java
  • CallNightService.java
  • CallContinuousService.java
  • CallSensitiveService.java

关键组件详解

通话记录控制器与服务

CallRecordController 暴露了 /cr/getCallRecord 接口,接收 CallRecordQuery,返回 Result<Page<CallRecord>>。这是一个简洁的 REST 接口设计,把具体查询逻辑交给 CallRecordService。

CallRecordService 继承 MyBatis Plus 的 ServiceImpl,说明它复用通用 CRUD 和分页能力,再叠加通话业务逻辑。

章节来源

  • CallRecordController.java:1-38
  • CallRecordService.java

夜间通话分析

夜间通话分析由 CallNightService 处理,输入是 CallNightQuery,输出是 CallNightDTO。典型输出包括:

字段 含义
time 时间段标识,例如夜间某个小时区间
otherName、personName 对方和本方姓名
otherPhone 对方号码集合,可能以逗号分隔
callCount 该时间段通话次数
totalMonthCount 跨越的月份总数
startHour、endHour 夜间时段起止小时

夜间通话的价值在于发现非正常作息下的联络行为,例如深夜频繁通话、长期只在夜间联系的固定关系。

章节来源

  • CallNightService.java
  • CallNightQuery.java:1-16
  • CallNightDTO.java:1-57

连续通话分析

连续通话分析由 CallContinuousService 处理,输入是 CallContinuousQuery,输出是 CallContinuousDTO。核心输出包括:

字段 含义
personName、personPhone 本方信息
otherName、otherPhone、otherPhones 对方信息,可能合并多个号码
pairContMonthCount 连续通话月份数
pairTotalCalls 该关系总通话次数
continuousStartMonth、continuousEndMonth 连续区间起止月份

连续通话常用于判断两人是否存在长期稳定的社交关系。例如,连续六个月以上每月都有通话,比短期高频通话更能体现关系稳定性。

章节来源

  • CallContinuousService.java
  • CallContinuousQuery.java:1-24
  • CallContinuousDTO.java:1-37

敏感通话分析

敏感通话分析由 CallSensitiveService 处理,输入是 CallSensitiveQuery,输出是 CallSensitiveDTO。敏感通话的重点是“对方”是否值得关注:

字段 含义
personName 本方姓名
otherName 对方姓名
otherPhone 对方号码
callCount 通话次数

敏感通话可以结合外部黑名单、重点关注名单、历史案件线索进行筛选。

章节来源

  • CallSensitiveService.java
  • CallSensitiveQuery.java:1-22
  • CallSensitiveDTO.java:1-30

通话开放信息

CallOpenInfoService 管理号码开户信息,对应 call_opening_info 表。关键字段包括:

字段 含义
phoneType 号码类型
operatorId 运营商
personPhone 号码
personType 用户类型
personName 使用人姓名
personCertNo 使用人证件号
province、city 归属省、市
phoneStatus 号码状态
activationDateTime 入网时间
closingDateTime 销户时间
firstCallDateTime 首次通话时间
lastSuspensionDateTime 最后停机时间

开放信息适合用来:

  • 校验通话记录中的号码是否真实存在
  • 判断号码是否在通话发生时已入网
  • 判断号码是否已销户或停机
  • 对比号码归属地与通话归属地是否一致

章节来源

  • CallOpenInfoService.java
  • CallOpenInfoMapper.java
  • CallOpenInfo.java:1-138
  • case_table.sql:223-246

依赖关系分析

通话模块内部依赖关系如下:

graph LR
    A["CallRecordController"] --> B["CallRecordService"]
    C["CallNightController"] --> D["CallNightService"]
    E["CallContinuousController"] --> F["CallContinuousService"]
    G["CallSensitiveController"] --> H["CallSensitiveService"]
    I["CallOpenInfoService"] --> J["CallOpenInfoMapper"]

    B --> K["CallRecordMapper"]
    D --> L["CallNightMapper"]
    F --> M["CallContinuousMapper"]
    H --> N["CallSensitiveMapper"]

    K --> O["call_record"]
    L --> O
    M --> O
    N --> O
    J --> P["call_opening_info"]

图示来源

  • CallRecordController.java:1-38
  • CallRecordService.java
  • CallNightService.java
  • CallContinuousService.java
  • CallSensitiveService.java
  • CallOpenInfoService.java
  • case_table.sql:90-246

外部依赖主要包括:

  • Spring Web:控制器注解、REST 接口
  • MyBatis Plus:分页、实体映射
  • Hutool:转换、字符串处理
  • Guava:列表拼接、集合工具
  • Lombok:简化实体类
  • Agent 工具框架:通过 CallAnalysisTool 暴露通话分析能力

章节来源

  • CallRecord.java:1-200
  • CallAnalysisToolTest.java

性能与索引优化

已有索引

通话记录表已创建以下索引:

索引名 列 作用
idx_call_record_person_name personName 按本方姓名查询
idx_call_record_person_phone personPhone 按本方号码查询
idx_call_record_other_name otherName 按对方姓名查询
idx_call_record_other_phone otherPhone 按对方号码查询

开放信息表已创建:

索引名 列 作用
idx_call_opening_info_person_phone personPhone 按号码查开户信息
idx_call_opening_info_person_name personName 按姓名查开户信息

章节来源

  • case_table.sql:123-126
  • case_table.sql:245-246

推荐索引优化

对于大数据量通话模块,建议增加以下索引:

建议索引 列组合 原因
时间范围索引 callDate、callDateTime 绝大多数查询会带时间范围
主被叫组合索引 callDirection、personPhone 常见于按本方号码和主被叫方向查询
对方关系索引 otherPhone、otherName 支持对方号码、对方姓名的联合查询
基站索引 personRegionId、personCellId 支持按基站区域或小区定位通话
文件来源索引 fileId、sheetId 支持按数据源隔离查询

时间范围查询如果没有 callDate 或 callDateTime 索引,容易退化为全表扫描,尤其在通话记录达到千万级时影响显著。

分区策略

如果通话记录数据量很大,可按时间分区:

分区方式 优点 缺点
按月分区 与连续通话、夜间通话按月分析契合 维护分区较多
按日分区 适合高频增量写入 分区过多
按年份分区 结构简单 时间粒度粗

推荐优先按“年+月”或“月”分区,配合 callDate 索引,使时间范围查询既能走分区裁剪,又能走索引扫描。

查询性能注意事项

  1. 避免无时间范围的宽泛查询:如不传 startTime、endTime,可能扫描整表。
  2. 优先使用唯一性强的条件:personPhone、personCertNo、id 优于 personName。
  3. 合理使用分页:避免一次性拉取大量通话记录。
  4. 慎用 LIKE 模糊查询:尤其是 %xxx% 形式,难以命中索引。
  5. 避免在应用层重复聚合:能由 SQL 完成的聚合尽量放在数据库层。
  6. 区分明细表和统计表:概览用 person_call_stat、phone_call_stat,明细用 call_record。
  7. 注意号码格式不一致:应用层或 SQL 层应先标准化号码,再参与 JOIN 或 GROUP BY。

常见问题排查

查询不到通话记录

可能原因:

  • 查询条件为空或未设置时间范围。
  • 使用了错误的号码格式,例如带前缀、空格。
  • 本方号码与对方号码混淆。
  • 数据尚未入库或属于其他 fileId、sheetId。
  • 分页参数过大,导致第一页为空。

排查建议:

  1. 先用 id 或 personPhone 精确查询。
  2. 缩小时间范围。
  3. 检查 callDirection 是否为主叫或被叫。
  4. 确认数据来源 fileId、sheetId。

夜间通话结果为空

可能原因:

  • nightStart、nightEnd 配置不合理。
  • callTime 为空或格式异常。
  • 数据本身不在夜间时段。
  • 对方号码或姓名过滤过严。

排查建议:

  1. 先查全部通话,确认 callTime 分布。
  2. 调整夜间时段,例如 22:00 至次日 6:00。
  3. 暂时移除 otherName、otherPhone 过滤。

连续通话未识别

可能原因:

  • 连续月份阈值 monthVal 过高。
  • 通话集中在某个月,没有跨月连续。
  • 号码变化导致同一人不同号码未被合并。
  • 去重策略把连续通话合并掉了。

排查建议:

  1. 降低 monthVal 阈值。
  2. 先按人+对方号码分组看月度通话。
  3. 检查号码标准化逻辑。
  4. 查看 CallContinuousDTO 中的连续起止月份。

敏感通话漏报

可能原因:

  • 敏感名单未包含目标号码。
  • 高频阈值设置过高。
  • 通话记录不完整。
  • 对方号码存在别名或变体。

排查建议:

  1. 检查敏感名单是否包含目标号码。
  2. 放宽高频阈值进行测试。
  3. 核对通话记录是否完整。
  4. 结合 call_opening_info 验证号码有效性。

章节来源

  • CallNightQuery.java:1-16
  • CallContinuousQuery.java:1-24
  • CallSensitiveQuery.java:1-22
  • CallRecordQuery.java:1-92

结论

通话模块 call 是整个调查数据体系中的重要基础模块。它以通话记录为核心,向上支撑夜间通话、连续通话、敏感通话等业务分析,向外与人员、交易、轨迹、治理树产生交叉关系,向内通过开放信息完善号码身份。

在实际使用中,应重点关注:

  1. 明确“本方”和“对方”的身份边界。
  2. 使用时间与号码作为主要过滤条件。
  3. 在号码匹配中加入姓名、证件号校验。
  4. 对连续通话按月观察,对敏感通话结合重点名单。
  5. 对大数据量场景增加时间、主被叫、基站等索引,并考虑按时间分区。
  6. 优先使用预统计表做概览,使用明细表做证据溯源。

这样,通话模块不仅能回答“某人打过哪些电话”,还能进一步回答“他和谁建立了稳定关系”“是否存在异常夜间联络”“是否频繁联系敏感对象”,从而服务于更完整的调查分析。