Neo4j 笔记
Neo4j使用笔记
(1) Neo4j介绍
Neo4j是一种NoSQL数据库,原理是数学里的图论。
常见的SQL数据库有MySQL Oracle等
常见的NoSQL数据库有Redis ES Mongdb Neo4j等
近几年比较流行的的图数据库有Neo4j Titan OrientDB Sparksee Virtuso ArangoDb Airaph GraphDB GraphBase等
Neo4j数据库比较适合处理关系,比如人和人之间的社交关系。
比较成功的应用有 领英 FaceBook Twitter
2. Neo4j下载、安装、配置
Neo4j是开源免费的图数据库,社区版代码开源,企业版代码除集群相关的代码,其余代码全部开源
还有一点,社区版免费,企业版收费。
社区版最多允许 2^35
个节点,2^35
个关系,2^36
个属性
2.1 下载
Neo4j所有版本的下载地址
linux unix 推荐使用 .tar.gz包,windows推荐使用.zip包
这样做的好处就是解压完就可以使用,对目录结构、配置等比较了解
windows上使用.exe安装的用户经常找不见配置,load csv以及其他操作时经常找不见目录
https://dist.neo4j.org/neo4j-community-4.4.26-unix.tar.gz
https://dist.neo4j.org/neo4j-community-3.5.34-unix.tar.gz
https://dist.neo4j.org/neo4j-community-3.1.2-unix.tar.gz
https://neo4j.com/artifact.php?name=neo4j-community-3.1.2-unix.tar.gz
2.2 安装使用
2.2.1 linux下安装使用
- tar -zxvf neo4j-community-3.1.2.tar.gz
- 进入bin目录,使用
neo4j console
启动Neo4j数据库,如果想让Neo4j后台运行,使用neo4j start
启动 - 在浏览器里输入http://localhost:7474来访问数据库,默认用户名、密码: neo4j/neo4j
- 如果想自定义配置,可以在${NEO4J_HOME}/conf/neo4j.conf修改对应配置
linux用户注意:
使用超级用户修改 /etc/security/limits.conf
文件,允许当前用户(neo4j)打开40000个文件
neo4j soft nofile 40000
neo4j hard nofile 40000
修改 /etc/pam.d/su
文件
session required pam_limits.so
设置neo4j开机启动
vim /etc/rc.d/rc.local
在文件最后添加如下命令:/usr/share/neo4j/bin/neo4j start
其中 /usr/share/neo4j/bin/
是Neo4j的安装路径
2.2.2 windows下安装使用
- 下载的压缩包neo4j-community-3.1.2.zip,解压完就可以用。
- 解压完进入bin目录,输入
neo4j console
就可以看到neo4j数据库启动了 - 在浏览器里输入http://localhost:7474来访问数据库,默认用户名、密码: neo4j/neo4j
- 如果想自定义配置,可以在${NEO4J_HOME}/conf/neo4j.conf修改对应配置
2.3 配置
常用配置
#设置可以通过ip当问Neo4j数据库
dbms.connectors.default_listen_address=0.0.0.0
#历史版本请修改
dbms.connector.http.address=0.0.0.0:7474
org.neo4j.server.webserver.address=0.0.0.0
neo4j数据库设置初始密码
bin/neo4j-admin set-initial-password yourpassword
3. Neo4j使用
Neo4j里非常重要的一些思想,一个节点、一条边就是一个对象
节点可以有多个Label、边只能有一个RelationShip
Neo4j是no schema的数据库,导入数据前不需要定义结构
不要用关系型数据库的思维来对待Neo4j
A row is a node
A table name is a label name
Properties
Both nodes and relationships can have properties.
Properties are named values where the name is a string. The supported property values are:
• Numeric values,
• String values,
• Boolean values,
• Collections of any other type of value.
Labels have an id space of an int, meaning the maximum number of labels the database can contain is roughly 2 billion.
Paths
A path is one or more nodes with connecting relationships, typically retrieved as a query or traversal result
Neo4j is a schema-optional graph database
You can use Neo4j without any schema. Optionally you can introduce it in order to gain performance or modeling benefits. This allows a way of working where the schema does not get in your way until you are at a stage where you want to reap the benefits of having one.
Indexs
Performance is gained by creating indexes, which improve the speed of looking up nodes in the database.
Neo4j启动后动态修改配置
//
CALL dbms.setConfigValue('dbms.logs.query.enabled', 'true')
dbms.checkpoint.iops.limit Limit the number of IOs the background checkpoint process will consume per second.
dbms.logs.query.enabled Log executed queries that take longer than the configured threshold, dbms.logs.query.threshold.
dbms.logs.query.rotation.keep_number Maximum number of history files for the query log.
dbms.logs.query.rotation.size The file size in bytes at which the query log will auto-rotate.
dbms.logs.query.threshold If the execution of query takes more time than this threshold, the query is logged - provided query logging is enabled.
dbms.transaction.timeout The maximum time interval of a transaction within which it should be completed.
Cypher
:help 帮助页面
:schema 查看数据库结构
:schema ls -l :Person
:server change-password // 修改密码
CALL dbms.changePassword("newpassword") // (旧版本)修改密码
:server connect 连接
:play sysinfo 查看系统信息
// List node labels 查询所有的label
CALL db.labels()
// List relationship types 查询所有的type
CALL db.relationshipTypes()
// What is related, and how 查询数据里的节点和关系 类似于 SQL的desc
CALL db.schema()
// List functions
CALL dbms.functions()
// List procedures
CALL dbms.procedures()
CALL dbms.listQueries() ;
CALL dbms.killQuery(queryId);
// delete single node
// 删除id=1的节点
match (n:DictEntity) where id(n) = 1 delete n;
// delete a node and connected relationships
// 删除节点和关系
match (n:DictEntity {name: 'zhangsan'})-[r]-() delete r,n
// delete all nodes and relationships
// 删除所有节点和关系
match (n) OPTIONAL match (n)-[r]-() delete n,r
// delete all nodes and relationships
// 删除所有节点和关系
// 容易内存溢出
match (n) detach delete n;
match (n)-[r]-() where n.name = '词典1' delete r 删除关系
match (n:DictEntity) where n.name="词典1" delete n 删除节点
match (n:DictEntity {name:"词典1"}) delete n
// Count all nodes
// 查询一共有多少节点
match (n) RETURN count(n)
// Count all relationships
// 查询一共有多少关系 // 不带方向的话结果是2倍
match ()-->() RETURN count(*);
match ()-[r]->() return count(r);
// What kind of nodes exist
// Sample some nodes, reporting on property and relationship counts per node.
match (n) where rand() <= 0.1
RETURN
DISTINCT labels(n),
count(*) AS SampleSize,
avg(size(keys(n))) as Avg_PropertyCount,
min(size(keys(n))) as Min_PropertyCount,
max(size(keys(n))) as Max_PropertyCount,
avg(size( (n)-[]-() ) ) as Avg_RelationshipCount,
min(size( (n)-[]-() ) ) as Min_RelationshipCount,
max(size( (n)-[]-() ) ) as Max_RelationshipCount
// What is related, and how
// Sample the graph, reporting the patterns of connected labels,
// with min, max, avg degrees and associated node and relationship properties.
match (n) where rand() <= 0.1
match (n)-[r]->(m)
WITH n, type(r) as via, m
RETURN labels(n) as from,
reduce(keys = [], keys_n in collect(keys(n)) | keys + filter(k in keys_n where NOT k IN keys)) as props_from,
via,
labels(m) as to,
reduce(keys = [], keys_m in collect(keys(m)) | keys + filter(k in keys_m where NOT k IN keys)) as props_to,
count(*) as freq
// 在用户结点的用户名属性上创建索引 (除了结点名和字段名,cypther不区分大小写)
create index on :Person(name);
// 删除索引
drop index on :Person(name);
create constraint on (p:Person) assert p.name is unique; //
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE; // 在Book对象isbn属性上创建唯一性约束
// 删除Person类别上的name属性 索引
drop constraint on (p:Person) assert p.name is unique;
// 删除isbn属性上的唯一性约束
DROP CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE
//
DROP CONSTRAINT ON (book:Book) ASSERT exists(book.isbn)
PROFILE 在查询前加上prifile可以查看数据库查询的详细流程
match (a:Person), (b:Person) where a.name = 'zhangsan' and b.name = 'lisi'
merge (a)-[r:RELTYPE]->(b) return r
// 模糊匹配
match (n:Person) where n.name =~ '张.*' return n
// 包含
match (n:Person) where n.name contains '张' return n;
// 去重
match (n:Person) with n.name as name return distinct name;
// Count all nodes
// 查询一共有多少节点
match (n) RETURN count(n)
// Count all relationships
// 查询一共有多少关系
match ()-->() RETURN count(*);
// Get some data 随便查一些数据
match (n1)-[r]->(n2) RETURN r, n1, n2 LIMIT 25
// 查询一共有多少种节点
call db.labels();
match (n) return distinct label(n);
// 查询一共有多少关系
call db.relationshipTypes()
// 查询数据库里的所有属性
match (n) unwind keys(n) as allkeys return distinct allkeys;
// 查询关系最多的节点
// 实际使用时,最好对n加个范围,要不然 全图扫描
// 使用with 和 别名,能减少一次count(*)的查询
match (n:Movie)--() with n.title as title, count(*) as count return title, count order by count desc limit 1;
match (n:Movie)-[r]-() with n.tile as title, count(r) as count return title, count order by count desc limit 1;
// 查询孤立节点
match (n) where not (n)--() return id(n);
// 查询有3条关系的节点
match (n:Test)-->(m) with count(*) as count, n as result where count =3 return result limit 1;
// 查询有3度关系的节点
match (n:Test)-[r:RelationShip*3]->(m) return n limit 1;
// 查询有1到3度关系的节点
match (n:Test)-[r:RelationShip*1..3]->(m) return n limit 10;
match (p:Person) where id(p) > 184 set p.number=p.序号, p.name=p.姓名, p.class = p.班级, p.sex = p.性别 remove p.序号,p.姓名,p.班级,p.性别 return p;
// Person对象有个sex属性,因为业务需要想改成gender属性
match (p:Person {name:'张三'}) set p.gender = p.sex remove p.sex return p
// 关系r的名字叫IsFriend,因为业务需要改成汉语的名字
match (a)-[r:IsFrend]->(b) create (a)-[r2:朋友]->(b) set r2.id = r.id delete r
match (p1:Person)-[r:isFrend*1..6 {friend:1}]->(p2:Person) return p1,r,p2
match (a:A)-[r1:AB]-(b:B)-[r2:BC]-(c:C) where not (a)-[:AC]-(c) return a,r1,b,r2,c
match (n:Person {name:'lisi'}) with n skip 1 delete n ;
(a:Person {name:'a'})-[r:RelationShip {date:'2017-06-22 12:00:00'}]->(c:Person {name:'c'})<-[r2:RelationShip {date:'2017-06-22 12:30:00'}]-(b:Person {name:'b'})
(d:Person {name:'d'})-[r:RelationShip {date:'2017-06-22 12:00:00'}]->(e:Person {name:'e'})
想删除a, d, e
// 创建节点
merge (a:Person {name:'a'})-[r:RelationShip {date:'2017-06-22 12:00:00'}]->(c:Person {name:'c'})<-[r2:RelationShip {date:'2017-06-22 12:30:00'}]-(b:Person {name:'b'}) return r,r2;
merge (d:Person {name:'d'})-[r:RelationShip {date:'2017-06-22 12:00:00'}]->(e:Person {name:'e'}) return r
// 分三次执行
match (n:Person)-[r]->(m:Person) where (r.date >='2017-06-22 11:00:00' and r.date<='2017-06-22 12:29:59') set n.flag = '1' , m.flag = '1' delete r ;
match (n:Person)-[r]-(m:Person) with count(r) as count , n where count > 0 set n.flag = '0' return count,n;
match (n:Person) where n.flag = '1' delete n;
As the indexes are created after the nodes are inserted, their population happens asynchronously, so we use schema await (a shell command) to block until they are populated.
schema await
[r:Person*3..4]
neo4j-sh (?)$ CALL dbms.procedures();
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| name | signature | description |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| "db.awaitIndex" | "db.awaitIndex(index :: STRING?, timeOutSeconds = 300 :: INTEGER?) :: VOID" | "Wait for an index to come online (for example: CALL db.awaitIndex(":Person(name)"))." |
| "db.awaitIndexes" | "db.awaitIndexes(timeOutSeconds = 300 :: INTEGER?) :: VOID" | "Wait for all indexes to come online (for example: CALL db.awaitIndexes("500"))." |
| "db.constraints" | "db.constraints() :: (description :: STRING?)" | "List all constraints in the database." |
| "db.createLabel" | "db.createLabel(newLabel :: STRING?) :: VOID" | "Create a label" |
| "db.createProperty" | "db.createProperty(newProperty :: STRING?) :: VOID" | "Create a Property" |
| "db.createRelationshipType" | "db.createRelationshipType(newRelationshipType :: STRING?) :: VOID" | "Create a RelationshipType" |
| "db.index.explicit.addNode" | "db.index.explicit.addNode(indexName :: STRING?, node :: NODE?, key :: STRING?, value :: ANY?) :: (success :: BOOLEAN?)" | "Add a node to an explicit index based on a specified key and value" |
| "db.index.explicit.addRelationship" | "db.index.explicit.addRelationship(indexName :: STRING?, relationship :: RELATIONSHIP?, key :: STRING?, value :: ANY?) :: (success :: BOOLEAN?)" | "Add a relationship to an explicit index based on a specified key and value" |
| "db.index.explicit.auto.searchNodes" | "db.index.explicit.auto.searchNodes(query :: ANY?) :: (node :: NODE?, weight :: FLOAT?)" | "Search nodes in explicit automatic index. Replaces `START n=node:node_auto_index('key:foo*')`" |
| "db.index.explicit.auto.searchRelationships" | "db.index.explicit.auto.searchRelationships(query :: ANY?) :: (relationship :: RELATIONSHIP?, weight :: FLOAT?)" | "Search relationship in explicit automatic index. Replaces `START r=relationship:relationship_auto_index('key:foo*')`" |
| "db.index.explicit.auto.seekNodes" | "db.index.explicit.auto.seekNodes(key :: STRING?, value :: ANY?) :: (node :: NODE?)" | "Get node from explicit automatic index. Replaces `START n=node:node_auto_index(key = 'A')`" |
| "db.index.explicit.auto.seekRelationships" | "db.index.explicit.auto.seekRelationships(key :: STRING?, value :: ANY?) :: (relationship :: RELATIONSHIP?)" | "Get relationship from explicit automatic index. Replaces `START r=relationship:relationship_auto_index(key = 'A')`" |
| "db.index.explicit.drop" | "db.index.explicit.drop(indexName :: STRING?) :: (type :: STRING?, name :: STRING?, config :: MAP?)" | "Remove an explicit index - YIELD type,name,config" |
| "db.index.explicit.existsForNodes" | "db.index.explicit.existsForNodes(indexName :: STRING?) :: (success :: BOOLEAN?)" | "Check if a node explicit index exists" |
| "db.index.explicit.existsForRelationships" | "db.index.explicit.existsForRelationships(indexName :: STRING?) :: (success :: BOOLEAN?)" | "Check if a relationship explicit index exists" |
| "db.index.explicit.forNodes" | "db.index.explicit.forNodes(indexName :: STRING?) :: (type :: STRING?, name :: STRING?, config :: MAP?)" | "Get or create a node explicit index - YIELD type,name,config" |
| "db.index.explicit.forRelationships" | "db.index.explicit.forRelationships(indexName :: STRING?) :: (type :: STRING?, name :: STRING?, config :: MAP?)" | "Get or create a relationship explicit index - YIELD type,name,config" |
| "db.index.explicit.list" | "db.index.explicit.list() :: (type :: STRING?, name :: STRING?, config :: MAP?)" | "List all explicit indexes - YIELD type,name,config" |
| "db.index.explicit.removeNode" | "db.index.explicit.removeNode(indexName :: STRING?, node :: NODE?, key :: STRING?) :: (success :: BOOLEAN?)" | "Remove a node from an explicit index with an optional key" |
| "db.index.explicit.removeRelationship" | "db.index.explicit.removeRelationship(indexName :: STRING?, relationship :: RELATIONSHIP?, key :: STRING?) :: (success :: BOOLEAN?)" | "Remove a relationship from an explicit index with an optional key" |
| "db.index.explicit.searchNodes" | "db.index.explicit.searchNodes(indexName :: STRING?, query :: ANY?) :: (node :: NODE?, weight :: FLOAT?)" | "Search nodes in explicit index. Replaces `START n=node:nodes('key:foo*')`" |
| "db.index.explicit.searchRelationships" | "db.index.explicit.searchRelationships(indexName :: STRING?, query :: ANY?) :: (relationship :: RELATIONSHIP?, weight :: FLOAT?)" | "Search relationship in explicit index. Replaces `START r=relationship:relIndex('key:foo*')`" |
| "db.index.explicit.searchRelationshipsBetween" | "db.index.explicit.searchRelationshipsBetween(indexName :: STRING?, in :: NODE?, out :: NODE?, query :: ANY?) :: (relationship :: RELATIONSHIP?, weight :: FLOAT?)" | "Search relationship in explicit index, starting at the node 'in' and ending at 'out'." |
| "db.index.explicit.searchRelationshipsIn" | "db.index.explicit.searchRelationshipsIn(indexName :: STRING?, in :: NODE?, query :: ANY?) :: (relationship :: RELATIONSHIP?, weight :: FLOAT?)" | "Search relationship in explicit index, starting at the node 'in'." |
| "db.index.explicit.searchRelationshipsOut" | "db.index.explicit.searchRelationshipsOut(indexName :: STRING?, out :: NODE?, query :: ANY?) :: (relationship :: RELATIONSHIP?, weight :: FLOAT?)" | "Search relationship in explicit index, ending at the node 'out'." |
| "db.index.explicit.seekNodes" | "db.index.explicit.seekNodes(indexName :: STRING?, key :: STRING?, value :: ANY?) :: (node :: NODE?)" | "Get node from explicit index. Replaces `START n=node:nodes(key = 'A')`" |
| "db.index.explicit.seekRelationships" | "db.index.explicit.seekRelationships(indexName :: STRING?, key :: STRING?, value :: ANY?) :: (relationship :: RELATIONSHIP?)" | "Get relationship from explicit index. Replaces `START r=relationship:relIndex(key = 'A')`" |
| "db.indexes" | "db.indexes() :: (description :: STRING?, label :: STRING?, properties :: LIST? OF STRING?, state :: STRING?, type :: STRING?, provider :: MAP?)" | "List all indexes in the database." |
| "db.labels" | "db.labels() :: (label :: STRING?)" | "List all labels in the database." |
| "db.propertyKeys" | "db.propertyKeys() :: (propertyKey :: STRING?)" | "List all property keys in the database." |
| "db.relationshipTypes" | "db.relationshipTypes() :: (relationshipType :: STRING?)" | "List all relationship types in the database." |
| "db.resampleIndex" | "db.resampleIndex(index :: STRING?) :: VOID" | "Schedule resampling of an index (for example: CALL db.resampleIndex(":Person(name)"))." |
| "db.resampleOutdatedIndexes" | "db.resampleOutdatedIndexes() :: VOID" | "Schedule resampling of all outdated indexes." |
| "db.schema" | "db.schema() :: (nodes :: LIST? OF NODE?, relationships :: LIST? OF RELATIONSHIP?)" | "Show the schema of the data." |
| "dbms.changePassword" | "dbms.changePassword(password :: STRING?) :: VOID" | "Change the current user's password. Deprecated by dbms.security.changePassword." |
| "dbms.components" | "dbms.components() :: (name :: STRING?, versions :: LIST? OF STRING?, edition :: STRING?)" | "List DBMS components and their versions." |
| "dbms.functions" | "dbms.functions() :: (name :: STRING?, signature :: STRING?, description :: STRING?)" | "List all user functions in the DBMS." |
| "dbms.listConfig" | "dbms.listConfig(searchString = :: STRING?) :: (name :: STRING?, description :: STRING?, value :: STRING?)" | "List the currently active config of Neo4j." |
| "dbms.procedures" | "dbms.procedures() :: (name :: STRING?, signature :: STRING?, description :: STRING?)" | "List all procedures in the DBMS." |
| "dbms.queryJmx" | "dbms.queryJmx(query :: STRING?) :: (name :: STRING?, description :: STRING?, attributes :: MAP?)" | "Query JMX management data by domain and name. For instance, "org.neo4j:*"" |
| "dbms.security.changePassword" | "dbms.security.changePassword(password :: STRING?) :: VOID" | "Change the current user's password." |
| "dbms.security.createUser" | "dbms.security.createUser(username :: STRING?, password :: STRING?, requirePasswordChange = true :: BOOLEAN?) :: VOID" | "Create a new user." |
| "dbms.security.deleteUser" | "dbms.security.deleteUser(username :: STRING?) :: VOID" | "Delete the specified user." |
| "dbms.security.listUsers" | "dbms.security.listUsers() :: (username :: STRING?, flags :: LIST? OF STRING?)" | "List all local users." |
| "dbms.security.showCurrentUser" | "dbms.security.showCurrentUser() :: (username :: STRING?, flags :: LIST? OF STRING?)" | "Show the current user. Deprecated by dbms.showCurrentUser." |
| "dbms.showCurrentUser" | "dbms.showCurrentUser() :: (username :: STRING?, flags :: LIST? OF STRING?)" | "Show the current user." |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
46 rows
96 ms
neo4j-sh (?)$
github例子
https://github.com/neo4j-examples/movies-java-spring-data-neo4j-4
批量执行cpyther语句
要创建上百个索引,想找一个简单的办法
./neo4j-shell -c < /data/stale/data01/neo4j/create_index.cypther
热启动命令1
MATCH (n)
OPTIONAL MATCH (n)-[r]->()
RETURN count(n.prop) + count(r.prop);
1.1亿节点
neo4j-sh (?)$ match (n) optional match (n)-[r]->() return count(n.prop), count(r.prop);
+-------------------------------+
| count(n.prop) + count(r.prop) |
+-------------------------------+
| 0 |
+-------------------------------+
1 row
556974 ms
neo4j-sh (?)$ match (n) optional match (n)-[r]->() return count(n)+count(r);
+-------------------+
| count(n)+count(r) |
+-------------------+
| 262701611 |
+-------------------+
1 row
172145 ms
neo4j-sh (?)$ match (n) optional match (n)-[r]->() return count(n.uuid), count(r);
+---------------------------+
| count(n.uuid) | count(r) |
+---------------------------+
| 1233398 | 111001002 |
+---------------------------+
1 row
260481 ms
热启动命令2
CALL apoc.warmup.run();
neo4j-sh (?)$ CALL apoc.warmup.run();
+--------------------------------------------------------------------------------------------------------------------------+
| pageSize | nodesPerPage | nodesTotal | nodePages | nodesTime | relsPerPage | relsTotal | relPages | relsTime | totalTime |
+--------------------------------------------------------------------------------------------------------------------------+
| 8192 | 546 | 110000000 | 201466 | 0 | 240 | 110000000 | 458334 | 0 | 1 |
+--------------------------------------------------------------------------------------------------------------------------+
1 row
1416 ms
社区版和企业版有什么区别。其实他们在功能上没有本质区别。主要区别在如下几点:
1、容量:社区版最多支持 320 亿个节点、320 亿个关系和 640 亿个属性,而企业版没有这个限制;
2、并发:社区版只能部署成单实例,不能做集群。而企业版可以部署成高可用集群或因果集群,从而可以解决高并发量的问题;
3、容灾:由于企业版支持集群,部分实例出故障不会影响整个系统正常运行;
4、热备:社区版只支持冷备份,即需要停止服务后才能进行备份,而企业版支持热备,第一次是全量备份,后续是增量备份;
5、性能:社区版最多用到 4 个内核,而企业能用到全部内核,且对性能做了精心的优化;
6、支持:企业版客户能得到 5X10 电话支持(Neo4j 美国电话、邮件,微云数聚电话、微信、邮件);
References
[1] http://neo4j.com/docs/operations-manual/3.1/
[2] https://neo4j.com/docs/developer-manual/3.1/
[3] http://neo4j.com/docs/2.2.9/query-delete.html
[4] https://neo4j.com/docs/developer-manual/3.1/cypher/
[5] https://neo4j.com/blog/neo4j-3-1-ga-release/?ref=home
[6] https://neo4j.com/docs/developer-manual/3.1/cypher/clauses/set/
[7] https://neo4j.com/docs/operations-manual/3.2/installation/linux/debian/#multiple-java-versions
[8] https://neo4j.com/docs/operations-manual/current/installation/windows/
[9] http://neo4j.com/docs/developer-manual/current/extending-neo4j/procedures/
[10] https://neo4j.com/developer/guide-importing-data-and-etl/ 使用ETL方式导入Neo4j
[11] https://neo4j.com/developer/guide-import-csv/ 使用csv文件方式导入Neo4j
[12] https://neo4j.com/docs/
[13] https://neo4j.com/blog/neo4j-3-0-massive-scale-developer-productivity/#capabilities-data-size neo4j支持节点个数
[14] https://neo4j.com/developer/kb/warm-the-cache-to-improve-performance-from-cold-start/
https://stackoverflow.com/questions/41762487/neo4j-bulk-import-and-indexing
https://neo4j.com/blog/batchinsert-auto-indexing-and-friend-recommendation-with-neo4j/
http://grokbase.com/t/gg/neo4j/146xv2wa77/how-i-can-create-index-schema-legacy-after-importing-data-by-batch-inserter-from-neo4j-shell
https://stackoverflow.com/questions/44996896/how-to-execute-cypher-file-using-neo4j-3-1-4-not-through-zip-file
https://github.com/neo4j/cypher-shell/issues/96
https://stackoverflow.com/questions/15161221/neo4j-script-file-format-is-there-any