Files
cunkebao_v3/Moncter/技术方案.md

19 KiB
Raw Blame History

用户标签引擎技术方案(以身份证为主键)

一、目标与范围

  • 构建可扩展的用户标签引擎统一以身份证为主键的人person进行画像与筛选。
  • 支持多数据源接入(交易、行为、社群、外呼等),并聚合多个手机号、多个微信号到同一人。
  • 提供规则驱动的人群筛选、客群快照和线索分发能力,服务销售精细化运营。

0. 需求整合清单(共识)

  • 数据接入:多数据源/多数据库连接,按“数据源-表/接口”粒度定义 Job增量水位、批量与重试。
  • 标识治理:支持弱标识(手机号等)建“临时人”,获取强标识(身份证/unionid/客户号)后合并;全链路幂等与审计。
  • 标签体系:分通道层与人层;tag_dict 定义口径/类型/窗口/聚合/版本;标签写入包含 window/source/version。
  • 聚合计算:通道→人层遵循 aggregationsum/max/avg/any/best_of 等),支持实时触发与离线批处理。
  • 规则与人群DSL 配置、试算/执行、审计Redis 维护 cohort/位图,支持快照与导出。
  • 回灌与重算:规则或口径变更可对存量回评估;任务状态、错误与执行明细可观测、可重试。
  • 安全合规:身份证只存哈希(加盐),最小化数据使用,接口鉴权与导出留痕。

二、总体架构

  • 核心理念人层person是唯一真相通道层channel承载具体手机号/微信号等标识。
  • 组件分层:
    • 数据接入层:标准化事件/明细,写入通道层标签。
    • 聚合计算层:将通道层指标按口径聚合到人层标签。
    • 规则/人群层:基于人层标签做筛选、快照、导出与分发。
    • 存储与缓存MySQL字典/事实/审计)+ Rediscohort 人群集与位图)。

二点五、运行逻辑图(分层架构,数据流视角)

╔═════════════════════════════════════════════════════════════════════════╗
║                               数据源层                               ║
╚═════════════════════════════════════════════════════════════════════════╝
   ┌─────┐   ┌─────┐   ┌─────┐   ┌─────┐
   │交易系统│ │APP行为│ │客服系统│ │CRM │
   └─────┘   └─────┘   └─────┘   └─────┘
      │       │         │       │
      └───────┴─────────┘
           ▼
╔═════════════════════════════════════════════════════════════════════════╗
║                               接入层                                 ║
╚═════════════════════════════════════════════════════════════════════════╝
   ┌───────────────────────────────────────┐
   │  Job调度器   增量水位                │
   └───────────────────────────────────────┘
           ▼
   ┌───────────────────────────────────────┐
   │  标准化   校验                       │
   └───────────────────────────────────────┘
           ▼
╔═════════════════════════════════════════════════════════════════════════╗
║                               身份层                                 ║
╚═════════════════════════════════════════════════════════════════════════╝
   ┌───────────────────────────────────────┐
   │ IdentifierService                      │
   │ 手机号→person_id                       │
   └───────────────────────────────────────┘
           ▼
   ┌───────────────────────────────────────┐
   │ 临时人建表   强标识合并                │
   └───────────────────────────────────────┘
           ▼
╔═════════════════════════════════════════════════════════════════════════╗
║                               标签层                                 ║
╚═════════════════════════════════════════════════════════════════════════╝
   ┌───────────────────────────────────────┐
   │ channel_tags                           │
   │ 通道标签存储                           │
   └───────────────────────────────────────┘
           ▼
   ┌───────────────────────────────────────┐
   │ Aggregator                             │
   │ 聚合计算                               │
   └───────────────────────────────────────┘
           ▼
   ┌───────────────────────────────────────┐
   │ person_tags                            │
   │ 人层标签存储                           │
   └───────────────────────────────────────┘
           ▼
╔═════════════════════════════════════════════════════════════════════════╗
║                               规则层                                 ║
╚═════════════════════════════════════════════════════════════════════════╝
   ┌───────────────────────────────────────┐
   │ RuleEngine                              │
   │ DSL执行                                 │
   └───────────────────────────────────────┘
           ▼
   ┌───────────────────────────────────────┐
   │ Redis Cohort                            │
   │ 人群集合                               │
   └───────────────────────────────────────┘
           ▼
╔═════════════════════════════════════════════════════════════════════════╗
║                               应用层                                 ║
╚═════════════════════════════════════════════════════════════════════════╝
   ┌─────┐   ┌─────┐   ┌─────┐
   │人群查询│ │快照导出│ │分发推送│
   └─────┘   └─────┘   └─────┘

二点六、运行逻辑图(时序视角)

sequenceDiagram
    participant 业务系统 as 业务系统<br/>(交易/APP/客服)
    participant 接入服务 as 数据接入服务
    participant 身份服务 as 身份解析服务
    participant 通道标签 as channel_tags<br/>(存储)
    participant 聚合服务 as 聚合计算服务
    participant 人层标签 as person_tags<br/>(存储)
    participant 规则引擎 as 规则引擎
    participant 人群缓存 as Redis Cohort

    业务系统->>接入服务: 1. 推送事件/批量数据
    接入服务->>接入服务: 2. 标准化、校验、去重
    接入服务->>身份服务: 3. 解析标识<br/>(手机号/微信→person_id)
    身份服务-->>接入服务: 返回person_id<br/>(不存在则建临时人)
    接入服务->>通道标签: 4. 写入通道标签<br/>(幂等、window/source/version)
    
    通道标签->>聚合服务: 5. 触发聚合事件<br/>(实时/批量)
    聚合服务->>人层标签: 6. 按口径聚合<br/>(sum/max/avg/any)
    
    人层标签->>规则引擎: 7. 标签变更触发<br/>(受影响person_id)
    规则引擎->>规则引擎: 8. 执行DSL规则
    规则引擎->>人群缓存: 9. 更新cohort<br/>(SADD/SINTER)
    
    人群缓存-->>业务系统: 10. 人群查询/导出

二点七、运行逻辑图(简化版,核心路径)

graph TB
    Start([数据源<br/>交易/行为/客服/CRM]) --> Ingest[数据接入<br/>Job调度 + 标准化]
    Ingest --> Identity[身份解析<br/>手机号→person_id]
    Identity --> Channel[通道标签<br/>channel_tags]
    Channel --> Aggregate[聚合计算<br/>通道→人层]
    Aggregate --> Person[人层标签<br/>person_tags]
    Person --> Rule[规则引擎<br/>DSL筛选]
    Rule --> Cohort[人群集合<br/>Redis Cohort]
    Cohort --> Export([应用输出<br/>查询/快照/分发])
    
    Ingest -.->|状态| Audit1[(ingest_state)]
    Ingest -.->|错误| Audit2[(ingest_errors)]
    Rule -.->|执行记录| Audit3[(rule_executions)]
    
    style Start fill:#e1f5ff
    style Export fill:#e1f5ff
    style Ingest fill:#fff4e1
    style Identity fill:#e8f5e9
    style Channel fill:#f3e5f5
    style Aggregate fill:#f3e5f5
    style Person fill:#f3e5f5
    style Rule fill:#fff9c4
    style Cohort fill:#fff9c4

三、数据模型

-- 人:身份证(脱敏哈希)为主键
CREATE TABLE person (
  person_id       CHAR(32) PRIMARY KEY,     -- md5(uppercase(id_card_no_without_spaces))
  id_card_hash    CHAR(32) UNIQUE,
  name            VARCHAR(64) NULL,
  gender          TINYINT NULL,
  birthday        DATE NULL,
  created_at      DATETIME,
  updated_at      DATETIME
);

-- 标识绑定:一个人可有多个手机号/微信/外部ID
CREATE TABLE person_identifier (
  id              BIGINT PRIMARY KEY AUTO_INCREMENT,
  person_id       CHAR(32),
  id_type         ENUM('phone','wechat','external','email') NOT NULL,
  id_value        VARCHAR(128) NOT NULL,
  is_primary      TINYINT DEFAULT 0,
  verified        TINYINT DEFAULT 0,
  created_at      DATETIME,
  updated_at      DATETIME,
  UNIQUE KEY uk_type_value (id_type, id_value),
  KEY idx_person (person_id)
);

-- 标签字典
CREATE TABLE tag_dict (
  tag_code        VARCHAR(128) PRIMARY KEY, -- 例person.trade.arpu_90d
  name            VARCHAR(128),
  category        VARCHAR(64),
  level           ENUM('person','channel') NOT NULL,
  type            ENUM('int','bool','enum','set','string','float') NOT NULL,
  enum_values     JSON NULL,
  unit            VARCHAR(16) NULL,
  aggregation     ENUM('sum','max','min','avg','any','best_of') NULL, -- 通道→人层口径
  description     TEXT,
  version         INT DEFAULT 1,
  status          ENUM('draft','active','deprecated') DEFAULT 'active',
  owner           VARCHAR(64),
  created_at      DATETIME,
  updated_at      DATETIME
);

-- 人层标签(销售筛选用)
CREATE TABLE person_tags (
  person_id       CHAR(32),
  tag_code        VARCHAR(128),
  tag_value       VARCHAR(256),
  confidence      TINYINT DEFAULT 100,
  source          VARCHAR(64),
  window          VARCHAR(32),
  version         INT,
  updated_at      DATETIME,
  PRIMARY KEY (person_id, tag_code),
  KEY idx_tag (tag_code, tag_value)
);

-- 通道层标签(手机号/微信号维度)
CREATE TABLE channel_tags (
  id              BIGINT PRIMARY KEY AUTO_INCREMENT,
  id_type         ENUM('phone','wechat','external') NOT NULL,
  id_value        VARCHAR(128) NOT NULL,
  tag_code        VARCHAR(128),
  tag_value       VARCHAR(256),
  source          VARCHAR(64),
  window          VARCHAR(32),
  updated_at      DATETIME,
  UNIQUE KEY uk_dim (id_type, id_value, tag_code),
  KEY idx_tag (tag_code, tag_value)
);

-- 规则配置与执行审计
CREATE TABLE tag_rules (
  rule_id         BIGINT PRIMARY KEY AUTO_INCREMENT,
  name            VARCHAR(128),
  dsl             JSON,
  status          ENUM('draft','active','paused') DEFAULT 'active',
  schedule        VARCHAR(64) NULL,
  output_tag      VARCHAR(128) NULL,
  owner           VARCHAR(64),
  created_at      DATETIME,
  updated_at      DATETIME
);

CREATE TABLE rule_executions (
  exec_id         BIGINT PRIMARY KEY AUTO_INCREMENT,
  rule_id         BIGINT,
  started_at      DATETIME,
  finished_at     DATETIME,
  affected_users  INT,
  status          ENUM('success','failed','partial'),
  message         TEXT
);

四、标签规范

  • 分类:
    • 基础画像、行为活跃、交易能力、风险合规、社交关系、生命周期、设备画像、地域属性。
  • 命名:{level}.{category}.{name}_{window}
    • 人层:person.trade.arpu_90dperson.behavior.active_days_30d
    • 通道层:channel.wechat.group_join_30dchannel.phone.outbound_connect_7d
  • 口径:在 tag_dict 中声明 type/enum/range/aggregation/window/update_freq/version
  • 聚合:
    • 风险类any任一通道命中→人层命中
    • 活跃/价值max/sum/avg 视业务定义。
    • 可达性best_of如选近30日响应率最高的手机号

五、规则与人群DSL

{
  "name": "高潜付费人群",
  "logic": "AND",
  "conditions": [
    {"tag": "person.trade.arpu_90d", "op": "gte", "value": 500},
    {"tag": "person.behavior.active_days_30d", "op": "gte", "value": 10},
    {"tag": "person.risk.blacklist", "op": "eq", "value": false}
  ],
  "window": "rolling_90d",
  "ttl": "24h"
}

六、计算与刷新策略

  • 批处理T+1/T+0小时生成稳定画像交易统计、生命周期等
  • 准实时(秒级/分级):事件驱动更新通道层标签,触发对应人层增量聚合。
  • 回评估:字典/规则变更后对存量人群重算,并写入审计。

七、系统设计ThinkPHP 5.1

  • 目录结构(application/tag

    • controllerTagDictControllerRuleControllerSegmentControllerIdentifierController
    • modelTagDictPersonPersonIdentifierPersonTagsChannelTagsTagRulesRuleExecutions
    • service
      • IdentifierService(标识绑定/查找/合并)
      • ChannelTagService(通道标签写入)
      • PersonTagService(人层聚合/重算)
      • TagQueryService条件解析→Redis/DB组合查询
      • RuleEngineServiceDSL 校验/执行/审计)
      • CohortCacheServicecohort 维护、集合/位图运算)
    • commandExecuteRuleRecomputeTagsCohortSnapshot
  • 路由(建议,受 jwt 保护):

Route::group('v1/tag', function () {
  Route::get('dict', 'app\\tag\\controller\\TagDictController@index');
  Route::post('dict', 'app\\tag\\controller\\TagDictController@create');
  Route::post('identifier/bind', 'app\\tag\\controller\\IdentifierController@bind');
  Route::post('rule/execute/:id', 'app\\tag\\controller\\RuleController@execute');
  Route::post('segment/query', 'app\\tag\\controller\\SegmentController@query');
  Route::post('segment/snapshot', 'app\\tag\\controller\\SegmentController@snapshot');
})->middleware(['jwt']);

八、查询与筛选

  • 人层为主:person_tags 组合条件查询Redis 保存常用 cohort
    • Redis 示例:SINTER cohort:person.trade.arpu_90d:gt500 cohort:person.active_days_30d:gte10 SDIFF cohort:person.risk.blacklist:eq1
  • MySQL 组合查询示例:
SELECT DISTINCT t1.person_id
FROM person_tags t1
JOIN person_tags t2 ON t2.person_id=t1.person_id
LEFT JOIN person_tags t3 ON t3.person_id=t1.person_id AND t3.tag_code='person.risk.blacklist'
WHERE t1.tag_code='person.trade.arpu_90d' AND CAST(t1.tag_value AS DECIMAL)>=500
  AND t2.tag_code='person.behavior.active_days_30d' AND CAST(t2.tag_value AS SIGNED)>=10
  AND (t3.tag_value IS NULL OR t3.tag_value='0')
LIMIT 50 OFFSET 0;

九、关键流程

  1. 事件接入:收到 id_type + id_value(如手机号)→ 查 person_identifier → 得到 person_id
  2. 通道标签更新:写 channel_tags,并发布“聚合任务”。
  3. 人层聚合:按 tag_dict.aggregation 规则,更新 person_tags
  4. 规则评估:对受影响的 person_id 运行启用中的规则,更新 cohort/输出标签。
  5. 人群产出:支持分页查询、生成快照、导出或推送 CRM/外呼系统。

十、缓存与索引

  • Redis
    • 集合/位图存 cohortKey 规范:cohort:{tag_code}:{op}{value} 或区间桶。
    • TTL默认 24h可按规则 ttl 覆盖。
  • MySQL
    • person_tags(tag_code, tag_value)channel_tags(tag_code, tag_value) 倒排索引。
    • 审计表按时间分区或冷热分离。

十一、合规与安全

  • 身份证只存哈希(不可逆),不落明文;导出脱敏。
  • 最小权限访问,接口留痕审计(规则执行、导出、查看)。
  • 口径透明:标签保留来源、窗口、置信度、版本。

十二、里程碑(落地计划)

  • M1建表与服务骨架接入交易/行为两类数据产出10个核心标签。
  • M2规则试算与快照Redis cohort首批销售客群模板高价值流失预警
  • M3通道“最佳触达”策略CRM/外呼对接;质量监控与看板。