图数据库使用及业务场景

首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164...
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca...

一. 前言

来学习下图数据以及图数据库

二. 图数据库的简单原理

2.1 图数据

我认为图数据结构就是点线面的关系,图大致分为以下概念 :

  • 节点 : 图中的基本元素,可以用来表示现实世界中的一个**实体 **
  • : 节点之间连接的线,用来描述实体之间的关系
    • 边可以有方向,有起始节点到终止节点
    • 边可以包含属性
  • 属性 :节点和边都可以包含属性,属性存储有关实体的信息
  • 权重权重指边上的一个值,用来标识成本,强度等等概念 (最短路径,最低消耗等)
  • 路径 :一个节点到另外一个节点的路程表示路径,一个路径可以包含多个节点多个边

分类

  • 按照图的方向性可以分为 :有向图,无向图
  • 按照边是否带权重可以分为 :有权图,无权图
  • 按照边的多少可以分为 : 稠密图,稀疏图
  • 按照特定类型包括 : 邻接矩阵、邻接表、关联矩阵

2.2 图数据案例

  • Neo4j: Neo4j是最受欢迎的图数据库之一,采用图结构来存储数据,并提供高效的图查询和遍历功能。Neo4j支持Cypher查询语言,适用于各种图数据分析任务
  • OrientDB : 一个多模型数据库,支持图数据库、文档数据库和对象数据库
  • Dgraph : 一个分布式图数据库,支持属性图和图数据库功能

好了,图的基本概念是清楚了,用法我们基于 Neo4j 来看

三. 图数据库 Neo4j

2.1 创建图数据库 Neo4j

可惜找了几个云服务商都没能薅羊毛,没看到可以免费领取的图数据库,所以只能自己安装下 Neo4j 了,简单点还是基于 Docker :

准备 docker-compose.yml

java 复制代码
version: '3'
services:
  neo4j:
    image: neo4j:latest
    container_name: neo4j
    ports:
      - "7474:7474"
      - "7687:7687"
    environment:
      NEO4J_AUTH: neo4j/test123456

安装运行

java 复制代码
docker-compose up -d

> 访问地址
http://localhost:7474/

2.2 弄清楚 Neo4j 里面的一些知识点

  • 可以通过配置创建多个Neo4j 实例,但是这种创建属于物理层面,需要修改底层配置
  • 不同于关系型数据库和NoSQL , 一个 Neo4j 实例里面只有一个主图多个子图(Enterprise版本才有子图)
  • 标签和属性更像一种分类,而不是单纯的看成节点的字段

支持的索引

  • 节点索引 :基于节点的属性创建索引
  • 关系索引 :用于关系的查找操作,基于关系的属性创建索引
  • 全文索引 :在节点的文本属性上创建,执行全文搜索查询
  • 空间索引 :用于地理空间数据 ,支持范围搜索和最近搜索
  • 时间/属性/组合等自定义索引 :其他的索引类型
java 复制代码
CREATE INDEX ON :Person(name)

2.3 Neo4j 使用流程

使用层面上我们首先创建一个人物画像/社交网络,用于后续的分析 :

S1 : 创建节点

  • 语法 : CREATE (node:Label {property: value})
  • node 是节点变量名,可以通过 return 返回这个变量,用于后续使用,本身无含义
  • property 表示节点的属性,键值对关系,可以有多个
  • label :节点标签,用来标识节点的类型
java 复制代码
CREATE (n1:User {name:'会员A',level:'1'}) RETURN n1;
CREATE (n2:User {name:'会员B',level:'2'}) RETURN n2;
CREATE (n3:User {name:'会员C',level:'3'}) RETURN n3;
CREATE (n4:User {name:'会员D',level:'4'}) RETURN n4;
CREATE (n5:User {name:'会员E',level:'5'}) RETURN n5;


// 创建节点的时候创建关系
CREATE (a:User {name:'会员F'})-[r:FRIENDS]->(b:User {name:'会员D'})

S2 : 查询节点

  • 查询所有节点 :MATCH (n:User {}) RETURN n
  • 查询特定属性 :MATCH (n:User {name:'会员A'}) RETURN n

👉查询到的结果 👇👇👇

S3 : 为节点创建关系

JAVA 复制代码
MATCH (startNode:Label1), (endNode:Label2)
CREATE (startNode)-[:RELATIONSHIP_TYPE]->(endNode)
  • MATCH 子句用于匹配起始节点(startNode)和结束节点(endNode),通常使用标签和属性来过滤节点
  • CREATE 子句用于创建关系,表示连接起始节点和结束节点
  • [:RELATIONSHIP_TYPE] 是关系的类型,可以替换为想要创建的关系类型
  • 箭头表示关系的方向,从起始节点指向结束节点
java 复制代码
// 创建 User 节点间的关系 (关系为朋友)
MATCH (a:User {name:'会员A'}), 
      (b:User {name:'会员B'}) 
MERGE (a)-[:FRIENDS]->(b)

// ↑↑↑↑ 解释
- 这里的 a 和 b 都是节点别名,用于创建关系时使用
- User 标识的是节点类型,查询这一类节点
- name 才是匹配节点的关联关系,这里是 name ,也可以是 id 等更加具体的属性

S4 : 关系查询

PS : 这里的 sn ,en 都是别名,表示是 startNode 、 endNode ,篇幅有限

java 复制代码
- 查询特定的关系的关系 :MATCH ()-[relation:FRIENDS]->() RETURN relation
- 查询有特定关系的节点 :MATCH (n)-[:FRIENDS]-() RETURN n
- 查询特定节点和关系   :MATCH (n:User)-[:FRIENDS]-(friend:User) RETURN n, friend

// 复杂查询
- 复杂语句 :MATCH (sn)-[relation]-(en) WHERE sn.name = '会员A' AND en.name = '会员B' RETURN relation
- 特定关系 :MATCH (sn)-[rl:FRIENDS]->(en) WHERE sn.name = '会员A' RETURN rl, en
- 查询属性 :MATCH ()-[relation:FRIENDS]->() RETURN relation.propertyName
- 查询数量 :MATCH (sn)-[rl]->(en) WHERE sn.name = '会员A' RETURN COUNT(rl)
- 查询路径 :MATCH path = (sn)-[rl*]->(en) WHERE sn.name = '会员A' AND en.name = '会员C' RETURN path

以上基础就完成了,后续就进行相关的业务扩展了

S5 : 创建更多类型的节点

java 复制代码
CREATE (n1:address {name:'武汉'}) RETURN n1;
CREATE (n2:address {name:'上海'}) RETURN n2;
CREATE (n3:address {name:'北京'}) RETURN n3;
CREATE (n4:address {name:'深圳'}) RETURN n4;
CREATE (n5:address {name:'杭州'}) RETURN n5;

S6 : 创建复杂的关系图

java 复制代码
// 地址关联
MATCH (a:User {name:'会员A'}), (b:address {name:'武汉'}) MERGE (a)-[:ADDRESS]->(b);
MATCH (a:User {name:'会员B'}), (b:address {name:'武汉'}) MERGE (a)-[:ADDRESS]->(b);
MATCH (a:User {name:'会员C'}), (b:address {name:'武汉'}) MERGE (a)-[:ADDRESS]->(b);
MATCH (a:User {name:'会员D'}), (b:address {name:'上海'}) MERGE (a)-[:ADDRESS]->(b);
MATCH (a:User {name:'会员E'}), (b:address {name:'北京'}) MERGE (a)-[:ADDRESS]->(b);
MATCH (a:User {name:'会员A'}), (b:address {name:'深圳'}) MERGE (a)-[:FRIENDS]->(b);
MATCH (a:User {name:'会员A'}), (b:address {name:'杭州'}) MERGE (a)-[:FRIENDS]->(b);

// 朋友关联 : 
MATCH (a:User {name:'会员B'}), (b:User {name:'会员E'}) MERGE (a)-[:FRIENDS]->(b);

S7 : 最终效果

java 复制代码
// 查询所有节点和节点间的关系 :
MATCH (n) RETURN n

// 查询所有有关系的节点
MATCH (a)--() RETURN a


// 查询所有对外有关系的节点,以及关系类型
MATCH (a)-[r]->() RETURN a.name, type(r)

S8 : 基于图的业务价值

java 复制代码
// 查询与武汉节点关联的节点
MATCH (a:address {name: '武汉'})-[r]-(b) RETURN b
MATCH (a:address {name: '武汉'})-[r]-(b) RETURN a,b
- PS : 这里 return 可以返回多个,展示的效果是不同的


// 查询朋友的朋友
MATCH (a:User {name:'会员A'})-[r1:FRIENDS]-()-[r2:FRIENDS]-(friend_of_a_friend) RETURN friend_of_a_friend.name AS fofName

S9 : 补充语法

java 复制代码
// 修改节点属性
MATCH (a:User {name:'会员A'}) SET a.city="武汉"

// 删除节点属性
MATCH (a:User {name:'会员A'}) REMOVE a.city

// 删除节点
MATCH (a:User {name:'会员G'}) DELETE a

// 删除关系
MATCH (a:User {name: '会员G'})-[r:FRIENDS]-(b:User {name: '会员D'}) DELETE r

// 删除节点及关系
MATCH (alice:User {name: '会员G'}) DETACH DELETE alice

三. 性能对比

性能比较主要集中在特定的场景,图数据库因为其特殊的形式,在深度遍历等方面的效率是远大于关系型数据库的,取自Neo4j 官方的博文 : @ neo4j.com/news/how-mu...

一百万数据 里面抽取 1000 个样本进行计算,查询朋友的朋友,按照不同的深度进行查询。

对于简单的好友的好友查询,Neo4j 比 MySQL 快 60%。对于朋友的朋友的朋友来说,Neo 的速度快了 180 倍。对于深度四查询,Neo4j 的速度快了 1,135 倍

四. 业务上怎么使用它更受益

在此期间比较浅显的读了一下 Neo4j 实战,大概可以从这几个方面来描述一下图数据库的优势 :

4.1 图数据库的使用场景

想看使用场景我们直接去官方看案例即可 :

我打交道比较多的就是社交和零散,主要看看这两块

社交关系

不知道大家有没有听过一个理论叫六度分隔理论,这个理论说的就是 : 世界上任意两个人之间的联系最多需要通过不超过六个中介,即通过六个人,就可以建立起联系

我们假设这个理论上成立的,我想知道我和一个陌生人之间可以是通过哪几个人进行关联的,首先从 MySQL 角度看 :

  • S1 : 构建一个人员信息表 , 为每个人员分配一个主键,标识现实中的实体
  • S2 : 构建一个关联信息表,构建这个人会和哪些人员进行关联
  • S3 : 走3个left join 或者逻辑中进行 for 循环+算法进行判断

很明显,这种方式占用资源很多,一不小心就会形成笛卡尔积,几何倍数

那么如果用图数据库,该怎么做?

JAVA 复制代码
// 展示会员A 朋友的朋友的朋友
MATCH (start:User {name: '会员A'})-[:FRIENDS*3]-(foaf:User) RETURN start, foaf

零售行业

最直接的包括最短路径算法,最优库存的实现 , 其次包括会员关系,精准有效都有些作用。

最短路径最直接的场景就是送外卖,哪些外卖分配更加合理。往更高级方向想就是物流。

总结

图数据库的使用是能解决很多复杂场景的问题的,但是这需要达到一定的量级。没达到量级使用关系型数据一样能满足。

但是整体来说,针对特定场景提高效率,优化业务,精准消费的效果还是很可观的。

参考文档

neo4j.com/

手把手教你快速入门知识图谱 - Neo4J教程 - 知乎 (zhihu.com)

相关推荐
测开小菜鸟23 分钟前
使用python向钉钉群聊发送消息
java·python·钉钉
Ai 编码助手1 小时前
MySQL中distinct与group by之间的性能进行比较
数据库·mysql
P.H. Infinity1 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天1 小时前
java的threadlocal为何内存泄漏
java
陈燚_重生之又为程序员2 小时前
基于梧桐数据库的实时数据分析解决方案
数据库·数据挖掘·数据分析
caridle2 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
白云如幻2 小时前
MySQL排序查询
数据库·mysql
萧鼎2 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
^velpro^2 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋32 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx