4、用户身份识别与统一:ID-Mapping技术、设备指纹、多源用户合并策略

做用户画像,最头疼的问题是什么?

我个人的经验是——你根本不知道「这个人」到底是谁。

一个用户可能在手机APP上叫「小明」,在PC网站上叫「xiaoming123」,在微信小程序里又变成了「明哥」。你想想看,如果系统认为这是三个人,那画像就全乱了。今天我们要聊的,就是怎么把这些碎片拼成一张完整的脸。

4.1 为什么需要ID-Mapping?

说白了,ID-Mapping就是给同一个用户的所有身份「对上号」。

一个真实用户,可能拥有这些标识:

  • 注册ID:用户在系统里注册的账号
  • 设备ID:手机IMEI、Android ID、IDFA(iOS)
  • Cookie ID:浏览器存储的匿名标识
  • 社交账号:微信OpenID、微博UID
  • 手机号/邮箱:实名信息

我在项目中遇到过最典型的场景:一个电商平台,用户在APP里浏览商品,加购物车,但没登录。这时候系统只知道他的设备ID。等他下单时登录了微信支付,微信OpenID就关联上了。再后来他绑定了手机号——好,三个ID终于串起来了。

核心目标:建立一张「ID关系图谱」,把分散的标识映射到同一个全局用户ID(Global User ID, GUID)上。

4.2 ID-Mapping的三种主流策略

嗯,这里要注意,没有一种策略是万能的。我根据实战经验,把常见策略分成三类:

4.2.1 确定性匹配(Deterministic Matching)

这是最靠谱的方式。基于强关联关系进行合并,比如:

  • 同一个手机号绑定的多个账号
  • 同一个身份证号对应的不同平台账号
  • 微信支付回调时返回的OpenID + 用户手机号

优点:准确率接近100%,没有误合并风险。

缺点:覆盖范围有限,很多用户没有提供强关联信息。

我的建议:确定性匹配应该作为ID-Mapping的「锚点」。先搞定这部分,再考虑其他策略。我曾经在一个项目中,先用手机号合并了60%的用户,剩下的再用概率匹配慢慢补。

4.2.2 概率匹配(Probabilistic Matching)

说白了,就是猜。但猜得有依据。

通过多个弱信号综合判断两个ID是否属于同一个人:

  • 相同的IP地址(尤其是家庭WiFi)
  • 相同的设备指纹
  • 相似的行为模式(比如都在凌晨2点活跃)
  • 相同的收货地址

我习惯给每个信号打一个权重分,总分超过阈值就合并。举个例子:

信号 权重 说明
相同IP(家庭宽带) 30 家庭IP通常稳定
相同设备指纹 40 设备指纹唯一性高
相同收货地址 50 强信号
相同WiFi BSSID 35 同一路由器

阈值我一般设在80分以上才合并。低于80分的,宁可放过,不要错杀。

避坑指南:我曾经把公司WiFi下的所有用户合并成一个人,结果发现是整层楼的同事共用同一个出口IP。那一次误合并率直接飙到15%。后来我加了「设备指纹」作为必要条件,才把误合并率压到1%以下。

4.2.3 图算法匹配(Graph-based Matching)

当数据量大了以后,用图数据库(比如Neo4j)来做ID-Mapping,效率会高很多。

每个ID是一个节点,ID之间的关系是边。通过连通分量算法(Connected Components),可以自动找出属于同一个人的所有ID。

# 伪代码示例:基于连通分量的ID合并
from collections import defaultdict

def build_id_graph(relations):
    graph = defaultdict(set)
    for id_a, id_b in relations:
        graph[id_a].add(id_b)
        graph[id_b].add(id_a)
    return graph

def find_connected_components(graph):
    visited = set()
    components = []
    for node in graph:
        if node not in visited:
            component = []
            stack = [node]
            while stack:
                current = stack.pop()
                if current not in visited:
                    visited.add(current)
                    component.append(current)
                    stack.extend(graph[current] - visited)
            components.append(component)
    return components

# 示例:手机号关联设备ID,设备ID关联Cookie
relations = [
    ('phone_138xxxx', 'device_abc123'),
    ('device_abc123', 'cookie_xyz789'),
    ('cookie_xyz789', 'wechat_openid_001'),
]
graph = build_id_graph(relations)
components = find_connected_components(graph)
# 输出:['phone_138xxxx', 'device_abc123', 'cookie_xyz789', 'wechat_openid_001']

图算法的好处是:不需要人工设定规则,能自动发现间接关联。但坏处是:如果图里有「噪声边」,会把不相干的人合并到一起。

4.3 设备指纹技术

设备指纹是ID-Mapping里最常用的「粘合剂」。为什么?因为用户可能不登录,但设备是固定的。

一个完整的设备指纹,通常包含这些信息:

  • 硬件信息:CPU型号、GPU型号、内存大小
  • 系统信息:操作系统版本、内核版本、语言设置
  • 网络信息:IP地址、MAC地址(现在受限)、WiFi BSSID
  • 浏览器信息:User-Agent、Canvas指纹、WebGL指纹、字体列表

我常用的设备指纹生成方式,是把这些信息拼接后做哈希:

import hashlib
import json

def generate_device_fingerprint(device_info):
    # 按固定顺序排列字段,保证一致性
    sorted_info = {
        'cpu': device_info.get('cpu'),
        'gpu': device_info.get('gpu'),
        'os': device_info.get('os'),
        'resolution': device_info.get('resolution'),
        'timezone': device_info.get('timezone'),
        'language': device_info.get('language'),
        'canvas_hash': device_info.get('canvas_hash'),
    }
    raw_string = json.dumps(sorted_info, sort_keys=True)
    return hashlib.sha256(raw_string.encode()).hexdigest()

我的经验:Canvas指纹在PC端准确率很高,但在移动端因为浏览器差异,经常变化。我建议移动端优先用「设备ID + WiFi BSSID」的组合,稳定性和唯一性都更好。

4.4 多源用户合并策略

合并策略,说白了就是「什么时候合并,什么时候不合并」。我总结了一个四步流程:

  1. 数据清洗:去掉无效ID(比如全是0的IMEI、过期的Cookie)
  2. 确定性合并:先处理手机号、身份证等强关联
  3. 概率性合并:用设备指纹+行为特征做弱关联
  4. 人工审核:对高价值用户(比如VIP)的合并结果做抽样验证

这里有个关键点:合并是单向的还是双向的?

我建议采用「单向合并」策略。什么意思呢?

  • 如果设备A和手机号B确定关联,那么设备A的所有历史行为都归到用户B名下
  • 但反过来,用户B的历史行为不能自动归到设备A上

这样做的好处是:避免把「共用设备」的场景搞乱。比如一家人共用一台iPad,设备指纹是同一个,但用户是不同的。单向合并可以保证:设备行为归到登录用户,但登录用户的历史不污染设备。

核心原则:宁可漏合并,不要误合并。误合并一个用户,会导致整个画像系统产生连锁错误。我见过最惨的案例,因为误合并,把两个完全不同的用户标签混在一起,推荐系统直接崩了三天。

4.5 实战中的避坑指南

最后,分享几个我踩过的坑:

  • 不要用IP做唯一标识:公司、学校、商场都是共享IP,一合并就出事
  • 注意ID的时效性:Cookie ID会过期,设备ID会重置,手机号会换。我习惯给每个关联关系加一个时间戳,超过30天没出现的关联自动降权
  • 保留合并历史:万一合并错了,要有能力「拆开」。我设计过一个回滚机制,每次合并都记录操作日志,可以一键撤销
  • 冷启动问题:新用户第一次访问,没有任何关联信息。这时候我建议先给他一个临时GUID,等收集到足够信号后再做正式合并

嗯,ID-Mapping这块内容,说起来简单,做起来全是细节。但只要你把确定性匹配做扎实了,设备指纹选对了,合并策略定清楚了,整个用户画像系统就有了最稳固的地基。