图数据库Neo4j详解

目录

图形数据库的使用场景

Neo4j简介

设计理念

Neo4j特点

Neo4j相关特性

数据模型

索引

事务

原子性

一致性

隔离性

永久性

遍历和查询

图算法

嵌入式可扩展

Neo4j与传统数据库的区别

RDBMS

Neo4j

Neo4j集群模式运行原理

Neo4j优缺点

优点:

缺点:

应用场景

Neo4j不适用于:

官方例子

Neo4j核心之Cypher语法

Cypher介绍

操作符

参数

节点对象参数

多节点id参数

字符串参数

索引键值参数

索引查询参数

l SKIP 与LIMIT * 的数字参数

正则表达式参数

标识符

注解

Start

Match

相关节点

接出关系(Outgong Relationship)

定向关系和标识符

通过关系类型匹配

通过关系类型匹配和使用标识符

带有特殊字符的关系类型

多重关系

可变长度的关系

在可变长度关系的关系标识符

零长度路径

可选关系

可选类型和命名关系

可选元素的属性

复杂匹配

最短路径

所有最短路径

命名路径

在绑定关系上的匹配

Where

Boolean 操作类型

节点属性上的过滤

正则表达式

转义正则表达式

不分大小些正则表达式

关系类型上的过滤

属性存在性

如果缺失属性默认为true

如果缺失属性默认为false

空置Null过滤

关系过滤

Neo4j 综合

返回节点

返回关系

返回属性

带特殊字符的标识符

列的别名

可选属性

特别的结果

Neo4j 聚合函数

聚合(Aggregation)

计数

计算节点数

分组计算关系类型

计算实体数

计算非空可以值数

求和(sum)

平均值(avg)

最大值(max)

最小值(min)

聚类(COLLECT)

相异(DISTINCT)

Neo4j 高级篇

排序(Order by)

通过节点属性排序节点

通过多节点属性排序节点

倒序排列节点

空值排序

Skip

跳过前三个

返回中间两个

Limit

返回第一部分

函数(Functions)

判断

All

Any

None

Single

Scalar函数

Length

Type

Id

Coalesce

Iterable函数

Nodes

Relationships

Extract

Neo4j常见问题

Q:neo4j数据库支持最大多少个节点?最大支持多少条边?

Q:Neo4j数据库支持的最复杂的连接是什么?(比如每个节点都与其他任何一个节点相连)

Q:在数据库中,读/写性能跟节点/边的数量有关吗?

Q:Neo4j数据库支持的读/写并发请求最大数量是多少?

Q:在数据库集群环境中数据一致性如何保证的呢?

Q:当在一个数据库中发生更新操作时如何快速更新其他所有服务器呢?

Q:在集群环境中,在不同服务器会出现按比例延迟新增吗?

Q:支持在线扩展吗?换句话说,如果我们想新加入一台服务器到集群中需要关闭所有服务器吗?

Q:新加入一台服务器到全部同步需要多长时间?

Q:重启需要多久呢?

Q:是否有备份恢复机制?

Q:是否支持跨区集群?跨区集群是否比同区集群性能更低呢?

Q:是否有任何指定测控策略用于环境建立之类的需求?

Q:写数据库是线程安全的吗?

Q:从HA读数据最好的策略是什么?

Q:对于获取(如果不存在则创建)这中需求最好的策略是什么?

Q:如何锁定服务?

Q:数据存储占用空间如何?

Q:如何进行数据库查询?

Q:Neo4j有使用日志(在数据丢失时可以修复丢失的数据)功能吗?

Q:如何提升Neo4j的性能?

Q:独立服务器怎么样?

Q:在HA环境中如何使用负载均衡?

Q:Neo4j支持那些监控器?

Q:如何导入数据到Neo4j中?


转载专用:
        读到了好文章,用于分享收藏,侵权删。
        转发自大佬:https://blog.csdn.net/Dream_bin/article/details/104470275

图形数据库的使用场景

一:借助图形数据库的数据结构保存数据。以减少保存图形数据的烦恼,实现图形计算的主要有两种方式(图形数据库除外),主要有两种:

  •     第一种是迭代的遍历计算,该实现方式效率低,且计算量大。
  •     第二种就是使用专业的第三方工具jar。例如Jgraph/Gauva graph (均是内存级别,曾经做过简单的测试,Jgraph 占用内存稍低,但是比Gauva graph慢一些,Gauva graph比较快,但是内存占用多)。

二:借助图形数据库的算法,到达计算的目的。

Neo4j简介

Neo4j是一个高性能的NOSQL图形数据库,它将结构化数据存储在网络上而不是表中

它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。

Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下,而不是严格、静态的表中。但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。Neo4j因其嵌入式、高性能、轻量级等优势,越来越受到关注。

现实中很多数据都是用图来表达的,比如社交网络中人与人的关系、地图数据、或是基因信息等等。RDBMS并不适合表达这类数据,而且由于海量数据的存在,让其显得捉襟见肘。NoSQL数据库的兴起,很好地解决了海量数据的存放问题,图数据库也是NoSQL的一个分支,相比于NoSQL中的其他分支,它很适合用来原生表达图结构的数据。

通常来说,一个图数据库存储的结构就如同数据结构中的图,由顶点和边组成

Neo4j是图数据库中一个主要代表,其开源且用Java实现(需安装Neo4j不同版本对应的不同版本的JDK)。经过几年的发展,已经可以用于生产环境。其有两种运行方式,一种是服务的方式,对外提供REST接口;另外一种是嵌入式模式,数据以文件的形式存放在本地,可以直接对本地文件进行操作。

Neo4j分三个版本:社区版(community)、高级版(advanced)和企业版(enterprise)。

社区版是基础,本文主要对其作出介绍,它使用的是GPLv3协议,这意味着修改和使用其代码都需要开源,但是这是建立在软件分发的基础上,如果使用Neo4j作为服务提供,而不分发软件,则不需要开源。这实际上是GPL协议本身的缺陷。

高级版和企业版建立在社区版的基础上,但多出一些高级特性。高级版包括一些高级监控特性,而企业版则包括在线备份、高可用集群以及高级监控特性。要注意它们使用了AGPLv3协议,也就是说,除非获得商业授权,否则无论以何种方式修改或者使用Neo4j,都需要开源。

设计理念

Neo4j的设计动机是为了更好地同时也更高效地描述实体之间的关系。

在现实生活中,每一个实体都于周围的其他实体有着千丝万缕的关系,这些关系里面所存储的信息甚至要大于身体本身的属性。

传统的关系型数据库更注重刻画实体内部的属性,实体与实体之间的关系通常都是利用外键来实现。所以在求解关系的时候通常需要join操作,而join操作通常又是耗时的。互联网尤其是移动互联网的爆发式增长本来就使得传统关系型数据库不堪重负,再加上诸如社交网络等应用对于关系的高需求,可以说关系型数据库已经是毫无优势。

图数据库作为重点描述数据之间关系的数据库应运而生,成为了NoSQL中非常重要的一部分。而Neo4j正是图数据库中最为优秀的之一。

Neo4j特点

  • 所用语言: Java
  • 特点:基于关系的图形数据库
  • 使用许可: GPL,其中一些特性使用 AGPL/商业许可
  • 协议:HTTP/REST(或嵌入在 Java中)
  • 可独立使用或嵌入到 Java应用程序
  • 图形的节点和边都可以带有元数据
  • 很好的自带web管理功能
  • 使用多种算法支持路径搜索
  • 使用键值和关系进行索引为读操作进行优化
  • 支持事务(用 Java api)
  • 使用 Gremlin图形遍历
  • 语言支持 Groovy脚本
  • 支持在线备份,高级监控及高可靠

Neo4j相关特性

数据模型

Neo4j被称为Property Graph,除了顶点(Node)边(Relationship,其包含一个类型),还有一种重要的部分,属性

无论是顶点还是边,都可以有任意多的属性。属性的存放类似于一个Hashmap,Key为一个字符串,而Value必须是Java基本类型或者是基本类型数组,比如说String、int或者int[]都是合法的。

索引

Neo4j支持索引,其内部实际上通过Lucene实现。

事务

Neo4j完整支持事务,即满足ACID性质。

ACID是以下四个事务特性的缩写:

原子性

一个事务的所有工作要么都(成功)执行,要么都不执行。不会发生只执行一部分的情况。

比如说,一个事务开始更新100行记录,但是在更新了20行之后(因为某种原因)失败了,那么此时数据库会回滚(撤销)对那20条记录的修改。

一致性

事务将数据库从一个一致性状态带入另一个一致性状态。

比如说,在一个银行事务(在描述关系数据库事务的特性时,基本上都是用银行事务来作为描述对象的)中,需要从存储账户扣除款项,然后在支付账户中增加款项。

如果在这个中转的过程发生了失败,那么绝对不能让数据库只执行其中一个账户的操作,因为这样会导致数据处于不一致的状态(这样的话,银行的账目上,借贷就不平衡了)。

隔离性

这个特性是说,直到事务结束时(commit/rollback),其他事务(或者会话)对此事务所操作的数据都不可见(但并不是说其他会话的读取会被阻塞)。

比如说,一个用户正在修改hr.employees表,但是没有提交,那么其他用户在这个修改没有提交之前是看不到这个修改的。

永久性

被提交的更改会永久地保存到数据库中(并不是说以后就不可以修改)。

事务提交之后,数据库必须通过“恢复机制”来确保事务更改的数据不会丢失。

遍历和查询

遍历是图数据库中的主要查询方式,所以遍历是图数据中相当关键的一个概念。可以用两种方式来进行遍历查询:

  • 第一种是直接编写Java代码,使用Neo4j提供的Traversal框架;
  • 第二种方式是使用Neo4j提供的描述型查询语言,Cypher。

图算法

Neo4j实现的三种图算法:

  • 最短路径(最少数目的关系);
  • Dijkstra算法(解决有向图中任意两个顶点之间的最短路径问题);
  • A*算法(是解决静态路网中求解最短路最有效的方法)。

嵌入式可扩展

Neo4j是一个嵌入式的、基于磁盘的、支持完整事务的Java持久化引擎,它在图像中而不是表中存储数据。

Neo4j提供了大规模可扩展性,在一台机器上可以处理数十亿节点、关系、属性的图像,可以扩展到多台机器并行运行。相对于关系数据库来说,图形数据库善于处理大量复杂、互连接、低结构化的数据,这些数据变化迅速,需要频繁的查询,在关系数据库中,这些查询会导致大量的表连接,因此会产生性能上的问题。

Neo4j重点解决了拥有大量连接的传统RDBMS在查询时出现的性能衰退问题。通过围绕图形进行数据建模,Neo4j会以相同的速度遍历节点与边,其遍历速度与构成图形的数据量没有任何关系。

Neo4j与传统数据库的区别

Ne04jRDBMS
允许对数据的简单且多样的管理高度结构化的数据
数据添加和定义灵活,不受数据类型和数量的限制,无需提前定义表格Schema需预定义,修改和添加数据结构和类型复杂,对数据有严格的限制
常数时间的关系查询操作关系查询操作耗时
提出全新的查询语言cypher,查询语句更加简单查询语句更为复杂,尤其涉及到join或union操作时

最后再以下面两张图来展示一下两者在查询关系时的区别:

RDBMS

Neo4j

Neo4j集群模式运行原理

一个Neo4j HA集群的协作运行,协调行为是通过zookeeper完成的。2.0以后是基于Paxos协议开发了自己的集群协调机制。

  1. 当一个Neo4j HA实体开启时将去连接协调器服务(zookeeper)注册其本身并询问“谁是主机(master)?”。如果某个机器是主机,新的实体将以从机(slaver)开启并连接到主机(master)。如果机器开启时为第一个注册或者通过主机选择算法应该成为主机,将会作为主机开启。
  2. ​当从一个从机上执行一个写入的事务时,每个写入操作将与主机同步(主机与从机将被锁定)。当事务提交时首先存在于主机上。当主机事务提交成功,从机上的事务也会被提交。为确保一致性,在执行写入操作前从机与主机同步必须是最新的。这是建立主机与从机之间的通讯协议,所以如果需要,更新将会自动发生。
  3. ​可以通过在包含ha.slave_coordinator_update_mode=none配置参数的配置文件中将数据库实体设置成只做为从机。此实体虽然在系统故障恢复选择时将不可能再成为主机,然而此从机的行为与其他所有从机都一样,含有永久写入到主机的能力。
  4. 当从主机上执行写入操作,它将与在普通的嵌入模式中执行一样。此时主机将不会推送更新消息到从机。相反,从机可以配置一个拉取消息的时间间隔。没有选举,更新操作仅仅只会发生在从机上,任何时候都将同步一个写入到主机。
  5. ​ 将所有写入操作通过从机执行的好处是数据将被复制到两台机器上。这是建议的,避免当新选主机时可能造成回滚失败。
  6. ​当某台neo4j数据库服务不可用时,协调器(coordinator)将探测到并从集群中删除掉。当主机当机时,新的主机将自动被选择出来。一般地,一个新的主机被选定并在几秒钟内启动,在这段时间将不会执行任何写入操作(写入将抛出异常)。当某台机器从故障中恢复了,将会被自动重新连接到集群中。当没有得到其他任何机器的备份的旧的主机改变时, 是唯一不确定的。如果新的主机被选择并在旧的主机恢复前执行改变,将会有两个不同版本的数据。旧主机将移除分支数据库并从新主机下载一个全版本的数据。

所有这些可以归纳如下:

  1. 从机可以处理写入事务。
  2. 更新相对从机最终将会一致。
  3. Neo4j HA 是一个容错并能继续执行从x台机器到单独一台机器(基于zookeeper设置)。
  4. 在写入操作上从机将自动同步到主机。
  5. 当主机故障时新的主机将自动选出。
  6. 当任何导致运行中断的错误(网络、维护)解决时当台机器将会自动被重新连接到集群中。
  7. 事务的原子性、持久性和一致性并最终会广播到其他从机上。
  8. 主机故障了,所有正在运行写入事务将会被回滚,主机选举时任何写入操作都不能执行。
  9. 读取操作高度可用。

Neo4j优缺点

优点:

  • 数据的插入,查询操作很直观,不用再像之前要考虑各个表之间的关系。
  • 提供的图搜索和图遍历方法很方便,速度也是比较快的。
  • 更快的数据库操作。当然,有一个前提条件,那就是数据量较大,在MySql中存储的话需要许多表,并且表之间联系较多(即有不少的操作需要join表)。

缺点:

  • 当数据过大时插入速度可能会越来越慢。
  • 超大节点。当有一个节点的边非常多时(常见于大V),有关这个节点的操作的速度将大大下降。这个问题很早就有了,官方也说过会处理,然而现在仍然不能让人满意。
  • 提高数据库速度的常用方法就是多分配内存,然而看了官方操作手册,貌似无法直接设置数据库内存占用量,而是需要计算后为其”预留“内存。
  • 注:鉴于其明显的优缺点,Neo4j适合存储“修改较少,查询较多,没有超大节点”的图数据。

应用场景

适用于图形一类数据。这是 Neo4j与其他Nosql数据库的最显著区别。例如:社会关系,公共交通网络,地图及网络拓谱。

Neo4j不适用于:

  • 记录大量基于事件的数据(例如日志条目或传感器数据);
  • 对大规模分布式数据进行处理,类似于Hadoop;
  • 二进制数据存储;
  • 适合于保存在关系型数据库中的结构化数据。
  • 官方例子

  • 官方有两个例子,其中一个是Movie的图关系建模,编辑器文本框输入:play movies可以查看这个demo,步骤如下:

    根据步骤到create 这里,copy一下cypher语句,因为篇幅较长这里就截取一部分示例:

    CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'})
    CREATE (Keanu:Person {name:'Keanu Reeves', born:1964})
    CREATE (Carrie:Person {name:'Carrie-Anne Moss', born:1967})
    CREATE (Laurence:Person {name:'Laurence Fishburne', born:1961})
    CREATE (Hugo:Person {name:'Hugo Weaving', born:1960})
    CREATE (LillyW:Person {name:'Lilly Wachowski', born:1967})
    CREATE (LanaW:Person {name:'Lana Wachowski', born:1965})
    CREATE (JoelS:Person {name:'Joel Silver', born:1952})
    CREATE
      (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix),
      (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix),
      (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix),
      (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix),
      (LillyW)-[:DIRECTED]->(TheMatrix),
      (LanaW)-[:DIRECTED]->(TheMatrix),
      (JoelS)-[:PRODUCED]->(TheMatrix)
    CREATE (Emil:Person {name:"Emil Eifrem", born:1978})
    CREATE (Emil)-[:ACTED_IN {roles:["Emil"]}]->(TheMatrix)

    接下来进行查询:

    WITH TomH as a
    MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) RETURN a,m,d LIMIT 10 ;

    就可以看到节点间的关系图形化界面:

点击某个节点还可下钻。

Neo4j核心之Cypher语法

Cypher介绍

“Cypher”是一个描述性的图形查询语言,允许不必编写图形结构的遍历代码对图形存储有表现力和效率的查询。

Cypher还在继续发展和成熟,这也就意味着有可能会出现语法的变化。同时也意味着作为组件没有经历严格的性能测试。

Cypher设计的目的是一个人类查询语言,适合于开发者和在数据库上做点对点模式(ad-hoc)查询的专业操作人员。它的构念是基于英语单词和灵巧的图解。

Cyper通过一系列不同的方法和建立于确定的实践为表达查询而激发的。许多关键字如like和order by是受SQL的启发。模式匹配的表达式来自于SPARQL。正则表达式匹配实现实用Scala Programming Language语言。

Cypher是一个申明式的语言。对比命令式语言如Java和脚本语言如Gremlin和JRuby,它的焦点在于从图中如何找回,而不是怎么去做。这使得在不对用户公布的实现细节里关心的是怎么优化查询。

这个查询语言包含以下几个明显的部分:

START:在图中的开始点,通过元素的ID或所以查找获得。

MATCH:图形的匹配模式,束缚于开始点。

WHERE:过滤条件。

RETURN:返回所需要的。

更多cypher语法请参考:Cypher Cheat Sheet - Neo4j Documentation Cheat Sheet

操作符

  1. Cypher中的操作符有三个不同种类:数学,相等和关系
  2. 数学操作符有+,-,*,/和%。当然只有+对字符有作用
  3. 等于操作符有=,<>,<,>,<=,>=
  4. 因为Neo4j是一个模式少的图形数据库,Cypher有两个特殊的操作符?和!

有些是用在属性上,有些事用于处理缺少值。对于一个不存在的属性做比较会导致错误。为替代与其他什么做比较时总是检查属性是否存在,在缺失属性时问号将使得比较总是返回true,感叹号使得比较总是返回false。

WHEREn.prop? = “foo”

这个断言在属性缺失情况下将评估为true。

WHEREn.prop! = “foo”

这个断言在属性缺失情况下将评估为false。

警告:在同一个比较中混合使用两个符号将导致不可预料的结果。

参数

Cypher支持带参数的查询。这允许开发者不需要必须构建一个string的查询,并且使得Cypher的查询计划的缓存更容易。

参数可以在where子句,start子句的索引key或索引值,索引查询中作为节点/关系id的引用

以下是几个在java中使用参数的示例:

节点id参数

Map<String, Object> params = new HashMap<String, Object>();

params.put( “id”, 0 );

ExecutionResult result = engine.execute( “start n=node({id}) return n.name”, params );

节点对象参数

Map<String, Object> params = new HashMap<String, Object>();

params.put( “node”, andreasNode );

ExecutionResult result = engine.execute( “start n=node({node}) return n.name”, params );

多节点id参数

Map<String, Object> params = new HashMap<String, Object>();

params.put( “id”, Arrays.asList( 0, 1, 2 ) );

ExecutionResult result = engine.execute( “start n=node({id}) return n.name”, params );

字符串参数

Map<String, Object> params = new HashMap<String, Object>();

params.put( “name”, “Johan” );

ExecutionResult result = engine.execute( “start n=node(0,1,2) where n.name = {name} return n”, params );

索引键值参数

Map<String, Object> params = new HashMap<String, Object>();

params.put( “key”, “name” );

params.put( “value”, “Michaela” );

ExecutionResult result = engine.execute( “start n=node:people({key} = {value}) return n”, params );

索引查询参数

Map<String, Object> params = new HashMap<String, Object>();

params.put( “query”, “name:Andreas” );

ExecutionResult result = engine.execute( “start n=node:people({query}) return n”, params );

l SKIP 与LIMIT * 的数字参数

Map<String, Object> params = new HashMap<String, Object>();

params.put( “s”, 1 );

params.put( “l”, 1 );

ExecutionResult result = engine.execute( “start n=node(0,1,2) return n.name skip {s} limit {l}”, params );

正则表达式参数

Map<String, Object> params = new HashMap<String, Object>();

params.put( “regex”, “.h.” );

ExecutionResult result = engine.execute( “start n=node(0,1,2) where n.name =~ {regex} return n.name”, params );

标识符

当你参考部分的模式时,需要通过命名完成。定义的不同的命名部分就被称为标识符。

如下例中:

START n=node(1) MATCH n–>b RETURN b

标识符为n和b。

标识符可以是大写或小些,可以包含下划线。当需要其他字符时可以使用符号。对于属性名的规则也是一样。

注解

可以在查询语句中使用双斜杠来添加注解。如:

START n=node(1) RETURN b //这是行结束注释

START n=node(1) RETURN b

START n=node(1) WHERE n.property = “//这部是一个注释” RETURN b

Start

每一个查询都是描述一个图案(模式),在这个图案(模式)中可以有多个限制点。一个限制点是为模式匹配的从开始点出发的一条关系或一个节点。可以通过id或索引查询绑定点。

通过id绑定点

通过node(*)函数绑定一个节点作为开始点

查询:

START n=node(1)

RETURN n

返回引用的节点。

通过id绑定关系

可以通过relationship()函数绑定一个关系作为开始点。也可以通过缩写rel()。

查询:

START r=relationship(0)

RETURN r

Id为0的关系将被返回

通过id绑定多个节点

选择多个节点可以通过逗号分开。

查询:

START n=node(1, 2, 3)

RETURN n

所有节点

得到所有节点可以通过星号(*),同样对于关系也适用。

查询:

START n=node(*)

RETURN n

这个查询将返回图中所有节点。

通过索引查询获取节点

如果开始节点可以通过索引查询得到,可以如此来写:

node:index-name(key=”value”)。在此列子中存在一个节点索引叫nodes。

查询:

START n=node:nodes(name = “A”)

RETURN n

索引中命名为A的节点将被返回。

通过索引查询获取关系

如果开始点可以通过索引查询得到,可以如此做:

Relationship:index-name(key=”value”)。

查询:

START r=relationship:rels(property =“some_value”)

RETURN r

索引中属性名为”some_value”的关系将被返回。

多个开始点

有时需要绑定多个开始点。只需要列出并以逗号分隔开。

查询:

START a=node(1), b=node(2)

RETURN a,b

A和B两个节点都将被返回。

Match

在一个查询的匹配(match)部分申明图形(模式)。模式的申明导致一个或多个以逗号隔开的路径(path)

节点标识符可以使用或者不是用圆括号。使用圆括号与不使用圆括号完全对等,如:

MATCH(a)–>(b) 与 MATCH a–>b 匹配模式完全相同。

模式的所有部分都直接或者间接地绑定到开始点上。可选关系是一个可选描述模式的方法,但在真正图中可能没有匹配(节点可能没有或者没有此类关系时),将被估值为null。与SQL中的外联结类似,如果Cypher发现一个或者多个匹配,将会全部返回。如果没有匹配,Cypher将返回null。

如以下例子,b和p都是可选的病都可能包含null:

START a=node(1) MATCH p = a-[?]->b

START a=node(1) MATCH p = a-[*?]->b

START a=node(1) MATCH p = a-[?]->x–>b

START a=node(1), x=node(100) MATCH p = shortestPath( a-[*?]->x )

相关节点

符号—意味着相关性,不需要关心方向和类型。

查询:

START n=node(3)

MATCH (n)–(x)

RETURN x

所有与A相关节点都被返回。

接出关系(Outgong Relationship)

当对关系的方向感兴趣时,可以使用–>或<–符号,如:

查询:

START n=node(3)

MATCH (n)–>(x)

RETURN x

所有A的接出关系到达的节点将被返回.

定向关系和标识符

如果需要关系的标识符,为了过滤关系的属性或为了返回关系,可如下例使用标识符。

查询:

START n=node(3)

MATCH (n)-[r]->()

RETURN r

所有从节点A接出的关系将被返回。

通过关系类型匹配

当已知关系类型并想通过关系类型匹配时,可以通过冒号详细描述。

查询:

START n=node(3)

MATCH (n)-[:BLOCKS]->(x)

RETURN x

返回A接出关系类型为BLOCKS的节点。

通过关系类型匹配和使用标识符

如果既想获得关系又要通过已知的关系类型,那就都添加上,如:

查询:

START n=node(3)

MATCH (n)-[r:BLOCKS]->()

RETURN r

所有从A接出的关系为BLOCKS的关系都被返回。

带有特殊字符的关系类型

有时候数据库中有非字母字符类型,或有空格在内时,使用单引号。

查询:

START n=node(3)

MATCH (n)-[r:TYPE WITH SPACE IN IT]->()

RETURN r

返回类型有空格的关系。

多重关系

关系可以通过使用在()—()多个语句来表达,或可以串在一起。如下:

查询:

START a=node(3)

MATCH (a)-[:KNOWS]->(b)-[:KNOWS]->©

RETURN a,b,c

路径中的三个节点。

可变长度的关系

可变数量的关系->节点可以使用-[:TYPE*minHops…maxHops]->。

查询:

START a=node(3), x=node(2, 4)

MATCH a-[:KNOWS*1…3]->x

RETURN a,x

如果在1到3的关系中存在路径,将返回开始点和结束点。

在可变长度关系的关系标识符

当连接两个节点的长度是可变的不确定的时,可以使用一个关系标识符遍历所有关系。

查询:

START a=node(3), x=node(2, 4)

MATCH a-[r:KNOWS*1…3]->x

RETURN r

如果在1到3的关系中存在路径,将返回开始点和结束点。

零长度路径

当使用可变长度路径,可能其路径长度为0,这也就是说两个标识符指向的为同一个节点。如果两点间的距离为0,可以确定这是同一个节点。

查询:

START a=node(3)

MATCH p1=a-[:KNOWS0…1]->b, p2=b-[:BLOCKS0…1]->c

RETURN a,b,c, length(p1), length(p2)

这个查询将返回四个路径,其中有些路径长度为0.

可选关系

如果关系为可选的,可以使用问号表示。与SQL的外连接类似。如果关系存在,将被返回。如果不存在在其位置将以null代替。

查询:

START a=node(2)

MATCH a-[?]->x

RETURN a,x

返回一个节点和一个null,因为这个节点没有关系。

可选类型和命名关系

通过一个正常的关系,可以决定哪个标识符可以进入,那些关系类型是需要的。

查询:

START a=node(3)

MATCH a-[r?:LOVES]->()

RETURN a,r

返回一个节点和一个null,因为这个节点没有关系。

可选元素的属性

返回可选元素上的属性,null值将返回null。

查询:

START a=node(2)

MATCH a-[?]->x

RETURN x, x.name

元素x在查询中为null,所有其属性name为null。

复杂匹配

在Cypher中,可哟通过更多复杂模式来匹配,像一个钻石形状模式。

查询:

START a=node(3)

MATCH (a)-[:KNOWS]->(b)-[:KNOWS]->©,(a)-[:BLOCKS]-(d)-[:KNOWS]-©

RETURN a,b,c,d

路径中的四个节点。

最短路径

使用shortestPath函数可以找出一条两个节点间的最短路径,如下。

查询:

START d=node(1), e=node(2)

MATCH p = shortestPath( d-[*…15]->e )

RETURN p

这意味着:找出两点间的一条最短路径,最大关系长度为15.圆括号内是一个简单的路径连接,开始节点,连接关系和结束节点。关系的字符描述像关系类型,最大数和方向在寻找最短路径中都将被用到。也可以标识路径为可选。

所有最短路径

找出两节点节点所有的最短路径。

查询:

START d=node(1), e=node(2)

MATCH p = allShortestPaths( d-[*…15]->e )

RETURN p

这将在节点d与e中找到两条有方向的路径。

命名路径

如果想在模式图上的路径进行过滤或者返回此路径,可以使用命名路径(named path)。

查询:

START a=node(3)

MATCH p = a–>b

RETURN p

开始节点的两个路径。

在绑定关系上的匹配

当模式中包含一个绑定关系时,此关系模式没有明确的方向,Cypher将尝试着切换连接节点的边匹配关系。

查询:

START a=node(3), b=node(2)

MATCH a-[?:KNOWS]-x-[?:KNOWS]-b

RETURN x

将返回两个连接节点,一次为开始节点,一次为结束节点。

Where

如果需要从查找的数据的图中过滤,可以在查询语句中添加where子句。

Boolean 操作类型

可以使用boolean操作符and 和 or 或者也可以使用not()函数。

查询:

START n=node(3, 1)

WHERE (n.age < 30 and n.name = “Tobias”) ornot(n.name = “Tobias”)

RETURN n

返回节点。

节点属性上的过滤

查询:

START n=node(3, 1)

WHERE n.age < 30

RETURN n

正则表达式

可以通过使用=~ /regexp/来匹配正在表达式。如下:

查询:

START n=node(3, 1)

WHERE n.name =~ /Tob.*/

RETURN n

返回名叫Tobias的节点。

转义正则表达式

如果在正则表达式中需要有斜杠时可以通过转义实现。

查询:

START n=node(3, 1)

WHERE n.name =~ /Some/thing/

RETURN n

没有匹配的节点返回。

不分大小些正则表达式

在正则表达式前加上?i,整个正则表达式将会忽略大小写。

查询:

START n=node(3, 1)

WHERE n.name =~ /(?i)ANDR.*/

RETURN n

属性name为Andres的节点将返回

关系类型上的过滤

可以match模式中通过添加具体的关系类型,但有时需要针对类型的更加高级的过滤。可以使用明确的type属性来对比,查询对关系类型名作一个正则比较。

查询:

START n=node(3)

MATCH (n)-[r]->()

WHERE type® =~ /K.*/

RETURN r

关系整个以K开始的类型名都将返回。

属性存在性

查询:

START n=node(3, 1)

WHERE n.belt

RETURN n

如果缺失属性默认为true

仅当属性存在时,比较一个图的元素的此属性,使用允许空属性的语法。

查询:

START n=node(3, 1)

WHERE n.belt? = ‘white’

RETURN n

所有节点即使没有belt属性的 都将返回。此类比较返回为true。

如果缺失属性默认为false

需要在缺失属性时为false,即不想返回此属性不存在的节点时。使用感叹号。

查询:

START n=node(3, 1)

WHERE n.belt! = ‘white’

RETURN n

空置Null过滤

有时候需要测试值或者标识符是否为Null。与sql类似使用 is null 或 is not null也能起作用。

查询:

START a=node(1), b=node(3, 2)

MATCH a<-[r?]-b

WHERE r is null

RETURN b

Tobias节点没有链接上。

关系过滤

为过滤两点间基于关系的子图,在match子句中使用限制部分。可以描述带方向的关系和可能的类型。

这些都是有效的表达:WHERE a-→b WHERE a←-b WHERE a←[:KNOWS]-bWHERE a-[:KNOWS]-b

查询:

START a=node(1), b=node(3, 2)

WHERE a<–b

RETURN b

Tobias节点没有链接

Neo4j 综合

查询中的返回部分,返回途中定义的感兴趣的部分。可以为节点、关系或其上的属性。

返回节点

返回一个节点,在返回语句中列出即可。

查询:

START n=node(2)

RETURN n

返回关系

查询:

START n=node(1)

MATCH (n)-[r:KNOWS]->©

RETURN r

返回属性

查询:

START n=node(1)

RETURN n.name

带特殊字符的标识符

使用不在英语字符表中的字符,可以使用’单引号。

查询:

START This isn’t a commonidentifier=node(1)

RETURN This isn’t a commonidentifier.<<!!__??>>`

列的别名

可以给展示出来的列名起别名。

查询:

START a=node(1)

RETURN a.age AS SomethingTotallyDifferent

返回节点的age属性,但重命名列名。

可选属性

属性在节点上可能存在也可能不存在,可以使用问号来标识标识符即可。

查询:

START n=node(1, 2)

RETURN n.age?

如果存在age属性,则返回,不存在则返回null。

特别的结果

DISTINCT 仅检索特别的行,基于选择输出的列。

查询:

START a=node(1)

MATCH (a)–>(b)

RETURN distinct b

返回name为B的节点,但仅为一次。

Neo4j 聚合函数

聚合(Aggregation)

为集合计算数据,Cypher提供聚类功能,与SQL的group by类似。在return语句中发现的任何聚类函数,所有没有聚类函数的列将作为聚合key使用。

计数

计数(count)使用来计算行数。Count有两种使用方法:

  • Count(*)计算匹配的行的行数;
  • Count(<标识符>)计算标识符中非空值数。
计算节点数

计算链接到一个节点的节点数,可以使用count(*)。

查询:

START n=node(2)

MATCH (n)–>(x)

RETURN n, count(*)

返回开始节点和相关节点节点数。

分组计算关系类型

计算分组了得关系类型,返回关系类型并使用count(*)计算。

查询:

START n=node(2)

MATCH (n)-[r]->()

RETURN type®, count(*)

返回关系类型和其分组数。

计算实体数

相比使用count(*),可能计算标识符更实在。

查询:

START n=node(2)

MATCH (n)–>(x)

RETURN count(x)

返回链接到开始节点上的节点数

计算非空可以值数

查询:

START n=node(2,3,4,1)

RETURN count(n.property?)

求和(sum)

Sum集合简单计算数值类型的值。Null值将自动去掉。如下:

查询:

START n=node(2,3,4)

RETURN sum(n.property)

计算所有节点属性值之和。

平均值(avg)

Avg计算数量列的平均值

查询:

START n=node(2,3,4)

RETURN avg(n.property)

最大值(max)

Max查找数字列中的最大值。

查询:

START n=node(2,3,4)

RETURN max(n.property)

最小值(min)

Min使用数字属性作为输入,并返回在列中最小的值。

查询:

START n=node(2,3,4)

RETURN min(n.property)

聚类(COLLECT)

Collect将所有值收集到一个集合list中。

查询:

START n=node(2,3,4)

RETURN collect(n.property)

返回一个带有所有属性值的简单列。

相异(DISTINCT)

聚合函数中使用distinct来去掉值中重复的数据。

查询:

START a=node(2)

MATCH a–>b

RETURN count(distinct b.eyes)

Neo4j 高级篇

排序(Order by)

输出结果排序可以使用order by 子句。注意,不能使用节点或者关系排序,仅仅只针对其属性有效。

通过节点属性排序节点

查询:

START n=node(3,1,2)

RETURN n

ORDER BY n.name

通过多节点属性排序节点

在order by子句中可以通过多个属性来排序每个标识符。Cypher首先将通过第一个标识符排序,如果第一个标识符或属性相等,则在order by中检查下一个属性,依次类推。

查询:

START n=node(3,1,2)

RETURN n

ORDER BY n.age, n.name

首先通过age排序,然后再通过name排序。

倒序排列节点

可以在标识符后添加desc或asc来进行倒序排列或顺序排列。

查询:

START n=node(3,1,2)

RETURN n

ORDER BY n.name DESC

空值排序

当排列结果集时,在顺序排列中null将永远放在最后,而在倒序排列中放最前面。

查询:

START n=node(3,1,2)

RETURN n.length?, n

ORDER BY n.length?

Skip

Skip允许返回总结果集中的一个子集。此不保证排序,除非使用了order by’子句。

跳过前三个

返回结果中一个子集,从第三个结果开始,语法如下:

查询:

START n=node(3, 4, 5, 1, 2)

RETURN n

ORDER BY n.name

SKIP 3

前三个节点将略过,最后两个节点将被返回。

返回中间两个

查询:

START n=node(3, 4, 5, 1, 2)

RETURN n

ORDER BY n.name

SKIP 1

LIMIT 2

中间两个节点将被返回。

Limit

Limit允许返回结果集中的一个子集。

返回第一部分

查询:

START n=node(3, 4, 5, 1, 2)

RETURN n

LIMIT 3

函数(Functions)

在Cypher中有一组函数,可分为三类不同类型:判断、标量函数和聚类函数

判断

判断为boolean函数,对给出的输入集合做判断并返回true或者false。常用在where子句中过滤子集。

All

迭代测试集合中所有元素的判断。

语法:

All(标识符 in iterable where 判断)

参数:

  • iterable :一个集合属性,或者可迭代的元素,或一个迭代函数。
  • 标识符:可用于判断比较的标识符。
  • 判断:一个测试所有迭代器中元素的判断。

查询:

START a=node(3), b=node(1)

MATCH p=a-[*1…3]->b

WHERE all(x in nodes§ WHERE x.age > 30)

RETURN p

过滤包含age〈30的节点的路径,返回符合条件路径中所有节点。

Any

语法:ANY(identifierin iterable WHERE predicate)

参数:

  • Iterable(迭代器):一个集合属性,或者可迭代的元素,或一个迭代函数。
  • Identifier(标识符):可用于判断比较的标识符。
  • Predicate(判断):一个测试所有迭代器中元素的判断。

查询:

START a=node(2)

WHERE any(x in a.array WHERE x = “one”)

RETURN a

None

在迭代器中没有元素判断将返回true。

语法:NONE(identifierin iterable WHERE predicate)

  • Iterable(迭代器):一个集合属性,或者可迭代的元素,或一个迭代函数。
  • Identifier(标识符):可用于判断比较的标识符。
  • Predicate(判断):一个测试所有迭代器中元素的判断。

查询:

START n=node(3)

MATCH p=n-[*1…3]->b

WHERE NONE(x in nodes§ WHERE x.age = 25)

RETURN p

Single

如果迭代器中仅有一个元素则返回true。

语法:SINGLE(identifierin iterable WHERE predicate)

参数:

  • Iterable(迭代器):一个集合属性,或者可迭代的元素,或一个迭代函数。
  • Identifier(标识符):可用于判断比较的标识符。
  • Predicate(判断):一个测试所有迭代器中元素的判断。

查询:

START n=node(3)

MATCH p=n–>b

WHERE SINGLE(var in nodes§ WHERE var.eyes = “blue”)

RETURN p

Scalar函数

标量函数返回单个值。

Length

使用详细的length属性,返回或过滤路径的长度。

语法:LENGTH(iterable )

参数:

  • Iterable(迭代器):一个集合属性,或者可迭代的元素,或一个迭代函数。

查询:

START a=node(3)

MATCH p=a–>b–>c

RETURN length§

返回路径的长度。

Type

返回关系类型的字符串值。

语法:TYPE(relationship )

参数:

  • Relationship:一条关系。

查询:

START n=node(3)

MATCH (n)-[r]->()

RETURN type®

返回关系r的类型。

Id

返回关系或者节点的id

语法:ID(property-container )

参数:

  • Property-container:一个节点或者一条关系。

查询:

START a=node(3, 4, 5)

RETURN ID(a)

返回这三个节点的id。

Coalesce

返回表达式中第一个非空值。

语法:COALESCE(expression [, expression]* )

参数:

  • Expression:可能返回null的表达式。

查询:

START a=node(3)

RETURN coalesce(a.hairColour?,a.eyes?)

Iterable函数

迭代器函数返回一个事物的迭代器—在路径中的节点等等。

Nodes

返回一个路径中的所有节点。

语法:NODES(path )

参数:

  • Path:路径

查询:

START a=node(3), c=node(2)

MATCH p=a–>b–>c

RETURN NODES§

Relationships

返回一条路径中的所有关系。

语法:RELATIONSHIPS(path )

参数:

  • Path:路径

查询:

START a=node(3), c=node(2)

MATCH p=a–>b–>c

RETURN RELATIONSHIPS§

Extract

可以使用extract单个属性,或从关系或节点集合迭代一个函数的值。将遍历迭代器中所有的节点并运行表达式返回结果。

语法:EXTRACT(identifier in iterable : expression )

  • Iterable(迭代器):一个集合属性,或者可迭代的元素,或一个迭代函数。
  • Identifier(标识符):闭包中表述内容的标识符,这决定哪个标识符将用到。
  • expression(表达式):这个表达式将对于迭代器中每个值运行一次,并生成一个结果迭代器。

查询:

START a=node(3), b=node(4),c=node(1)

MATCH p=a–>b–>c

RETURN extract(n in nodes§ : n.age)

返回路径中所有age属性值。

Neo4j常见问题

Q:neo4j数据库支持最大多少个节点?最大支持多少条边?

A目前累积统计它有34.4亿个节点,344亿的关系,和6870亿条属性。

Q:Neo4j数据库支持的最复杂的连接是什么?(比如每个节点都与其他任何一个节点相连)

A: 可以从上面的数字得出理论的极限:它基本上就产生了262144节点和34359607296的关系图。我们从来没有见过这种使用情况。

Q:在数据库中,读/写性能跟节点/边的数量有关吗?

这个问题意味着两个不同的问题。单次读/写操作不依赖数据库的大小。不管数据库是有10个节点还是有1千万个都一样。 — 然而,有一个事实是如果数据库太大,你的内存可能无法完全缓存住它,因此,你需要频繁的读写磁盘。虽然很多用户没有这样大尺寸的数据库,但有的人却有。如果不巧你的数据库达到了这个尺寸,你可以扩展到多台机器上以减轻缓存压力。

Q:Neo4j数据库支持的读/写并发请求最大数量是多少?

在并发请求上面没有任何限制。服务器的并发量更多的是依赖于操作本身的性能(高压写操作,简单读,复杂的遍历等等),以及使用的硬件性能。据粗略估计,在遍历最简单路径时每毫秒可以达到1000次请求。在讨论了指定的用户案例后,我们能得到更好的性能优化方案。

Q:在数据库集群环境中数据一致性如何保证的呢?

主从复制。从服务器从主服务器拉取数据变化。拉取间隔可以在每个从服务器上进行配置,从毫秒到分钟,根据你自己的需要来定。HA也可以通过从服务器来进行写操作。当发生时,从服务器通过追上主服务器来被写入,然后写入在主从之间完成。其他从服务器做一般处理。

Q:当在一个数据库中发生更新操作时如何快速更新其他所有服务器呢?

拉取间隔在每个从服务器上面进行配置,从几秒到几分钟不等,根据需求而定。当通过一个从服务器写操作时,从服务器立即在写之前与主服务器进行同步。一般情况下,读写加载不并影响从服务器的同步工作。一个复杂的写操作会给从服务器的文件系统巨大压力,与此同时,从服务器也要求拉取同步数据。实际上,我们不系统这成为一个关注的问题。

Q:在集群环境中,在不同服务器会出现按比例延迟新增吗?

在集群中从服务器超过10台的规模时,我们能预料到来自从服务器的大量的拉取请求会降低从服务器的性能。在集群中的写操作才会受影响,而读操作依然保持线性缩放。

Q:支持在线扩展吗?换句话说,如果我们想新加入一台服务器到集群中需要关闭所有服务器吗?

新的从服务器在不用停止或者启动整个集群的情况下可以被加入到一个已经存在的集群中。我们的HA协议会新增入加入的服务器。从服务器也可以简单的通过关闭他们自己来从集群中移除。

Q:新加入一台服务器到全部同步需要多长时间?

我们推荐在将从服务器加入之前先做一个最近的数据库的快照。一般通过备份来完成。从服务器之需要同步最近的更新,一般情况下只会一点点时间的数据。

Q:重启需要多久呢?

如果重启,你的意思是关闭集群然后再重启它,这完全依赖与你打字的速度。一般是10秒的样子。Neo4j的缓存不会自动预加载,而操作系统的文件系统缓存不会重置。

Q:是否有备份恢复机制?

Neo4j 企业版提供了一个在线备份(完整备份和增量备份)功能。

Q:是否支持跨区集群?跨区集群是否比同区集群性能更低呢?

我们有用户在AWS上面测试了多区域部署的情况。跨地区部署在集群管理的效率和协议同步上有一定影响。集群管理大量的延迟会触发主服务器的频繁重选,拖慢整个集群的速度。在跨区部署支持上面以后还需大量提升。

Q:是否有任何指定测控策略用于环境建立之类的需求?

关于这个话题我们有更深入的探讨。

Q:写数据库是线程安全的吗?

不管在单服务模式还是HA模式,数据库在更新之前都通过锁定节点和关系来保证线程安全。

Q:从HA读数据最好的策略是什么?

保持会话。

在response中发送返回数据,而在独立的请求中移除需要读回的数据。

当操作需要时,强制请求从主服务器做一个拉取数据更新操作。

Q:对于获取(如果不存在则创建)这中需求最好的策略是什么?

单线程模式。

如果不存在,悲观锁在一个普通节点上。

如果不存在,乐观创建它,然后再检查。

Q:如何锁定服务?

悲观锁。在读数据时并不要求锁。写操作并不会阻塞读操作。不用任何明确的锁定操作就可以完成读取数据操作是非常重要的。当一个节点或者属性修改或者新增时,写锁定会自动完成,或者也可以通过明确的锁设置。它常被用来提供读取语义和保证必须的数据一致性。

Q:数据存储占用空间如何?

Neo4j当前并不适合存储 BLOBs/CLOBs。节点,关系和属性并不是保存在磁盘的同一个地方。这个特性将来会进一步介绍。数据库索引怎么样? Neo4j支持复杂的属性索引。额外的索引功能超过了图本身的索引。Lucene引擎管理独立分页的索引并要求一些空间来存储一个自动索引以及管理私有索引(通过API搜索)。

Q:如何进行数据库查询?

核心 API, Traversal API, REST API, Cypher, Gremlin

Q:Neo4j有使用日志(在数据丢失时可以修复丢失的数据)功能吗?

在HA集群环境中基于主从服务器之间的写增量来完成。

Q:如何提升Neo4j的性能?

采用内存映射存储Neo4j文件,Neo4j缓存策略解释如下:

  1. 软索引缓存: 软索引在GC认为需要时会被随时清理。如果应用加载并不高时使用。
  2. 弱索引缓存: 不管GC是否找到,都会清理弱索引。如果在读取大量数据或者遍历操作时使用。
  3. 强索引缓存: 所有的节点和关系都会保存在内存中,JVM会阻止高加载的操作。比如半分钟的暂停间隔。 更大的堆大小是好的,然而12G或者更大的内存对于GC是不切实际的。如果用从磁盘获取数据做比较,用内存映射文件缓存会提供100倍性能,而用Java堆则会是1000倍。

在主从服务器直接的ACID事务。

在初始从服务器到主服务器的事务同步中,最终从主服务器到其他从服务器。用死锁探测来完成多个从服务器事务并发支持。从一个数据完整性的角度看是完全一致的,但是必须得重多个点考虑。

Q:独立服务器怎么样?

REST API是完全无状态的,但他也可以通过批量提交来实现大量事务支持。线程池和每个socket的线程:对于独立服务器和HA模式来说,Neo4j采用Jetty来连接线程池。(比如在HA集群中25/每节点)。

Q:在HA环境中如何使用负载均衡?

通常一个小型服务器扩展被写入后会返回200或404,取决于机器是否是主或从。 扩展被负载均衡服务器用来探测主从服务器设置。只写到从服务器来确保至少在两个地方存在提交事务。

Q:Neo4j支持那些监控器?

Neo4j目前没有内建的追踪和解释计划。JMX是用于统计和监控的主要接口。线程内容可以用于调试。

Q:如何导入数据到Neo4j中?

Neo4j批量插入用于初始化一个数据库。在批量插入后,存储的内容可以用与嵌入模式或者HA环境。直接跟传统SQL服务器直接的数据交换目前没有官方支持。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值