1. 引言
随着数据关联性的日益增强,传统关系型数据库在处理复杂关系和大规模连接查询时表现出瓶颈。图数据库以其强大的关系表达能力和高效的遍历性能,成为社交网络、推荐系统、知识图谱等领域的首选技术。NebulaGraph 作为一款开源分布式图数据库,具备高性能、可扩展的特点,适合处理海量图数据。
本文将带你一步步在 AWS EC2 上快速部署 NebulaGraph,并通过一个示例场景完成图数据的生成与分析,帮助你快速上手 NebulaGraph 图数据库的实战应用。
2. 准备工作
- 首先,确保你拥有一个有效的 AWS 账户,并且具备创建 EC2 实例、配置 VPC、EBS 等资源的权限。登录 AWS 管理控制台,检查你的资源配额,确保有足够的弹性 IP、EC2 实例配额等。
- 你可以选择在新的 VPC 中启动 EC2 部署 NebulaGraph,或使用已有的 VPC。部署前请确保在目标区域有可用的 EC2 密钥对,用于安全登录 EC2 实例。
- 本次测试环境使用的 EC2 机型是 c5a.2xlarge,可以提前创建一台。
3. 在 AWS EC2 上部署 NebulaGraph
NebulaGraph 采用计算与存储分离架构,部署包含 graphd
、storaged
和 metad
节点。以下是在同一台 EC2 上搭建 NebulaGraph graphd
、storaged
和 metad
3 个节点的过程。
登陆 EC2,下载启动 NebulaGraph:
sudo su ubuntu
cd ~
export NEBULA_VERSION=3.4.0
wget https://oss-cdn.nebula-graph.com.cn/package/${NEBULA_VERSION}/nebula-graph-${NEBULA_VERSION}.ubuntu2004.amd64.deb
sudo dpkg -i nebula-graph-${NEBULA_VERSION}.ubuntu2004.amd64.deb
sudo /usr/local/nebula/scripts/nebula.service start all
sudo /usr/local/nebula/scripts/nebula.service status all
下载 Nebula console ,以便通过命令行查询操作
wget https://github.com/vesoft-inc/nebula-console/releases/download/v${NEBULA_VERSION}/nebula-console-linux-amd64-v${NEBULA_VERSION}
chmod 111 ./nebula-console-linux-amd64-v${NEBULA_VERSION}
下载 Nebula importer,可以更方便、快速地导入数据
wget https://github.com/vesoft-inc/nebula-importer/releases/download/v${NEBULA_VERSION}/nebula-importer-linux-amd64-v${NEBULA_VERSION}
chmod 111 nebula-importer-linux-amd64-v${NEBULA_VERSION}
4. 图数据生成:创建图空间与导入数据
本次我们通过处理 MySQL 数据库中的几张表,来生成实体之间的依赖关系,这个实体对应图中的一个类型的点,如下图所示的 V1, 由于 V1 之间有依赖关系,如果从 MySQL 解析依赖关系需要多表关联且不确定依赖关系的层数,因此构建图来查找出最长的路径以及依赖和被依赖最多的点。我们将 V1 这个类型的点之间的边定义为 E1,由于相同的 V1 之间可能有不同周期的依赖关系,用 rank 来区分它们。
如上图所示,在点和边上,我们设置了 property,用来做更进一步的 filter,在边上,除了 property 之外还使用了 rank,用来区分两个点之间不同的边,关于 property 和 rank 的详细说明如下:
1. Rank 的作用
- Rank 是用来区分同一对起点(src_vid)和终点(dst_vid)之间多条边的唯一标识。
- 在 NebulaGraph 中,一条边由四元组唯一标识:
(src_vid, edge_type, rank, dst_vid)
。
- 如果两个边的起点、终点和边类型相同,但它们代表不同的关系或不同时刻的关系,就可以通过不同的 rank 值区分。
- 默认情况下,rank 值为 0,如果需要插入多条相同起点和终点的边,必须指定不同的 rank。
- 例如,A 和 B 之间有多次转账记录,每次转账可以用不同的时间戳作为 rank 区分。
2. Property(属性)的作用
- 属性是边或点携带的具体数据字段,用来描述边或点的详细信息。
- 属性是用户定义的键值对,比如时间、金额、状态等。
- 属性是边或点的内容,描述边边或点特征和业务含义。
- 例如,转账边或点属性可能包括转账金额、转账时间、备注等。
数据的生成使用 python 生成 csv 即可,一种点对应一个 csv 文件,一种边对应一个 csv 文件,点 csv 文件包括点的唯一标识 ID,后面的字段为 property 的具体值;边 csv 文件第一列是起点,第二列是终点的 ID,后面的字段为 property 以及 rank 的具体值。准备好 csv 文件后,可以按照格式准备以下 importer 的 yaml 配置文件,这里需要注意的是不同 NebulaGraph 的版本的 yaml 文件格式可能会有些许的差异,因此需要严格按照 Nebula Graph 的版本去官方文档获取 yaml 的格式。
config.yaml:
version: v2
description: data import
removeTempFiles: null
clientSettings:
retry: 3
concurrency: 10
channelBufferSize: 128
space: workflow_analysis
connection:
user: "root"
password: "pwd"
address: "127.0.0.1:9669"
postStart: null
preStop: null
logPath: import.log
workingDir: null
files:
- path: ./v1_vertex.csv
failDataPath: v1_vertex_FAIL_DATA
batchSize: 60
limit: null
inOrder: null
type: csv
csv:
withHeader: false
withLabel: false
delimiter: null
schema:
type: vertex
edge: null
vertex:
vid:
index: 0
function: null
type: string
prefix: null
tags:
- name: V1
props:
- name: name
type: int
index: 0
- name: project
type: int
index: 1
- path: ./E1_edge.csv
failDataPath: E1_FAIL_DATA
batchSize: 60
limit: null
inOrder: null
type: csv
csv:
withHeader: false
withLabel: false
delimiter: null
schema:
type: edge
edge:
name: E1
withRanking: null
props:
- name: duration_time
type: int
index: 2
srcVID:
index: 0
function: null
type: string
prefix: null
dstVID:
index: 1
function: null
type: string
prefix: null
rank:
index: 3
vertex: null
之后,通过 Nebula Console 来创建图的 schema:
./nebula-console-linux-amd64-v${NEBULA_VERSION} -addr localhost -port 9669 -u root -p pwd
CREATE SPACE `workflow_analysis` (partition_num = 1, replica_factor = 1, charset = utf8, collate = utf8_bin, vid_type = FIXED_STRING(128));
USE `workflow_analysis`;
CREATE TAG `V1` ( `name` int64 NOT NULL, `project` string NOT NULL) ttl_duration = 0, ttl_col = "";
CREATE EDGE `E1` ( `duration_time` int64 NOT NULL) ttl_duration = 0, ttl_col = "";
CREATE EDGE INDEX IF NOT EXISTS e1_duration_index ON E1(duration_time);
CREATE TAG INDEX IF NOT EXISTS v1_name_index ON V1(name);
:sleep 10
REBUILD TAG INDEX v1_name_index;
REBUILD EDGE INDEX e1_duration_index;
最后,在 EC2 上,通过 Nebula impoter 导入数据:
./nebula-importer-linux-amd64-v${NEBULA_VERSION} --config config.yaml
图数据分析实战
# 随机查询3个V1点
MATCH (v:V1) \
RETURN v \
LIMIT 3;
# 随机查询3条E1边
MATCH ()-[e:E1]->() \
RETURN e \
limit 3;
# 查询name为12345的点
MATCH (v:V1{ name: '12345' }) RETURN v;
# 查询从点12345开始、0~1 跳、所有 Edge type 的子图。
GET SUBGRAPH 1 STEPS FROM "12345" YIELD VERTICES AS nodes, EDGES AS relationships;
# 找出两个V1之间的最短路径
FIND SHORTEST PATH FROM "12345" TO "45678" OVER * YIELD path AS p;
# 某种依赖周期下被依赖最多的点,rank(e)==2代表其中一种依赖周期
MATCH (v:V1) \
WITH v LIMIT 1000000\
OPTIONAL MATCH (v2:V1)-[e:E1]->(v) \
WITH v, e \
WHERE rank(e)==2 \
WITH v, count(e) AS in_degree \
RETURN id(v) AS V1_id, in_degree \
ORDER BY in_degree DESC \
LIMIT 10;
# 查询最长的路径前10条,1-100跳
# 用path_length排序, 注意在有环的情况下这条语句不能执行,会打满内存
MATCH p = (v1:V1)-[e:E1*1..100]->(v2:V1) \
WITH p, \
relationships(p) AS rs, \
REDUCE(total = 0, e1 IN relationships(p) | total + e1.d_time) AS total_duration, \
length(p) AS path_length \
WHERE ALL(e2 IN relationships(p) WHERE rank(e2)==1) AND length(p) >= 1 \
RETURN p, total_duration, path_length \
ORDER BY path_length DESC \
LIMIT 10;
# 查找所有42条到12345的点,该语句执行不受环的影响,因为它只返回点,并不涉及路径
GO 42 STEPS FROM "12345" \
OVER E1 REVERSELY \
YIELD DISTINCT $$.V1.code AS code ;
# 查询"12345" TO "45678"之间的5跳及以下所有没有环的路径并limit其中一条
FIND NOLOOP PATH FROM "12345" TO "45678" \
OVER E1 \
UPTO 5 STEPS \
YIELD path AS p \
| ORDER BY $-.p DESC \
| LIMIT 1;
# 查询点有没有环,如果是多个点,则需要使用nebula python client 一一执行下面的语句
FIND ALL PATH FROM "v1_id1" TO "v1_id1" OVER E1 UPTO 10 STEPS YIELD path AS p
以上语句均扩展自 NebulaGraph官方文档,需要结合数据的实际情况及想要查询的逻辑和结果选择如何去使用。
性能与扩展建议
- 本次点的数量在 10w 以内,边的数量在 20w 以内,使用的机型可以支持高效的查询,如果您的数据量非常大,建议更换机型及使用集群模式来提高查询性能。
- 生成图数据时,如果是读数据库,建议读非生产环境的数据库生成。
- 在生产环境使用时,需要结合多副本 + 多可用区 + 负载均衡的设计来提高可用性。
总结与展望
- 通过本次在 NebulaGraph 上的分析,将原来在 MySQL 场景下多跳依赖关系的查询时间优化到了秒级,并且成功的找出了关系链中存在的环路,对它们进行拆解后可以提高业务测的运行效率。
- 随着图数据库与大数据、AI 的深度融合,图数据库 在智能分析、业务洞察、自动化决策等方面的应用潜力将持续释放。
- Nebula Graph 参考文档
本篇作者