公司让我调研下图数据库,本文是对Nebula官方教程和社区实践的的一个整理.
中间发生了一个趣事,
在某一个微信群,谈到了图数据时,得到的回答是
图是什么
图论始于 18 世纪初期的柯尼斯堡七桥问题。柯尼斯堡当时是普鲁士的城市,普雷格尔河穿过柯尼斯堡,不仅把柯尼斯堡分成了两部分,而且还在河中间形成了两个小岛。这就将整个城市分割成了四个区域,各区域由七座桥连接。在所有的桥都只能走一遍的前提下,如何能把这个地方所有的桥都走一遍呢?
欧拉发表的相关论文被认为是图论领域的第一篇文章,因此普遍认为欧拉是图论的创始人。
一张图由一些小圆点(称为顶点或节点,即 Vertex)和连接这些圆点的直线或曲线(称为边,即 Edge)组成。
- 节点,即对象或实体。通常简称为点(Vertex)。
- 节点之间的关系,通常简称为边(Edge)。通常边是有方向或者无方向的,以表示两个实体之间有持续的关系。
股权关系
点通常是一个自然人或者是一家企业,边通常是某自然人与某企业之间的股权关系。
点上的属性可以是自然人姓名、年龄、身份证号等。边上的属性可以是投资金额、投资时间、董监高等职位关系。
权力的游戏
点为人物,边为人物之间的互动关系;点的属性为人物姓名、年龄、阵营等,边的属性(距离)为两个人物之间的互动次数,互动越频繁距离越近。
黑产关系分析
在一个黑产账户和设备网络中,其中的点可以是账户、手机设备和 WIFI 网络,边是这些账户与手机设备之间的登录关系,以及手机设备和 WIFI 网络之间的接入关系。
这些登录记录的网络构成了黑产群体网络的团伙作案特征。360 数科、快手、微信、知乎、携程金融这些公司都通过图技术实时(毫秒级的)识别超过百万个的黑产社群。
推荐系统
地理位置与图的结合也可以用于一些 O2O 的场景,例如基于 POI(Point-of-Interest)的实时美食推荐,使得美团这类本地生活服务平台公司能在消费者在打开 APP 的时候,实时推荐出更为合适的商家。
使用范围总结
欺诈检测
金融机构必须仔细研究大量的交易信息,才能检测出潜在的金融欺诈行为,并了解某个欺诈行为和设备的内在关联。这种场景可以通过图来建模,然后借助 NebulaGraph,可以很容易地检测出诈骗团伙或其他复杂诈骗行为。
推荐系统
NebulaGraph 能够及时处理访问者产生的实时信息,并且精准推送文章、视频、产品和服务。
知识图谱
自然语言可以转化为知识图谱,存储在 NebulaGraph 中。用自然语言组织的问题可以通过智能问答系统中的语义解析器进行解析并重新组织,然后从知识图谱中检索出问题的可能答案,提供给提问人。
社交网络
人际关系信息是典型的图数据,NebulaGraph 可以轻松处理数十亿人和数万亿人际关系的社交网络信息,并在海量并发的情况下,提供快速的好友推荐和工作岗位查询。
为什么要使用图数据库
虽然关系型数据库与 XML/JSON 等半结构类型的数据库,都可以用来描述图结构的数据模型,但是,图(数据库)不仅可以描述图结构与存储数据本身,更着眼于处理数据之间的关联(拓扑)关系.
优点包括以下:
- 图是一种更直观、更符合人脑思考直觉的知识表示方式。这使得我们在抽象业务问题时,可以着眼于“业务问题本身”,而不是“如何将问题描述为数据库的某种特定结构(例如表格结构)”。
- 图更容易展现数据的特征,例如转账的路径、近邻的社区
- 图查询语言是针对图结构访问设计的,可以更加直观。
- 由于存储引擎和查询引擎可以针对图的结构专门设计,图的遍历(对应 SQL 中的 join)要高效得多。
- 图数据库具有广泛的适用场景。例如数据集成(知识图谱)、个性化推荐、欺诈与威胁检测、风险分析与合规、身份(与控制权)验证、IT 基础设施管理、供应链与物流、社交网络研究等。
- 图数据库用图来存储数据,而图是最接近高度灵活、高性能的数据结构之一
- 图数据库是一种专门用于存储和检索庞大信息网的存储引擎,它能够高效地将数据存储为点和边,并允许对这些点边结构进行高性能的检索和查询。
与比较PostgreSQL
要求:查找某人(Person)在社交网络上发布的帖子(Posts);查找相应的回复(Message,回复本身还会被多次回复);发帖时间、回帖时间都满足一定条件;根据回帖数量对结果排序。
WITH RECURSIVE post_all(psa_threadid
, psa_thread_creatorid, psa_messageid
, psa_creationdate, psa_messagetype
) AS (
SELECT m_messageid AS psa_threadid
, m_creatorid AS psa_thread_creatorid
, m_messageid AS psa_messageid
, m_creationdate, 'Post'
FROM message
WHERE m_c_replyof IS NULL -- post, not comment
AND m_creationdate BETWEEN :startDate AND :endDate
UNION ALL
SELECT psa.psa_threadid AS psa_threadid
, psa.psa_thread_creatorid AS psa_thread_creatorid
, m_messageid, m_creationdate, 'Comment'
FROM message p, post_all psa
WHERE p.m_c_replyof = psa.psa_messageid
AND m_creationdate BETWEEN :startDate AND :endDate
)
SELECT p.p_personid AS "person.id"
, p.p_firstname AS "person.firstName"
, p.p_lastname AS "person.lastName"
, count(DISTINCT psa.psa_threadid) AS threadCount
END) AS messageCount
, count(DISTINCT psa.psa_messageid) AS messageCount
FROM person p left join post_all psa on (
p.p_personid = psa.psa_thread_creatorid
AND psa_creationdate BETWEEN :startDate AND :endDate
)
GROUP BY p.p_personid, p.p_firstname, p.p_lastname
ORDER BY messageCount DESC, p.p_personid
LIMIT 100;
如果使用为图专门设计的图语言 Cypher 编写查询语句:
MATCH (person:Person)<-[:HAS_CREATOR]-(post:Post)<-[:REPLY_OF*0..]-(reply:Message)
WHERE post.creationDate >= $startDate AND post.creationDate <= $endDate
AND reply.creationDate >= $startDate AND reply.creationDate <= $endDate
RETURN
person.id, person.firstName, person.lastName, count(DISTINCT post) AS threadCount,
count(DISTINCT reply) AS messageCount
ORDER BY
messageCount DESC, person.id ASC
LIMIT 100
效率比较
由于存储引擎和查询引擎可以针对图的结构专门设计,图的遍历(对应 SQL 中的 join)要高效得多。下图是知名产品 Neo4j 所做的一个对比。
图数据库
- 第一代图数据库的先行者 Neo4j
- 第二代(分布式)图数据库:Titan 和其后继者 JanusGraph
- 同期知名产品 OrientDB, TigerGraph, ArangoDB, 和 DGraph
- 新一代开源分布式图数据库 NebulaGraph
最佳实践分享案例
推荐场景
推荐基本都是基于用户喜好、物品的特征、用户与物品交互历史和其他相关上下文去做的。
一个推荐系统会包含以下几个部分:
数据、特征的处理
从特征出发,生成推荐列表
过滤、排序推荐列表
这其中,过滤的核心方法主要有两种:基于内容的过滤 Content-Based Filtering、与协同过滤 Collaborative Filtering
CBF,内容过滤的思想是利用领域知识、历史记录、元数据分别对用户和物件做画像、打标签,最终根据用户的标签与待推荐物件之间的距离评分进行排序给出相关推荐。
协同过滤主要可以分为两种:
User-User CF 基于多个用户对物件的历史行为,判定用户之间的相似性,再根据相似用户的选择推荐新的物件;
Item-Item CF 判断物件之间的相似性,给用户推荐他喜欢的物品相似的物品。
ItemCF 看起来和前边的 CBF 有些类似,核心区别在于 CBF 找到相似物件的方式是基于物件的“内容”本身,是领域知识的画像,而 ItemCF 的协同则是考虑用户对物件的历史行为。
https://discuss.nebula-graph.com.cn/t/topic/11491
风控场景
风控场景中使用到很多图挖掘算法,如:
高密度子图,一些异常账号和异常行为对象之间会存在高密度子图。
邻居域异常,异常节点、边、网络存在异常的形状(如星形散射状),即该账户的邻居域异常。
复杂网络,比如异常网络的度分布和正常网络的度分布是不同的。如有时挖掘了一些团伙,可以基于 Degree Sequence 构建特征和模型。不同 Degree Sequence 分布的网络存在不同的特性,这可以指导我们进一步构建拓扑相关特征。
https://discuss.nebula-graph.com.cn/t/topic/11705
DEMO操作
环境请自行搭建哦,增删改查四件套
CREATE SPACE basketballplayer(partition_num=15, replica_factor=1, vid_type=fixed_string(30));
USE basketballplayer;
CREATE TAG player(name string, age int);
CREATE TAG team(name string);
CREATE EDGE follow(degree int);
CREATE EDGE serve(start_year int, end_year int);
INSERT VERTEX player(name, age) VALUES "player100":("Tim Duncan", 42);
INSERT VERTEX player(name, age) VALUES "player101":("Tony Parker", 36);
INSERT VERTEX player(name, age) VALUES "player102":("LaMarcus Aldridge", 33);
INSERT VERTEX team(name) VALUES "team203":("Trail Blazers"), "team204":("Spurs");
INSERT EDGE follow(degree) VALUES "player101" -> "player100":(95);
INSERT EDGE follow(degree) VALUES "player101" -> "player102":(90);
INSERT EDGE follow(degree) VALUES "player102" -> "player100":(75);
INSERT EDGE serve(start_year, end_year) VALUES "player101" -> "team204":(1999, 2018),"player102" -> "team203":(2006, 2015);
//从 VID 为player101的球员开始,沿着边follow找到连接的球员。
GO FROM "player101" OVER follow YIELD id($);
//从 VID 为player101的球员开始,沿着边follow查找年龄大于或等于 35 岁的球员,
//并返回他们的姓名和年龄,同时重命名对应的列。
GO FROM "player101" OVER follow WHERE properties($).age >= 35
YIELD properties($).name AS Teammate, properties($).age AS Age;
从 VID 为player101的球员开始,沿着边follow查找连接的球员,然后检索这些球员的球队。为了合并这两个查询请求,可以使用管道符或临时变量。
GO FROM "player101" OVER follow YIELD dst(edge) AS id |
GO FROM $-.id OVER serve YIELD properties($).name AS Team,
properties($^).name AS Player;
//查询 VID 为player100的球员的属性。
FETCH PROP ON player "player100" YIELD properties(vertex);
//用UPDATE修改 VID 为player100的球员的name属性,然后用FETCH语句检查结果。
UPDATE VERTEX "player100" SET player.name = "Tim";
FETCH PROP ON player "player100" YIELD properties(vertex);
//用UPDATE修改某条边的degree属性,然后用FETCH检查结果。
UPDATE EDGE ON follow "player101" -> "player100" SET degree = 96;
FETCH PROP ON follow "player101" -> "player100" YIELD properties(edge);
//用INSERT插入一个 VID 为player111的点,然后用UPSERT更新它。
INSERT VERTEX player(name,age) VALUES "player111":("David West", 38);
UPSERT VERTEX "player111" SET player.name = "David", player.age = $^.player.age + 11
WHEN $^.player.name == "David West" AND $^.player.age > 20
YIELD $^.player.name AS Name, $^.player.age AS Age;
//删点.边
DELETE VERTEX "player111", "team203";
DELETE EDGE follow "player101" -> "team204";
//创建索引
CREATE TAG INDEX IF NOT EXISTS player_index_1 ON player(name(20));
//确保生效
REBUILD TAG INDEX player_index_1
//使用 LOOKUP 语句检索点的属性。
LOOKUP ON player WHERE player.name == "Tony Parker"
YIELD properties(vertex).name AS name, properties(vertex).age AS age;
nGql
nGQL(NebulaGraph Query Language)是 NebulaGraph 使用的的声明式图查询语言,支持灵活高效的图模式,而且 nGQL 是为开发和运维人员设计的类 SQL 查询语言,易于学习。
https://docs.nebula-graph.com.cn/3.4.1/3.ngql-guide/1.nGQL-overview/1.overview/
总结
图数据库可以极大的助力数据分析场景,
图数据库善于处理大量的、复杂的、互联的、多变的网状数据.
传统的关系型数据库,在处理复杂数据关系上表现得不是很完美。
如果对您有帮助,请关注一下这个二流程序员的公众号搜索-> 高级面试工程师,谢谢!