为什么需要图数据库?
设想一个场景:
在金融的反欺诈场景下,当一个用户小李
请求订单,我们可以设定一个规则:
- 获取该用户的身份证号、注册手机号、银行预留手机号、银行卡号、紧急联系人等信息
- 通过这些信息去关联包含这些信息的用户集合
小王、小张、小天
- 通过对关联出的
小王、小张、小天
判断黑名单用户、逾期用户、授信拒绝等信息综合判定一个分数 - 然后根据这个分数对
小李
判定是否授信通过;
为了更加有效果我们可以小王、小张、小天
作为源用户列表再获取这些用户的2度关联用户小小、小大
,获取一个综合评分,和一度关联的用户综合评分共同参考,来判定这个userA到底该不该授信通过,借钱给他,如下图:
基于上述场景,我们首先先考虑使用关系型数据库
: 一个用户表存储用户详情,上述过程我们需要
- 从接口入参获取小李的各种信息
- 通过小李的各种信息去表中查询出对应数据
- 再根据查出的一度用户去表中查询二度用户,那如果要查多度呢,如果想要获取用户的其他信息呢,就要join,多表join、多次join想想就刺激~
那么,基于图论
的图数据库
就诞生了,详细的我们下面再介绍,先基于将数据存储到图库中,用户做为节点、用户与用户之间的关系作为边、用户的其他属性作为节点的属性,类似于下图;
那么用图库该怎么查呢?
我们就以一种图库查询语言gremlin
来实现:
g.V().has(‘user_name‘,"小李").both("user_friend").both("user_friend").both("user_friend").bothV().has(‘sex‘,‘男‘)
一句话搞定,不用多次查询、图库帮你搞定~ 多度查询轻松拈来
ps : 具体图库底层数如何存储、查询逻辑、图库架构等 欢迎关注我~ 后续系列文章会出~
总结一下,图库在特定场景
下的优点:
-
高性能
:随着数据量的增多和关联深度的增加,传统关系型数据库受制于检索时需要多个表之间连接操作,数据写入时也需考虑外键约束,从而导致较大的额外开销,产生严重的性能问题。而图模型固有的数据索引结构,使得它的数据查询与分析速度更快。 -
灵活
:图数据库有非常灵活的数据模型,使用者可以根据业务变化随时调整数据模型,比如任意添加或删除顶点、边,扩充或者缩小图模型这些都可以轻松实现,这种频繁的 Schema 更改在关系型数据库上不能到很好的支持。 -
敏捷
:图数据库的图模型非常直观,支持测试驱动开发模式,每次构建时可进行功能测试和性能测试,符合当今最流行的敏捷开发需求,对于提高生产和交付效率也有一定帮助。
图数据库
图形数据库是NoSQL
数据库的一种类型,起源于欧拉理论和图理论
,也可称为面向/基于图的数据库
,对应的英文是Graph Database
。
它应用图形理论
存储实体之间的关系信息
;图数据库的基本含义是以“图”
这种数据结构做为逻辑结构
存储和查询数据。
我们知道一个图包含节点和边,如下图:
在图数据库中图
将实体表现为节点
,实体与其他实体连接的方式表现为联系(边)
。我们可以用这个通用的、富有表现力的结构来建模各种场景,从宇宙火箭的建造到道路系统,从食物的供应链及原产地追踪到人们的病历,甚至更多其他的场景。
例如,实体
:类似于用户、用户的亲属等作为一个节点存在于图中,边
:用户和用户亲属之间关联的关系,小李--->小李的父亲,这两个节点之间的边可以设定为“用户父母”的边;
主流图数据库
目前主流的图数据库有:Neo4j,Janusgraph,Dgraph,Giraph,TigerGraph等。
ps : 这里我们只看 database model专用支持graph类型的图库
受欢迎程度如下,时间是:2020-5月
简单介绍一下Neo4j 和 Janusgraph区别:
Neo4j:
- Neo4J使用原生的图存储,以高度*且规范的方式管理和存储数据。对比非原生图解决方案中,随着信息量的增加,使用面向对象的数据库存储数据库使数据操作变得越来越慢。
- Neo4J可以以每秒一百万条的惊人速度提供结果,因为数据中的链接部分或实体在物理上是已经相互连接的。
- Neo4J的另一个特点是ACID事务,它确保实时显示数据的合法性和准确性,这是企业级应用的重要特性。
- 单击不收费,集群收费,所以对于不想要花大价钱买的话,这个不推荐;如果不差钱,强烈推荐使用,社群活跃,服务稳定,功能强大
Janusgraph:
- 开源的分布式图数据库,采用第三方存储作为底层存储,如:HBase、Cassandra等
- 使用第三方框架支持全文匹配、范围匹配等,如Es等
- 集群节点可以线性扩展,以支持更大的图和更多的并发访问用户。
- 数据分布式存储,并且每一份数据都有多个副本,因此,有更好的计算性能和容错性。
- 原生集成Apache TinkerPop图技术栈,包括Gremlin graph query language、Gremlin graph server、Gremin applications。
- 免费开源,我们现在正在使用的就是这个
下面就以JanusGraph
为例来初探图数据库的设计
JanusGraph
可以看下官网上的解释:
JanusGraph is a scalable graph database optimized for storing and querying graphs containing hundreds of billions of vertices and edges distributed across a multi-machine cluster. JanusGraph is a transactional database that can support thousands of concurrent users executing complex graph traversals in real time.
JanusGraph是一个可扩展的图形数据库
,专门用于存储和查询分析分布在多机集群中的数千亿个顶点和关系边的图形。
JanusGraph是一个事务数据库
,可以支持数千个并发用户实时执行复杂的图遍历。
历史
- JanusGraph是2016年12月27日从Titan fork出来的一个分支,之后TiTan的开发团队在2017年陆续发了0.1.0rc1、0.1.0rc2、0.1.1、0.2.0等四个版本,最新的版本是2017年10月12日。
- titan是从2012年开始开发,到2016年停止维护的一个分布式图数据库。最初在2012年启动titan项目的公司是Aurelius,2015年此公司被 DataStax(DataStax是开发apache Cassandra 的公司)收购,DataStax公司吸收了TiTan的图存储能力,形成了自己的商业产品DataStax Enterprise Graph。
- TiTan开发者们希望把TitTan放到Apache Software Foundation下,不过,DataStax不愿意这样做,而且自从2015年9月DataStax收购了Titan的母公司后,TiTan一直处于停滞状态,鉴于此,2016年6月,TiTan的开发者们fork了一个TiTan的分支,重命名为JanusGraph,并将其置于Linux Software Foundation下。
- 2017年4月6日发布了第一个版本0.1.0-rc1,目前最新版本是
2020年05月27日
发布的0.6版
JanusGraph
项目启动的初衷是“通过为其增加新功能、改善性能和扩展性、增加后端存储系统来增强分布式图系统的功能,从而振兴分布式图系统的开发
”
JanusGraph
从Apahce TinkerPop
中吸收了对属性图模型(Property Graph Model)
的支持和对属性图模型进行遍历的Gremlin遍历语言。
基本概念
同大多数图数据库一样,JanusGraph采用 属性图
进行建模。基于属性图
的模型,JanusGraph有如下基本概念:
-
Vertex Label
:节点的类型,用于表示现实世界中的实体类型,比如"人”,“车”。在JanusGraph中,每一个节点有且只有一个Vertex Label。当不显式指定Vertex Label时,采用默认的Vertex Label。 -
Vertex
:节点/顶点,用于表示现实世界中的实体对象。 -
Edge Label
:边的类型,用于表示现实世界中的关系类型,比如“通话关系”,“转账关系”,“微博关注关系”等; -
Edge
: 边,用于表示一个个具体的联系。JanusGraph的边都是单向边。如果需要双向边,则通过两条相反方向的单向边组成。JanusGraph不存在无向边。 -
Property Key
:属性的类型,比如“姓名”,“年龄”,“时间”等。Property Key有Cardinality的概念。Cardinality有SINGLE、LIST和SET三种选项。这三种选项分别用于表示一个Property中,对于同一个Property Key是只允许有一个值、允许多个可重复的值,还是多个不可重复的值。 -
Property
:属性,用于表示一个个具体的附加信息,采用Key-Value结构。Key就是Property Key,Value就是具体的值。
类似于下面这种图,包含节点和边,节点包含多个属性:
关键点
- 弹性和线性可扩展性,适用于不断增长的数据和用户群。
- 用于性能和容错的数据分发和复制。
- 多数据中心高可用性和热备份。
- 支持ACID和 最终的一致性。
- 支持各种存储后端: Apache Cassandra\Apache HBase \ Google Cloud Bigtable \ Oracle BerkeleyDB
- 通过与大数据平台集成,支持全局图形数据分析,报告和ETL: Apache Spark\Apache Giraph\ApacheHadoop
- 支持以下方式进行geo、数据范围搜索和全文搜索: ElasticSearch \ Apache Solr \Apache Lucene
- 与Apache TinkerPop图形堆栈本机集成: Gremlin图查询语言 \ Gremlin图服务器 \ Gremlin应用程序
- Apache 2许可下的开源
- 工具可视化存储在JanusGraph中的图形:Cytoscape \Apache TinkerPop 的 Gephi插件\ Graphexp \ Cambridge Intelligence 的 KeyLines\Linkurious
整体架构
JanusGraph是一个图形数据库引擎,本身专注于紧凑图形序列化,丰富的图形数据建模和高效的查询。利用Hadoop进行图形分析和批处理图处理。
JanusGraph为数据持久性、数据索引和客户端访问实现了强大的模块化接口。其模块化架构使其能够与各种存储、索引和客户端技术进行互操作;模块化架构还简化了支持新的一个 模块的流程。
架构图如下:
ps:避免篇幅过大,架构相关的信息会在后续的博文详细说明
如何使用
作为一个数据库系统
,它是要用来为应用程序存储数据
用的,那么应用程序应该如何使用JanusGraph来为自己存储数据呢?
一般来说,应用程序可以通过两种不同的方式来使用JanusGraph:
- 第一种方式:可以把JanusGraph嵌入到应用程序中去,JanusGraph和应用程序处在
同一个JVM中
。应用程序中的客户代码(相对JanusGraph来说是客户)直接调用Gremlin
去查询JanusGraph中存储的图,这种情况下外部存储系统可以是本地的,也可以处在远程 -
第二种方式:应用程序和Janus Graph处在两个不同JVM中,应用通过给JanusGraph提交Gremlin查询给GremlinServer,来使用JanusGraph,因为JanusGraph原生是支持Gremlin Server的。
Gremlin Server是Apache Tinkerpop中的一个组件
JanusGraph集群
包含一个、或者多个JanusGraph实例。每次启动一个JanusGraph实例
的时候,都必须指定JanusGraph的配置。
在配置中,可以指定JanusGraph要用的组件,可以控制JanusGraph运行的各个方面,还可以指定一些JanusGraph集群的调优选项:
- 最小的JanusGraph配置只需要指定一下JanusGraph的后端存储系统,也就是它的持久化引擎。
- 如果要JanusGraph支持高级的图查询,就需要为JanusGraph指定一个索引后端。
- 若果要提升JanusGraph的查询性能,就必须为JanusGraph指定缓存,指定性能调优的选项。
以上提到的后端存储系统、索引后端、缓存、调优选项等都可以在JanusGraph的配置文件中进行指定。默认情况下它的配置文件存放在JanusGraph_home/conf
目录下。
storage.backend=cassandra
storage.hostname=localhost
index.search.backend=elasticsearch
index.search.hostname=
index.search.elasticsearch.client-only=true
也可以在写测试用例时代码控制:
/**
* 创建一个JanusGraph实例
* @return JanusGraph的一个实例
*/
private static JanusGraph create() {
try {
return JanusGraphFactory.build()
.set("storage.backend", "hbase")
.set("storage.hostname", "")
.set("storage.port", "")
.set("storage.hbase.table", "")
.set("cache.db-cache", "true")
.set("cache.db-cache-clean-wait", "20")
.set("cache.db-cache-time", "180000")
.set("cache.db-cache-size", "0.5")
.set("index.relationalNetwork.backend", "elasticsearch")
.set("index.relationalNetwork.hostname", "")
.set("index.relationalNetwork.port", 9000)
.open();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
通过上述代码,就可以生成一个janusgraph图实例,通过操作该图实例来对图数据库进行操作
总结
本文介绍了,为什么需要图数据库,图数据库的基础理论,市场上存在的流行的图数据库并依照janusgraph图数据库来展开讲解一下图数据库相关知识等。
更多技术文章,请关注公众号“匠心Java
”!