Neo4j图数据库
1. 文档简要
本文档简要描述了图数据库neo4j的应用场景、核心的概念等理论方面和应用方面中的操作语句cypher以及应用图数据库在应用中的几种开发方式。Neo4j多种集群的配置方式。
2. 参考文献
3. 定义及应用场景
图数据库源起欧拉和图理论,也可称为面向/基于图的数据库,对应的英文是Graph Database。图数据库的基本含义是以“图”这种数据结构存储和查询数据,而不是存储图片的数据库。它的数据模型主要是以节点和关系(边)来体现,也可处理键值对。它的优点是快速解决复杂的关系问题,包括如:数据项之间、模式之间的关系,或多个数据项之间。
是NOSQL数据库的一种,属于图类存储数据库,适合处理复杂网状结构关系的数据的存储查询,例如,传统应用:最优运输路线的确定、疾病爆发路径的预测、科技文献的应用关系等;新兴应用:社交网络分析,语义网络分析、生物信息网络分析、模式识别等;它解决了关系数据库在处理复杂网状关系在查询时的性能较低和复杂性高的问题,是处理该方面问题的有效的方式。
各模块功能说明如下:
查询和计算:最终用户用于在此语言基础之上进行图的遍历和查询,最终返回运行结果,如能提供RESTful API则能给开发者提供不少便利之处。
操作和运维:用于系统实时监控,例如系统配置、安装、升级、运行时监控,甚至包括可视化界面等。
数据加载:包括离线数据加载和在线数据加载,既可以是批量的数据加载,也可以是流数据加载方式。
图数据库核心:主要包括图存储和图处理引擎这两个核心。图处理引擎负责实时数据更新和执行图运算;图存储负责将关系型数据及其他非结构化数据转换成图的存储格式;HA服务负责处理处理数据容错、数据一致性以及服务不间断等功能。
Neo4J即为图数据库中的一种,是目前热度最高的图数据,分为企业版和社区版本;
可以通过GraphGist 将复杂的图关系使用符合格式的text文档中的数据上传后,生成丰富的可交互式的图,我们可以通过浏览器访问。
详细的场景分析可参考官网链接以及GraphGist中的实例。
Neo4j两种运行方式:
u Embedded模式:图数据库与你的程序像在一起一样,不是真的在一起,需要制定数据存储目录; 通过指定的磁盘目录标示图服务位置,使用neo4j原生API开启事务,在事务中进行图的各种操作;
u Server Standalone模式:使用neo4j数据库服务器,和我们目前应用关系型数据库方式一样。
4. 特性及原理
满足ACID的要求,即事务完全支持。满足CAP中的CP特征,保证数据一致性和分区容忍性,有时可用性不能很好的保证。可以处理上亿节点的与关系,有非常快的查询速度。
5. 缺点
1. 社区版免费开源,但是企业级项目实用性不强,只能在本机嵌入式使用,且仅支持java和基于jvm的语言,不能使用集群。
2. 企业版闭源且费用昂贵,集群也只是HA高可用,不能进行分布式存储。
3. 图数据结构导致写入性能差,大数据量导入麻烦,官方提供的load csv模式性能也不够理想,neo4j-import倒是不错,但是只能用于数据库初始化局限太大。
6. 核心概念
3.2.1
3.2.2
3.2.3
3.2.4
3.2.5
3.2.6
6.1 节点
6.2 关系
6.3 属性
6.4 标签
7. Schema
3.2.7
7.1 索引
索引是创建在label上的属性上,包含2大类,单属性索引和复合索引。主要用于cypher查询时提供更加快速的查询。
创建单索引:CREATE INDEX ON :Person(firstname)
创建复合索引:CREATE INDEX ON :Person(firstname, surname)
删除索引:DROP INDEX ON :Person(firstname)
删除复合索引:DROP INDEX ON :Person(firstname, surname)
7.2 约束
Neo4j通过使用约束来帮助实现数据的完整性。约束可以应用于节点或关系。可以创建唯一节点属性约束,以及节点和关系属性存在约束,以及节点密钥,其保证存在和唯一性。可针对节点上的属性做唯一约束,存在约束;关系属性存在约束;以及类似于关系型数据库主键的Node约束,它设置在节点的单个或者多个属性上。创建以上约束后,在写入或者merge执行时会做相应的检查。
8. 存储结构
Neo4j作为图形数据库,有其独特的数据存储结构。数据存储主要分为节点、关系、节点或关系上属性这三类数据存储。
在这个例子中,A~E表示Node 的编号,R1~R7 表示 Relationship 编号,P1~P10 表示Property 的编号。
Node 的存储示例图如下,每个Node 保存了第1个Property 和 第1个Relationship:
关系的存储示意图如下:
从示意图可以看出,从 Node-B 开始,可以通过关系的 next 指针,遍历Node-B 的所有关系,然后可以到达与其有关系的第1层Nodes,在通过遍历第1层Nodes的关系,可以达到第2层Nodes,…。
3.2.8
8.1 存储 node 的文件
1. 存储节点数据及其序列Id
o neostore.nodestore.db: 存储节点数组,数组的下标即是该节点的ID
o neostore.nodestore.db.id :存储最大的ID 及已经free的ID
2. 存储节点label及其序列Id
o neostore.nodestore.db.labels :存储节点label数组数据,数组的下标即是该节点label的ID
o neostore.nodestore.db.labels.id
8.2 存储 relationship 的文件
1. 存储关系数据及其序列Id
o neostore.relationshipstore.db 存储关系 record 数组数据
o neostore.relationshipstore.db.id
2. 存储关系组数据及其序列Id
o neostore.relationshipgroupstore.db 存储关系 group数组数据
o neostore.relationshipgroupstore.db.id
3. 存储关系类型及其序列Id
o neostore.relationshiptypestore.db 存储关系类型数组数据
o neostore.relationshiptypestore.db.id
4. 存储关系类型的名称及其序列Id
o neostore.relationshiptypestore.db.names 存储关系类型 token 数组数据
o neostore.relationshiptypestore.db.names.id
8.3 存储 label 的文件
1. 存储label token数据及其序列Id
o neostore.labeltokenstore.db 存储lable token 数组数据
o neostore.labeltokenstore.db.id
2. 存储label token名字数据及其序列Id
o neostore.labeltokenstore.db.names 存储 label token 的 names 数据
o neostore.labeltokenstore.db.names.id
8.4 存储 property 的文件
1. 存储属性数据及其序列Id
o neostore.propertystore.db 存储 property 数据
o neostore.propertystore.db.id
2. 存储属性数据中的数组类型数据及其序列Id
o neostore.propertystore.db.arrays 存储 property (key-value 结构)的Value值是数组的数据。
o neostore.propertystore.db.arrays.id
3. 属性数据为长字符串类型的存储文件及其序列Id
o neostore.propertystore.db.strings 存储 property (key-value 结构)的Value值是字符串的数据。
o neostore.propertystore.db.strings.id
4. 属性数据的索引数据文件及其序列Id
o neostore.propertystore.db.index 存储 property (key-value 结构)的key 的索引数据。
o neostore.propertystore.db.index.id
5. 属性数据的键值数据存储文件及其序列Id
o neostore.propertystore.db.index.keys 存储 property (key-value 结构)的key 的字符串值。
o neostore.propertystore.db.index.keys.id
8.5 其他的文件
1. 存储版本信息
o neostore
o neostore.id
2. 存储 schema 数据
o neostore.schemastore.db
o neostore.schemastore.db.id
3. 活动的逻辑日志
o nioneo_logical.log.active
4. 记录当前活动的日志文件名称
o active_tx_log
neo4j 中,主要有4类节点,属性,关系等文件是以数组作为核心存储结构;同时对节点,属性,关系等类型的每个数据项都会分配一个唯一的ID,在存储时以该ID 为数组的下标。这样,在访问时通过其ID作为下标,实现快速定位。所以在图遍历等操作时,可以实现 free-index。
9. Cypher语言
Cypher是Neo4J支持的对该数据库中数据的进行CRUD操作的语言。使用模式匹配描述图数据,类似SQL的申明式语句(只描述做什么,不需要告诉怎么做)。
q 创建节点:Create
CREATE (:Person { name: "Emil", from: "Sweden", klout: 99 })
· CREATE clause to create data
· () parenthesis to indicate a node 小括号代表数据节点
· ee:Person a variable 'ee' and label 'Person' for the new node 节点变量名为“ee”,并设置节点标签为“Person”。
· {} brackets to add properties to the node 花括号中使用json格式的制定数据节点的属性。
使用create子句一次创建多个节点和关系
MATCH (ee:Person) WHERE ee.name = "Emil"
CREATE (js:Person { name: "Johan", from: "Sweden", learn: "surfing" }),
(ir:Person { name: "Ian", from: "England", title: "author" }),
(rvb:Person { name: "Rik", from: "Belgium", pet: "Orval" }),
(ally:Person { name: "Allison", from: "California", hobby: "surfing" }),
(ee)-[:KNOWS {since: 2001}]->(js),(ee)-[:KNOWS {rating: 5}]->(ir),
(js)-[:KNOWS]->(ir),(js)-[:KNOWS]->(rvb),
(ir)-[:KNOWS]->(js),(ir)-[:KNOWS]->(ally),
(rvb)-[:KNOWS]->(ally)
使用逗号分开多条语句;使用[]中括号描述关系,同时可指定关系名称和属性;格式:[:关系名称{属性对}]。
q 匹配数据:Match
MATCH (ee:Person) WHERE ee.name = "Emil" RETURN ee;
· MATCH clause to specify a pattern of nodes and relationships MATCH 子句指明模式来匹配数据节点和关系
· (ee:Person) a single node pattern with label 'Person' which will assign matches to the variable 'ee' 单数据节点模式,并指定标签为person,数据节点变量名为ee
· WHERE clause to constrain the results 限制匹配结果
· ee.name = "Emil" compares name property to the value "Emil"
· RETURN clause used to request particular results 返回请求的结果
MATCH (ee:Person)-[:KNOWS]-(friends)
WHERE ee.name = "Emil" RETURN ee, friends
· MATCHclause to describe the pattern from known Nodes to found Nodes 匹配子句描述模式为:从已知节点去查询符合关系规则的节点
· (ee)starts the pattern with a Person (qualified by WHERE)
· -[:KNOWS]-matches "KNOWS" relationships (in either direction) 匹配KNOWS关系,不区分方向。
· (friends)will be bound to Emil's friends 查询绑定到Emil的朋友
应用于推荐的匹配查询
Johan在学习冲浪,因此他希望查询出他朋友的朋友的业余爱好是冲浪的人,可以通过以下语句:
MATCH (js:Person)-[:KNOWS]-()-[:KNOWS]-(surfer)
WHERE js.name = "Johan" AND surfer.hobby = "surfing"
RETURN DISTINCT surfer
· ()empty parenthesis to ignore these nodes 空括号表示忽略该节点数据
· DISTINCTbecause more than one path will match the pattern
· surferwill contain Allison, a friend of a friend who surfs
PROFILE MATCH (js:Person)-[:KNOWS]-()-[:KNOWS]-(surfer)
WHERE js.name = "Johan" AND surfer.hobby = "surfing"
RETURN DISTINCT surfer
使用PROFILE和EXPLAIN查看查询的过程。
使用LIMIT子句返回前N条数据。
MATCH (people:Person) RETURN people.name LIMIT 10
关系查询时使用匹配规则,满足更多情况查询。
MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..4]-(hollywood)
RETURN DISTINCT Hollywood
MATCH p=shortestPath(
(bacon:Person {name:"Kevin Bacon"})-[*]-(meg:Person {name:"Meg Ryan"})
)
RETURN p
q 删除数据:DELETE
删除子句用于删除数据节点和关系,和match子句确定删除的数据可使用where子句过滤。记住,您不能删除节点,而不删除在所述节点上开始或结束的关系。如果存在关系,则无法删除节点,需一起删除节点和关系。
DETACH DELETE删除所有的节点和关系。
MATCH (n) DETACH DELETE n
q 其他重要子句
merge、with、set、remove、limit,及可以使用hint方式的使用。
q 函数和存储过程
1. 函数完成简单的计算和转换,并且返回值只能是单个值。
2. 函数可以运用在表达式中和谓词中。
3. 存储过程完成复杂的计算,其返回值可以为数据流格式的返回值。
4. 存储过程必须使用call进行调用,使用yield处理存储过程的返回值。
5. 存储过程可以处理函数不能处理的一些功能,如:自定义的索引和约束的内省;函数功能比存储过程简单但是高效;
6. 用户可以自定义函数和存储过程,通过使用java语言开发,然后打包发布成jar包放到其插件目录中,即可以在cypher中使用。
q 性能调优和执行计划
调优的目标就是保证每次查询只返回必须的数据,减少数据检索扫描时间。查询时分为很多步骤,尽量在查询最开始的步骤中就减少数据量。避免查询返回所有的节点或者关系数据,在使用模式时,一般指定其最大匹配限制,避免扫描不相关的数据部分。
Cypher的查询引擎目前支持基于规则的优化,和基于成本的优化。从3.2版本后,所有的查询默认使用基于成本的优化。
在该查询引擎中也支持对参数语句的缓存,来减少语句解析分析的时间,提供执行效率。
通过提供的profile或者explain子句,可对语句的执行计划的分析,执行计划中的每一步操作有操作类型,并显示预估扫描的行数,是否使用缓存及缓存命中数等。
q Cypher语句索引
Reading clauses
Clause | Description |
MATCH | Specify the patterns to search for in the database. |
OPTIONAL MATCH | Specify the patterns to search for in the database while using nulls for missing parts of the pattern. |
START | Find starting points through legacy indexes. |
Projecting clauses
Clause | Description |
RETURN | Defines what to include in the query result set. |
WITH | Allows query parts to be chained together, piping the results from one to be used as starting points or criteria in the next. |
UNWIND | Expands a list into a sequence of rows. |
Reading sub-clauses
Sub-clause | Description |
WHERE | Adds constraints to the patterns in a MATCH or OPTIONAL MATCH clause or filters the results of a WITH clause. |
ORDER BY | A sub-clause following RETURN or WITH, specifying that the output should be sorted in particular way. |
SKIP | Defines from which row to start including the rows in the output. |
LIMIT | Constrains the number of rows in the output. |
Reading hints
Hint | Description |
USING INDEX | Index hints are used to specify which index, if any, the planner should use as a starting point. |
USING SCAN | Scan hints are used to force the planner to do a label scan (followed by a filtering operation) instead of using an index. |
USING JOIN | Join hints are used to enforce a join operation at specified points. |
Writing clauses
Clause | Description |
CREATE | Create nodes and relationships. |
DELETE | Delete graph elements — nodes, relationships or paths. Any node to be deleted must also have all associated relationships explicitly deleted. |
DETACH DELETE | Delete a node or set of nodes. All associated relationships will automatically be deleted. |
SET | Update labels on nodes and properties on nodes and relationships. |
REMOVE | Remove properties and labels from nodes and relationships. |
FOREACH | Update data within a list, whether components of a path, or the result of aggregation. |
Reading/Writing clauses
Clause | Description |
MERGE | Ensures that a pattern exists in the graph. Either the pattern already exists, or it needs to be created. |
--- ON CREATE | Used in conjunction with MERGE, this write sub-clause specifies the actions to take if the pattern needs to be created. |
--- ON MATCH | Used in conjunction with MERGE, this write sub-clause specifies the actions to take if the pattern already exists. |
CALL…YIELD | Invoke a procedure deployed in the database and return any results. |
CREATE UNIQUE | A mixture of MATCH and CREATE, matching what it can, and creating what is missing. |
Set operations
Clause | Description |
UNION | Combines the result of multiple queries into a single result set. Duplicates are removed. |
UNION ALL | Combines the result of multiple queries into a single result set. Duplicates are retained. |
Importing data
Clause | Description |
LOAD CSV | Use when importing data from CSV files. |
--- USING PERIODIC COMMIT | This query hint may be used to prevent an out-of-memory error from occurring when importing large amounts of data using LOAD CSV. |
Schema clauses
Clause | Description |
CREATE | DROP CONSTRAINT | Create or drop an index on all nodes with a particular label and property. |
CREATE | DROP INDEX | Create or drop a constraint pertaining to either a node label or relationship type, and a property. |
10. 外部数据导入
3.2.9
3.2.10
10.1 Cypher CREATE 语句
为每一条数据生成一条cypher中的create语句,使用事务提交。
CREATE (:label {property1:value, property2:value, property3:value} )
10.2 LOAD CSV 语句
using periodic commit 1000
load csv from "file:///fscapture_screencapture_syscall.csv" as line
create (:label {a:line[1], b:line[2], c:line[3], d:line[4], e:line[5], f:line[6], g:line[7], h:line[8], i:line[9], j:line[10]})
使用了语句USING PERIODIC COMMIT 1000,使得每1000行作为一次Transaction提交。
10.3 官方提供的Java API —— Batch Inserter(链接)
10.4 第三方开源的 Batch Import 工具(链接)
10.5 官方提供的 neo4j-import 工具(链接)
neo4j_home$ ./bin/neo4j-import --into path_to_target_directory --nodes movies2.csv --nodes actors2.csv --relationships roles2.csv --delimiter ";" --array-delimiter "|" --quote "'"
以上3中方法,在条件允许的情况下优先使用官方提供的导入工具。针对所有的数据导入和写入neo4j的方法,有以下比较分析图表:
| CREATE语句 | LOAD CSV语句 | Batch Inserter | Batch Import | Neo4j-import |
适用场景 | 1 ~ 1w nodes | 1w ~ 10 w nodes | 千万以上 nodes | 千万以上 nodes | 千万以上 nodes |
速度 | 很慢 (1000 nodes/s) | 一般 (5000 nodes/s) | 非常快 (数万 nodes/s) | 非常快 (数万 nodes/s) | 非常快 (数万 nodes/s) |
优点 | 使用方便,可实时插入。 | 使用方便,可以加载本地/远程CSV;可实时插入。 | 速度相比于前两个,有数量级的提升 | 基于Batch Inserter,可以直接运行编译好的jar包;可以在已存在的数据库中导入数据 | 官方出品,比Batch Import占用更少的资源 |
缺点 | 速度慢 | 需要将数据转换成CSV | 需要转成CSV;只能在JAVA中使用;且插入时必须停止neo4j | 需要转成CSV;必须停止neo4j | 需要转成CSV;必须停止neo4j;只能生成新的数据库,而不能在已存在的数据库中插入数据。 |
11. 应用:图数据和关系数据库集成
许多公司通过使用neo4j图数据库对高度关联连接的数据进行智能分析,达到很好的效果,由于图数据库的特性,在处理该方面的数据有天生的优势,但目前大部分的数据存储在关系型数据库中,因此怎样结合集成这2类数据库成为应用的关键。
将图形数据库引入到组合中不一定是一个破坏性的过程。与任何技术一样,了解其对整个系统的位置和贡献对于确定件如何组合在一起是关键。
3.2.11
11.1 职责描述
1) 现有的关系型数据库如:MySQL,在我们应用中将继续是主要的存储数据库。
2) Neo4j将是一个次要数据存储,其数据量小得多,主要用于以下两种方式:
a) OLTP模式:业务必须近实时的响应一些功能,因此有一定数量的数据尽可能保持最新。
b) 批量模式:其中一些数据以延迟方式收集和处理。
我们需要一种方法来使新的Neo4j系统在我们的主要RDBMS中随着时间的推移已经收集到的数据加快速度,其次,一旦Neo4j系统启动并运行,它们将保持同步。
基于此情况,我们需要考虑2方面的问题:初始化数据导入和后续数据同步的问题。初始化数据的导入我们选择的方式较多,可参考上节的内容。
后续数据同步:根据打算用Neo4j做什么,你可以决定定期导入数据来满足要求,可以运行一个预定的过程来完成我们在初始导入时所做的工作;如果事情产生时你即可获得,则可以使用event-base的集成方案。事件在源系统中产生,比如:新产品创建、订单生成等,neo4j系统可以获得该信息然后处理它。我们可以使用消息队列技术连接将多个系统联系起来。
应用程序松散耦合,并且将多种格式的多个数据源的数据消耗的问题简化为一个简单的解析问题。 我们发现这种方法运作良好。导入可能需要一段时间,因为它是事务性的,但考虑到初始导入不是一个频繁的过程,等待是值得的,不需要引入另一个数据导入工具。一旦处理好了这一点,基于事件的同步工作就会很好。
如开头所述,了解应用程序的数据同步模式对于确定如何处理它是非常重要的。如果您需要一次性迁移数据,上述方法可能是过度的,如果使用Neo4j服务器,您应该考虑一些可用的优秀工具,如批量导入器,GEOFF或REST批处理API。 而且,如果您希望使用带注释的自动映射实体类,Spring Data是需要考虑的方案。
12. 集群
集群特性只在企业版中才支持。Neo4j提供两个独立的解决方案,以确保高需求生产环境中的冗余和性能。目前这两种集群配置下,所有的数据全量存储到每一个节点实例上,不支持分片存储的方式。In both configurations, the full dataset is replicated to each instance – Neo4j doesn't currently support "sharding" a graph across instances of a cluster.
可以为您的组织设置HA和因果Neo4j集群。一般来说,我们发现大多数应用程序由单个HA集群提供服务,但是需要极端容错设置和地理分布的系统可能会受益于因果聚类。
3.2.12
因果集群是neo4j3.1版本发布的新的集群架构,基于Raft协议开发,可使Neo4j支持数据中心和云所用的大规模集群和多种集群拓扑。该技术中内置了由Neo4j Bolt驱动处理的负载均衡。Neo4j数据库还支持新的集群可感知会话,该会话同样是由Bolt驱动管理,有助于为开发人员解决架构上的问题。
新提供的因果集群是一种用于交易数据库集群的全新架构和方法。该方法的实现独立于以前版本中的Neo4j高可用(HA)技术,解决了HA方法中存在的一些问题。
因果集群主要着眼于提供全面的数据安全,即事务安全操作和可用性。该技术的构建一方面基于Neo4j一贯具备的强事务支持,这是通过Raft协议实现的;另一方面基于异步复制协议,它扩展了“读自写”(read-your-own-writes)一致性保证,可用于非常大规模的集群。
因果集群提供了远超最终一致性的、最为简单但最充分的一致性保证,即无论集群的规模如何,你都可随后读取你所写的。
新的因果集群在架构上具有两个主要组成部分:
u 一个服务器核心(Core),它接受写操作,并对数据安全做断言。核心组成了实际的(活跃的)集群。它使用Raft协议,为仲裁(Quorum)写操作、集群成员信息和领导者(Leader)信息等一系列集群操作提供一致性。
u 任意数量的读副本服务器,使得图查询可以横向扩展。
多台主机部署因果集群
1. 修改Network connector configuration组下的配置。
dbms.connectors.default_listen_address:本机用于接收消息的网络地址。放开默认的注释,设置为0.0.0.0
dbms.connectors.default_advertised_address:告知其他机器的连接网络地址。一般设置为本机的IP地址或者DNS域名。
修改Causal Clustering Configuration组下的配置。
dbms.mode:设置本机实例在集群中的角色,包含:CORE和READ_REPLICA2种,根据实际情况设置。
causal_clustering.expected_core_cluster_size:启动的初始集群大小。注意:设置的是核心节点数,不包含读副本节点。按照要求最少的节点数是3。
causal_clustering.initial_discovery_members:可用于引导此Core或Read副本实例的初始集群核心集群成员的网络地址。以逗号分隔包含网络地址和端口,一般设置为CORE节点的位置,默认端口为5000。
2. 部署读副本节点
在部署读副本节点时,其他配置几乎不需要调整,只需要设置dbms.mode为READ_REPLICA即可。
3. 集群节点扩展的方法
最简单的方式:设置本机default_advertised_address地址;按照需求设置dbms.mode模式;设置initial_discovery_members为已启动的core节点即可。并不需要修改之前已启动的各个节点的相关配置。
4. 检查集群是否正常方法
访问通过集群提供的http服务,如:http://172.16.238.128:7474/browser/;在提供的命令行中使用CALL dbms.cluster.overview() #检查集群情况;:sysinfo #查看集群信息;可以看到配置的所有core节点和读副本节点。
以上的配置信息是启动集群需要做的最小配置项,系统提供了很多的相关配置项。参考
一台主机多端口部署因果集群
此种方法部署方式使用了多端口上启动多个服务来模拟多台服务节点实现,配置信息和上一种方式一致,唯一需要注意的就是避免服务的端口冲突即可,通过在一台机器上多端口模拟集群服务,只可用于测试和学习场景,在生产场景不可用。
多主机部署高可用集群
1. 设置节点ID,在集群中唯一不重复。
ha.server_id = 1 # can not be negative id and must be unique
2. 设置高可用集群初始服务节点列表
ha.initial_hosts = 192.168.0.20:5001,192.168.0.21:5001,192.168.0.22:5001
3. 设置主机模式为高可用
dbms.mode=HA
4. 每一台主机节点的配置几乎一样,只需要保障其ha.server_id 不重复即可。
13. 示例demo(原生API)
3.2.13
13.1 驱动类driver
生命周期:同关系型数据库类似,在启动时构造一个驱动实例,在退出时销毁该实例。销毁实例的同时会马上关闭在通过该驱动实例打开的所有数据库连接,在驱动实例中包含的一个连接池,也会随着实例销毁关闭。
为构造一个驱动实例,必须提供一个连接的URI和认证相关信息。另外,如果系统需要的话还可以使用其他更加丰富的配置信息。在驱动实例的整个生命周期配置项信息是不可变的,因此如果需要多个配置的话,则需要多个驱动实例。
连接URI:指明图数据库,并指定连接方式。目前版本,支持2中的驱动模式:直接驱动和路由驱动;
URI Scheme | Driver object type | Example |
Bolt | Direct driver | bolt://localhost:7687 |
bolt+routing | Routing driver | bolt+routing://graph.example.com:7687 |
直接驱动即通过bolt URI创建的链接,这一类型的驱动主要应用于单数据库的情况;路由驱动通过Bolt Routing Protocol协议创建,以串联的方式工作,可在集群中多个实例中路由事务。
13.2 会话类session
会话是一系列事务的容器。会话根据需要从池中借用连接,因此应该被认为是轻量级的和一次性的。在线程安全是一个问题的语言中,会话不应被视为线程安全的。在支持它们的语言中,会话通常在上下文块内定义。需要确保它们被正确关闭,并且任何底层连接被释放并且不泄漏。
13.3 事务transaction
事务是由一个或者多个cypher语句执行statement的最小原子单元,事务通过会话执行。执行一个cypher需要2部分信息,statement模板和参数。模板中使用占位符来表示参数,尽管可以不使用占位符来描述需要执行的cypher语句,但最好不要这样使用。使用占位符的语句模板可以被cypher引擎缓存,极大提升性能。参数的值通过Values指定。其实这个和关系型数据库中的prepare statement一样。
Neo4j提供了3中事务机制:
l 自动提交事务机制
l 事务方法
l 显式事务
其中,只有事务方法的方式可以在故障时自动重放。
自动提交事务
是一种简单但有限的事务形式。这样的事务只能包含一个Cypher statement,不能在失败时自动重播,也不能参与因果链。
自动提交事务通过session.run方法调用。
public void addPerson( String name )
{
try ( Session session = driver.session() )
{
session.run( "CREATE (a:Person {name: $name})", Values.parameters( "name", name ) );
}
}
自动提交事务被发送到网络并立即确认。这意味着多个事务不能共享网络数据包,从而比其他事务形式表现出较小的网络效率。
自动提交事务旨在用于简单的用例,例如在学习Cypher或写入一次性脚本时。不建议在生产环境中使用自动提交事务,或者在性能或弹性是主要问题时使用。
然而,自动提交事务是执行使用PERIODIC COMMIT Cypher语句的唯一方法。
事务方法
事务函数是包含事务工作单位的推荐方式。此模板需要最少的样板代码,并允许清楚地分离数据库查询和应用程序逻辑。
public void addPerson( final String name )
{
try ( Session session = driver.session() )
{
session.writeTransaction( new TransactionWork<Integer>()
{
@Override
public Integer execute( Transaction tx )
{
return createPersonNode( tx, name );
}
} );
}
}
private static int createPersonNode( Transaction tx, String name )
{
tx.run( "CREATE (a:Person {name: $name})", parameters( "name", name ) );
return 1;
}
在事务方法中获得的任何查询结果都应该在该函数内被使用。事务函数可以返回值,但这些应该是派生值而不是原始结果。
显式事务
显式事务是事务功能的长期形式,提供对事务显式BEGIN,COMMIT和ROLLBACK操作的访问。虽然此形式对于少数用例很有用,但建议尽可能使用事务方法。
13.4 访问模式
系统分为读和写模式,在neo4j中数据的读、写都需要事务,这一点和关系型数据库不一致。并且,驱动程序不解析Cypher,无法确定事务是否用于执行读或写操作。作为结果,标记为读取的写入事务将被发送到读取服务器,但在执行时将失败。Neo4j的因果集群类似于mysql的读写分库的方式,在读取时和写入时根据代码中指明的方式开启读事务和写事务。
//读、写都需要事务,在代码中必须指定准确
public long addPerson(final String name) {
try (Session session = driver.session()) {
session.writeTransaction(new TransactionWork<Void>() {
@Override
public Void execute(Transaction tx) {
return createPersonNode(tx, name);
}
});
return session.readTransaction(new TransactionWork<Long>() {
@Override
public Long execute(Transaction tx) {
return matchPersonNode(tx, name);
}
});
}
}
private Void createPersonNode(Transaction tx, String name) {
tx.run("CREATE (a:Person {name: $name})", parameters("name", name));
return null;
}
private long matchPersonNode(Transaction tx, String name) {
StatementResult result = tx.run(
"MATCH (a:Person {name: $name}) RETURN id(a)",
parameters("name", name));
return result.single().get(0).asLong();
}
13.5 查询结果保留
默认情况下,查询结果在该事务关闭或者会话执行另外的查询时失效,如果需要保留的话需要显示的声明保存查询结果,驱动提供了多个方法将查询的流转换为对应语言下的标准的数据结构。
//通过list方法将查询结果保留
private List<Record> matchPersonNodes2(Transaction tx) {
return tx.run("MATCH (a:Person) RETURN a.name AS name").list();
}
14. 示例demo(spring data neo4j)
通过spring data neo4j提供的注解POJO和SD仓储对象以及neo4j模板对象,我们可以在高层次上使用操作对象的方式访问应用neo4j中的数据,其提供了ORM的封装,极大的简化了对图数据的应用;同时通过interface中的注解@Query又提供了灵活性,可以通过其编写neo4j中支持的各种cypher语句。
SDN底层依赖于neo4j-ogm包,它解决图数据库的ORM的问题。我们在实际应用开发的过程中可以根据实际情况直接选择SDN还是OGM。
使用SDN有2个核心的组件,通过继承的方式实现操作数据的Repository接口,在该接口中定义相关的业务接口,并且通过@Query注解描述相关语句;通过注解方式描述数据库中的node和relationship对象。
The Repository
instances are only created through Spring and can be auto-wired into your Spring beans as required.
Repository接口对象代码中如下:
public interface MovieRepository extends PagingAndSortingRepository<Movie, Long> {
Movie findByTitle(@Param("title") String title);
Collection<Movie> findByTitleContaining(String title);
@Query("MATCH (m:Movie)<-[r:ACTED_IN]-(a:Person) RETURN m,r,a LIMIT {limit}")
Collection<Movie> graph(@Param("limit") int limit);
}
注意代码中参数传递的方式,在注解中通过{paramName}将调用者参数绑定,方法上使用@Param注解。
持久化对象注解描述如下:
@RelationshipEntity(type = "ACTED_IN")
public class Role {
@GraphId
private Long id;
private Collection<String> roles = new ArrayList<>();
@StartNode
private Person person;
@EndNode
private Movie movie;
以上是对关系对象的注解;
@NodeEntity
public class Person {
@GraphId
private Long id;
private String name;
private int born;
@Relationship(type = "ACTED_IN")
private List<Movie> movies = new ArrayList<>();
以上代码是对节点对象的注解。