<div class="htmledit_views" id="content_views"> <p> 图数据库本身属于NoSql数据库中的一种,是基于数学中图论实现的一种数据库。不同于传统的关系型数据库将数据存在库表字段中,图数据库将数据和数据之间的关系存在节点和边中,在图数据库中这被称作“节点”和“关系”。没有了库表字段的概念,相当于是把数据存在了一张大宽表中。传统数据库的一些特性如CRUD、处理事务的能力在图数据库中也都支持。</p>
<p> <span style="color:#f33b45;"><strong>这里需要澄清一个概念:图数据库并不是前端展示用的数据库,它不是用来画图的。相反,它是用来存储数据用的,以图的节点和边的方式来存储数据。而前端展现需要用一些前端展示工具,例如D3、ECharts等来实现。</strong></span></p>
<p> 本文将以neo4j为例来介绍图数据库的使用。neo4j是由Java实现的开源NoSql图数据库,是图数据库中较为流行的一款。它提供了完整的数据库特性,包括ACID事务的支持、集群支持、备份与故障转移等(部分功能例如集群支持只有在neo4j企业版中才有,社区版不支持)。</p>
<p> 在笔者看来,图数据库最大的优势是体现在对数据关系的检索上。如果数据之间的关系很复杂,数据存在了多张表中,还有一些中间表的存在的话,传统数据库想要查询一些数据得通过各种联表操作才做得到,sql会写得很复杂,不利于维护,同时性能也不高。而图数据库仅仅通过简单的一句cypher语句便可实现查询功能(cypher语句是neo4j的执行语句,类似于关系型数据库中的SQL),同时执行速度也会快很多(书中所说是能够实现毫秒级响应,但通过笔者实测其实并没有这么夸张。neo4j是将数据存在内存中的,对硬件有一定要求。所以数据越来越多的情况下,同时也有事务的因素,查询速度也会变慢)。</p>
<p> 图数据库也支持查询一些复杂的关系。例如某节点周围一级的关系节点有哪些,二级的关系又有哪些。拿社交网络来举例,假如我现在要实现一个查询某人可能认识的人有哪些的功能。那么这个功能翻译成cypher就是:查询这个人A的周围一圈认识的人的集合B中,所有B周围一圈人中和A没有交集的人。这个用cypher语句是能写出来的,同时也不会太复杂。</p>
<p> neo4j的下载安装不做过多说明,官网上都可以下载,另外在微云数聚网站上也可以下载(笔者学习所使用的参考书籍正是张帜老师主编的《Neo4j权威指南》,他所创办的微云数聚公司也一直专注于研究图数据库技术及其应用)。</p>
<p> 启动neo4j成功后,可用浏览器打开网址:<a href="http://localhost:7474/" rel="nofollow" data-token="7011ff8465e4c568f7221b021fc113f6">http://localhost:7474/</a>,就可以看到neo4j的操作界面了,如下图所示。在最上面的输入框就可以输入cypher语句来操作数据了。</p>
<p><img alt="" class="has" height="167" src="https://img2018.cnblogs.com/blog/1112483/201908/1112483-20190808151732510-22613020.png" width="800"></p>
<p> 简单的一些语法例如:<1><strong>创建节点的语句</strong>:create(n:Person { name: 'Robert Hou', job: 'programmer'}),将会生成一个带有标签和属性的节点。</p>
<p><img alt="" class="has" height="249" src="https://img2018.cnblogs.com/blog/1112483/201908/1112483-20190808151754898-67041489.png" width="439"></p>
<p> <2><strong>创建关系的语句</strong>:match (a {name:'RobertHou'}), (b {name:'Lenovo'}) create(a)-[:HAS]->(b),将会创建一条关系连接两个节点。</p>
<p><img alt="" class="has" height="183" src="https://img2018.cnblogs.com/blog/1112483/201908/1112483-20190808151813876-1964899736.png" width="442"></p>
<p> 同时cypher也支持sql中的一些关键字查询,例如:order by、union、limit等;聚集函数也同样支持。</p>
<p> 比较有意思的语法是neo4j中支持搜索最短路径和全部路径的功能。只要输入起止节点,调用<strong>shortestPath</strong>和<strong>allShortestPaths</strong>方法就可以得到想要的结果了。下图是neo4j中一个电影的官方例子。节点有演员、导演和电影等。导演导演了某部电影,演员参演了某部电影。</p>
<p><img alt="" class="has" height="400" src="https://img2018.cnblogs.com/blog/1112483/201908/1112483-20190808151836930-170022842.png" width="800"></p>
<p><3><strong>查询两点之间的全部路径</strong>:match (Al:Person {name: 'Al Pacino'}),(Kevin:Person {name: 'Kevin Bacon'}), p = allShortestPaths((Al)-[*..15]-(Kevin))return p</p>
<p><img alt="" class="has" height="575" src="https://img2018.cnblogs.com/blog/1112483/201908/1112483-20190808151854607-1230359253.png" width="704"></p>
<p> 可以看到Al节点到Kevin节点的全部路径有两条。</p>
<p><4><strong>查询两点之间的最短路径</strong>:match (Al:Person {name: 'Al Pacino'}),(Kevin:Person {name: 'Kevin Bacon'}), p = shortestPath((Al)-[*..15]-(Kevin))return p</p>
<p><img alt="" class="has" height="410" src="https://img2018.cnblogs.com/blog/1112483/201908/1112483-20190808151919365-1736619557.png" width="463"></p>
<p> 可以看到Al节点到Kevin节点的最短路径变成了一条。</p>
<p> 其他的语法可以参考其他文章。本文不做过多赘述。同时,neo4j和spring的集成可以参考笔者的另一篇文章<a href="https://blog.csdn.net/weixin_30342639/article/details/86756977" rel="nofollow" data-token="8fc83aa1897151a19a2897703e2e4830">《Neo4j+D3展现的应用实例》</a>。需要注意的是Spring-Data-Neo4j库不支持jdk8以前的版本,相关的jar包版本和neo4j的版本号也要兼容,同时也要注意包可能存在冲突的问题。</p>
<p> neo4j也支持事务,在java中的写法大致类似于下面这样:</p>
<pre class="has" name="code"><code class="hljs java"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-keyword">try</span> {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> Tranction tx = graphDatabaseService.beginTx() {</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-comment">//和图数据库的交互语句</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> tx.success();</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" onclick="hljs.signin(event)"></div></pre>
<p><strong> <span style="color:#f33b45;">这里需要注意的是如果有循环操作图数据库的情况,一定不要在循环体里面开启关闭事务。应在循环体外开启和关闭事务,即一次开闭事务,在事务里面进行循环。</span></strong></p>
<p> 笔者之前就吃了这个亏,在循环体里开启关闭事务。如果循环了100次,则会有100次开闭事务,这个效率会有很大的问题。优化了代码之后,执行效率有显著提高。同样的思想也可用在java和数据库的交互上。像mybatis这样的持久层框架也都支持foreach功能。我们应该尽量用起来,减少java和数据库的交互次数。</p>
<p> 最后想说的是neo4j社区版还是应该用在平时的学习中,用在项目中可能会有不稳定的情况出现(不确定是否是使用了社区版导致的原因)。例如笔者将neo4j用在了实际的项目开发中,项目部署后经常出现图数据库自己关闭的情况。具体原因也需进一步研究。</p>
<p> 图数据库的前景很广,值得你我去深入研究!</p> 原文地址:https://blog.csdn.net/weixin_30342639/article/details/86477556 </div>
来源:oschina
链接:https://my.oschina.net/u/4337340/blog/3436408