图数据模型:节点、边、属性

上一章我们把图数据库环境搭起来了,也跑了几个简单的查询。但你有没有想过一个问题——图到底是怎么组织数据的?

嗯,我自己刚入行那会儿,总觉得图就是个“大网”,节点就是人,边就是关系。但其实如果不搞清楚节点、边、属性这三者的边界,后面做变量衍生很容易翻车。今天我们就来拆开揉碎了讲清楚。

节点:图的“故事主角”

节点是图里最基本的实体。在反欺诈场景里,它可以是用户、设备、手机号、IP地址、银行卡……总之,任何你想分析的对象,只要能独立存在,就应该建成一个节点。

节点之间是平等的,没有谁“挂”在谁下面。不像关系型数据库里一张订单表必须依赖用户表的主键。图里每个节点都有自己的唯一标识(通常是 id 或 uuid),你可以通过标签(Label)来分类。

我的经验:早期我做设备指纹关联时,把IMEI和MAC地址都放在一个“设备”标签下,结果发现同一台设备在不同时间可能换MAC。后来我改成按“硬件指纹”唯一标识,IMEI和MAC分别作为属性存。这个坑让我多花了三天重跑数据。

节点标签的命名,我建议用驼峰式、名词单数::User、:Device、:Phone、:IpAddress。别偷懒用拼音或缩写,团队其他人会恨你的。

边:关系的“动词”

边就是两个节点之间的连接。如果说节点是名词,那边就是动词——它描述了节点之间“做了什么”或“是什么关系”。

在反欺诈中常见的边类型:

  • :LOGIN — 用户登录设备
  • :TRANSFER — 用户向银行卡转账
  • :SHARE_SAME_IP — 两个用户共用过同一个IP(过去式)
  • :CONTACT — 用户之间有过通话或短信

边必须有方向。图数据库里的边默认是有向的,从起始节点指向目标节点。如果关系是双向的(比如“共用一个设备”),你可以建两条边,或者用无向语义处理(查询时忽略方向)。我个人倾向建单向边,查询时通过方向参数控制,更灵活。

注意:别把边当属性存!我曾经见过有人把“登录次数”做成边上的属性,然后在边标签里写 :LOGIN_TIMES。逻辑上不对,因为一条边只代表一次事件,次数是聚合后才有的东西。老老实实把每次登录事件存成一条边,查询时再 count。

属性:附着在节点和边上的“细节”

节点和边都可以挂属性。属性就是键值对,比如用户的注册时间、设备的操作系统版本、转账的金额和时间。

属性不能独立存在,必须依附于节点或边。它的作用就是补充描述——让节点更具体,让边更丰富。

属性设计有几个原则:

  1. 原子性— 一个属性只存一个值。别把“北京-朝阳-望京”塞到一个 address 字段里,拆成 province/city/district 三个属性。
  2. 选择合适类型— 数值、字符串、布尔、时间戳、列表(有些图库支持列表类型)。时间戳统一用 datetime 或毫秒级整数,避免时区问题。
  3. 避免存储大文本— 比如用户简介、备注等长篇文字,建议放外部存储,图里只存一个索引或指针。否则查询性能会急剧下降。
元素示例关键点
节点 :Userid=1, name='张三', reg_time=2023-01-15每个用户一个节点,标签统一为 :User
节点 :Deviceid=D001, os='iOS 16', screen_size=6.1硬件指纹做唯一标识,属性存设备特征
边 :LOGINfrom (:User) → to (:Device), time=2024-03-10 08:30:00每次登录创建一条边,时间戳作为边属性
边 :TRANSFERfrom (:User) → to (:BankCard), amount=5000, time=...金额、时间、渠道都可以放边属性

属性在变量衍生中的作用:节点属性可以直接拿来当特征,比如“用户注册天数”。边上的属性往往需要聚合,比如“过去7天该用户登录不同设备的次数”。这部分我们后面几章会专门讲,这里先记住:属性是手工造特征的原材料。

一个小技巧:建图之前,先画一张数据模型的草图——哪些实体是节点,哪些关系是边,节点和边上需要哪些属性。我当时拿着白板画了半小时,后面写导入脚本只花了半天。相反,我有个同事直接上手写 Cypher,结果改了四版数据模型,心态都崩了。

图数据模型的直观理解

下面这张图展示了反欺诈中典型的“用户-设备-IP”模型。节点用不同颜色区分标签,边用带方向箭头的关系连接,属性用小标签挂载在旁边。

反欺诈图数据模型示例(节点·边·属性) :User id=1001 name=张三 :Device hwid=D001 os=iOS16 :IpAddress ip=10.0.0.1 :LOGIN time=2024-03-10 08:30 :USED_AT time=2024-03-10 08:31 模型说明 • 节点(蓝、绿、红)代表不同的实体,每个都有标签和属性。 • 边(灰箭头)代表事件或关系,带方向,边属性记录时间等细节。 • 属性是键值对,附着在节点或边上。属性不能单独存在。 • 实际反欺诈图可能包含几十种节点类型和上百种边类型,但模型框架一样。 (节点属性示例)

画完这个图,你应该能立刻理解:节点是“谁”,边是“干了什么”,属性是“具体细节”。这三者缺一不可。后续所有变量衍生,本质上都是在节点和边的属性和关系上做统计、聚合、路径计算。

避坑指南

我曾经犯过一个错:把日期直接以字符串形式存成属性,比如 '2024-03-10'。后来做时间差计算时,发现图数据库不支持字符串减法,还得先转换。我花了一下午改全量数据。正确做法:存成 datetime 类型或毫秒级整数 1709993400000。

个人习惯:在一个新图谱项目开始时,我会先用一个简单的 CREATE 语句创建 3-5 个节点和几条边,然后用 MATCH 把图全量返回看看。确保节点标签、边类型和属性名称都没问题后,再正式写大批量导入脚本。这个“快速验证”的习惯帮我避免了至少 80% 的返工。