一、什么是图数据库
图数据库基于图数据模型的数据库系统,其中数据以节点(vertices)和边(edges)的形式表示,并通过节点和边之间的关系来组织和连接数据,节点通常代表实体(如人物、地点、物品等),而边则表示这些实体之间的关系(比如关系、连接、交互等)。每个节点和边都可以具有属性(properties),这些属性是关于节点或边的附加信息。
二、图数据库有什么用
图数据库适用于许多不同领域的应用,例如社交网络分析、推荐系统、网络安全、物流和路线优化等。世界上几乎所有领域的事物都有内在联系,关系型数据库这样的建模系统会提取实体之间的关系,并将关系单独存储到表和列中,而实体的类型和属性存储在其他列甚至其他表中,这使得侧重通过关系连接实体的数据管理费时费力。与传统的关系型数据库相比,图数据库更适合处理复杂的关系和连接,因为它们能够更有效地表示和查询这些关系。
三、什么是NebulaGraph
NebulaGraph 是一款开源的、分布式的、易扩展的原生图数据库,能够承载包含数千亿个点和数万亿条边的超大规模数据集,并且提供毫秒级查询。
四、NebulaGraph架构
NebulaGraph 由三种服务构成:Meta 服务、Graph 服务和 Storage 服务,是一种存储与计算分离的架构。以下是官方架构图:
Meta 服务是管家,主要作用是数据管理,比如Schema 操作、集群管理和用户权限管理等。
Graph 服务负责处理查询请求,包括解析查询语句、校验语句、生成执行计划以及按照执行计划执行四个大步骤。
Storage 服务负责具体数据相关的存储。Storage 服务定义了一系列和图相关的 API,例如:
- getNeighbors:查询一批点的出边或者入边,返回边以及对应的属性,并且支持条件过滤。
- insert vertex/edge:插入一条点或者边及其属性。
- getProps:获取一个点或者一条边的属性。
五、NebulaGraph数据模型
NebulaGraph 使用有向属性图模型,也就是点和边构成的图,并且这些边是有方向的,点和边都可以有属性。有6种基本的数据模型:
- 图空间(Space):图空间用于隔离不同团队或者项目的数据,不同图空间的数据是相互隔离的,可以指定不同的存储副本数、权限、分片等。
- 标签(Tag):点的schema,由一组事先预定义的属性构成。类似MySQL的表结构。
- 边类型(Edge type):边的schema,由一组事先预定义的属性构成。也类似MySQL的表结构。
- 属性(Property):属性是指以键值对形式表示的信息,一个Tag和Edge type可以定义多个属性。类似MySQL中的字段。
- 点(Vertex):点用来保存实体对象,一个点类似MySQL中实体表的一条记录,特点如下:
a. 点是用点标识符(VID)标识的。VID在同一图空间中唯一。VID 是一个 int64,或者 fixed_string(N)。
b. 点可以有 0 到多个 Tag。多个Tag类似MySQL的多表join后的一条记录。 - 边(Edge):边是用来连接点的,表示两个点之间的关系或行为,一条边类似MySQL中关系表的一条记录,特点如下:
a… 两点之间可以有多条边。
b. 边是有方向的,不存在无向边。
c. 四元组 <起点 VID、Edge type、边排序值 (rank)、终点 VID> 用于唯一标识一条边。边没有 EID。
d. 一条边有且仅有一个 Edge type。
e. 一条边有且仅有一个 Rank,类型为 int64,默认值为 0。Rank 可以用来区分 Edge type、起始点、目的点都相同的边。该值完全由用户自己指定。
六、NebulaGraph数据存储方式
数据存储: 使用 RocksDB 作为本地存储引擎,实现了自己的 KVStore,存储的主要数据是点和边。NebulaGraph 将点和边的信息存储为 key,同时将点和边的属性信息存储在 value 中,以便更高效地使用属性过滤。
索引: 为了提高查询性能,NebulaGraph 支持为点的 Tag 或 Tag 的某个属性,边的 Edge type 或 Edge type 的某个属性创建索引。索引可以基于指定的 Tag、Edge type、属性查询数据,但是索引本身不存储数据,而是存储数据的位置。索引只用来针对纯属性条件出发查询场景的功能,从一个点开始向外拓展的查询,根据VID查询不需要索引。NebulaGraph 支持两种类型索引:原生索引和全文索引。
- 原生索引:在本地和点数据被一起存储、分片。原生索引可以基于指定的属性查询数据。
- 全文索引:全文索引是基于 Elasticsearch 来实现的,用于对字符串属性进行前缀搜索、通配符搜索、正则表达式搜索和模糊搜索,有如下特点:
七、NebulaGraph使用示例
(1)快速安装NebulaGraph
- 下载并安装 Docker Desktop。
- 在Docker Desktop搜索栏搜索 NebulaGraph插件,并点击安装
(2)Docker Desktop切换到NebulaGraph页面,点击Get Started栏,再点击“Studio”进入控制台
(3)通过NebulaGraph控制台创建Space、Tag和Edge type
例如以下:
Space:test
Tag:patient、doctor
Edge type:follow、assist
(4)通过代码SessionPool的方式写入点和边,并查询数据
public class TestNebulaGraph {
public static void main(String[] args) {
List<HostAddress> addresses = Arrays.asList(new HostAddress("127.0.0.1", 9669));
String spaceName = "test";
String user = "root";
String password = "nebula";
SessionPoolConfig sessionPoolConfig =
new SessionPoolConfig(addresses, spaceName, user, password)
.setMaxSessionSize(10)
.setMinSessionSize(10)
.setRetryConnectTimes(3)
.setWaitTime(100)
.setRetryTimes(3)
.setIntervalTime(100);
SessionPool sessionPool = new SessionPool(sessionPoolConfig);
if (!sessionPool.init()) {
return;
}
ResultSet resultSet;
try {
//创建点(医生"牛大壮"和"史铁柱")
sessionPool.execute("INSERT VERTEX doctor (id, name) VALUES \"d1\":(1, \"牛大壮\"), \"d2\":(2, \"史铁柱\")");
//创建点(患者"张三"和"李四")
sessionPool.execute("INSERT VERTEX patient (id, name) VALUES \"p1\":(1, \"张三\"), \"p2\":(2, \"李四\")");
//创建点(既是患者"历飞雨"又是医生"韩立")
sessionPool.execute("INSERT VERTEX patient (id, name),doctor(id, name) VALUES \"pd1\":(3, \"历飞雨\",3,\"韩立\")");
//创建边("牛大壮" (协助)-> "史铁柱")
sessionPool.execute("INSERT EDGE assist (status, create_time) VALUES \"d1\"->\"d2\":(1, 1714381792084)");
//创建边("张三" (关注)-> "牛大壮")
sessionPool.execute("INSERT EDGE follow (status, create_time) VALUES \"p1\"->\"d1\":(1, 1714270192000)");
//创建边("张三" (关注)-> "史铁柱")
sessionPool.execute("INSERT EDGE follow (status, create_time) VALUES \"p1\"->\"d2\":(1, 1714183740000)");
//创建边("李四" (关注)-> "史铁柱")
sessionPool.execute("INSERT EDGE follow (status, create_time) VALUES \"p2\"->\"d2\":(1, 1711519740000)");
//查询边
resultSet = sessionPool.execute("MATCH ()-[e]->() RETURN e LIMIT 10;");
System.out.println(resultSet.toString());
} catch (IOErrorException | ClientServerIncompatibleException | AuthFailedException
| BindSpaceFailedException e) {
e.printStackTrace();
sessionPool.close();
System.exit(1);
}
}
}
(5)也可以通过控制台查询数据
MATCH ()-[e]->() RETURN e LIMIT 10;