图数据库本身属于NoSql数据库中的一种,是基于数学中图论实现的一种数据库。不同于传统的关系型数据库将数据存在库表字段中,图数据库将数据和数据之间的关系存在节点和边中,在图数据库中这被称作“节点”和“关系”。没有了库表字段的概念,相当于是把数据存在了一张大宽表中。传统数据库的一些特性如CRUD、处理事务的能力在图数据库中也都支持。

        这里需要澄清一个概念:图数据库并不是前端展示用的数据库,它不是用来画图的。相反,它是用来存储数据用的,以图的节点和边的方式来存储数据。而前端展现需要用一些前端展示工具,例如D3、ECharts等来实现。

        本文将以Neo4j为例来介绍图数据库的使用。Neo4j是由Java实现的开源NoSql图数据库,是图数据库中较为流行的一款。它提供了完整的数据库特性,包括ACID事务的支持、集群支持、备份与故障转移等(部分功能例如集群支持只有在neo4j企业版中才有,社区版不支持)。

        在我看来,图数据库最大的优势是体现在对数据关系的检索上。如果数据之间的关系很复杂,数据存在了多张表中,还有一些中间表的存在的话,传统数据库想要查询一些数据得通过各种联表操作才做得到,sql会写得很复杂,不利于维护,同时性能也不高。而图数据库仅仅通过简单的一句cypher语句便可实现查询功能(cypher语句是Neo4j的执行语句,类似于关系型数据库中的SQL),同时执行速度也会快很多(书中所说是能够实现毫秒级响应,但通过我实测其实并没有这么夸张。Neo4j是将数据存在内存中的,对硬件有一定要求。所以数据越来越多的情况下,同时也有事务的因素,查询速度也会变慢)。

        图数据库也支持查询一些复杂的关系。例如某节点周围一级的关系节点有哪些,二级的关系又有哪些。拿社交网络来举例,假如我现在要实现一个查询某人可能认识的人有哪些的功能。那么这个功能翻译成cypher就是:查询这个人A的周围一圈认识的人的集合B中,所有B周围一圈人中和A没有交集的人。这个用cypher语句是能写出来的,同时也不会太复杂。

        Neo4j的下载安装不做过多说明,官网上都可以下载,另外在微云数聚网站上也可以下载(我学习所使用的参考书籍正是张帜老师主编的《Neo4j权威指南》,他所创办的微云数聚公司也一直专注于研究图数据库技术及其应用)。

        启动Neo4j成功后,可用浏览器打开网址:http://localhost:7474/,就可以看到Neo4j的操作界面了,如下图所示。在最上面的输入框就可以输入cypher语句来操作数据了。

        简单的一些语法例如:

        <1>创建节点的语句:create(n:Person { name: 'Robert Hou', job: 'programmer'}),将会生成一个带有标签和属性的节点。

        <2>创建关系的语句:match (a {name:'RobertHou'}), (b {name:'Lenovo'}) create(a)-[:HAS]->(b),将会创建一条关系连接两个节点。

        同时cypher也支持sql中的一些关键字查询,例如:order by、union、limit等;聚集函数也同样支持。

        比较有意思的语法是Neo4j中支持搜索最短路径和全部路径的功能。只要输入起止节点,调用shortestPathallShortestPaths方法就可以得到想要的结果了。下图是Neo4j中一个电影的官方例子。节点有演员、导演和电影等。导演导演了某部电影,演员参演了某部电影。

        <3>查询两点之间的全部路径:match (Al:Person {name: 'Al Pacino'}),(Kevin:Person {name: 'Kevin Bacon'}), p = allShortestPaths((Al)-[*..15]-(Kevin))return p

        可以看到Al节点到Kevin节点的全部路径有两条。

        <4>查询两点之间的最短路径:match (Al:Person {name: 'Al Pacino'}),(Kevin:Person {name: 'Kevin Bacon'}), p = shortestPath((Al)-[*..15]-(Kevin))return p

        可以看到Al节点到Kevin节点的最短路径变成了一条。

        其他的语法可以参考其他文章。本文不做过多赘述。同时,Neo4j和Spring的集成可以参考我的另一篇文章《Neo4j+D3展现的应用实例》。需要注意的是Spring-Data-Neo4j库不支持jdk8以前的版本,相关的jar包版本和Neo4j的版本号也要兼容,同时也要注意包可能存在冲突的问题。

        Neo4j也支持事务,在java中的写法大致类似于下面这样:

try {
    Tranction tx = graphDatabaseService.beginTx() {
    //和图数据库的交互语句
    tx.success();
    }
}

        这里需要注意的是如果有循环操作图数据库的情况,一定不要在循环体里面开启关闭事务。应在循环体外开启和关闭事务,即一次开闭事务,在事务里面进行循环。

        我之前就吃了这个亏,在循环体里开启关闭事务。如果循环了100次,则会有100次开闭事务,这个效率会有很大的问题。优化了代码之后,执行效率有显著提高。同样的思想也可用在java和数据库的交互上。像mybatis这样的持久层框架也都支持foreach功能。我们应该尽量用起来,减少java和数据库的交互次数。

        最后想说的是Neo4j社区版还是应该用在平时的学习中,用在项目中可能会有不稳定的情况出现(不确定是否是使用了社区版导致的原因)。例如我将Neo4j用在了实际的项目开发中,项目部署后经常出现图数据库自己关闭的情况。具体原因也需进一步研究。

        图数据库的前景很广,值得你我去深入研究!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐