如何批量插入关系

时间:2014-07-21 22:09:15

标签: neo4j cypher

我正在玩Neo4j。我有一个包含大约400,000个节点的数据库。我想从CSV文件中插入关系。有大约140万个关系。

我目前正在使用REST API。 REST请求看起来像这样的例子:

POST http://localhost:7474/db/data/cypher
Accept: application/json; charset=UTF-8
Content-Type: application/json
{"query": "MATCH (a { ConceptId: '280844000' }), (b { ConceptId: '71737002' }) CREATE (a)-[:Is_a]->(b) RETURN a"}

问题是每个请求都需要几秒钟。对于我希望插入的关系数量来说,这太慢了。

我无法访问底层节点ID,只能访问插入它们时给出的属性。

有更快的方法吗?

注意:我目前没有使用索引(我还没有弄清楚如何添加它们),但明天会再次使用索引。我只是想知道是否有某种方式以批量方式插入关系。

2 个答案:

答案 0 :(得分:8)

第一个改进可能是为节点分配标签,以便您可以使用索引。如果没有conceptId上的索引,则每次执行查询时,它将扫描400,000个节点两次,对于您匹配的两个节点中的每个节点扫描一次。根据您的查询进行推测,您可以为您的节点提供标签:Concept并将conceptId属性编入索引,如下所示

MATCH (n)
// WHERE HAS (n.conceptId) //if you have some nodes that don't represent concepts, and conceptId distinguishes the ones that do from others
SET n:Concept

然后是索引

CREATE INDEX ON :Concept(conceptId)

或如果conceptId是唯一标识值,则可以使用约束

CREATE CONSTRAINT ON (c:Concept) ASSERT c.conceptId IS UNIQUE

设置标签并创建索引后,您可以使用它们快速查找要连接的节点。您需要做的就是在查询中包含label和indexed属性。您已经使用了索引属性,因此添加查询的标签

MATCH (a:Concept {ConceptId: '280844000'}), (b:Concept {ConceptId: '71737002'}) 
CREATE (a)-[:Is_a]->(b) 
RETURN a

您可以阅读有关架构in the Neo4j documentation的更多信息。

第二项改进可能是使用LOAD CSV,正如@stephenmuss建议的那样。

如果您将来的查询不是基于csv文件,还有两件事需要考虑。第一个是参数化您的查询。您的HTTP电话会看起来像这样

POST http://localhost:7474/db/data/cypher
Accept: application/json; charset=UTF-8
Content-Type: application/json
{"query": "MATCH (a { ConceptId: {a} }), (b { ConceptId: {b} }) CREATE (a)-[:Is_a]->(b) RETURN a","params":{"a":"280844000","b":"71737002"}}

这允许执行引擎为该结构的第一个查询创建一次执行计划。下次发出具有相同结构的查询时,将重用缓存的执行计划。这将显着提高具有相同结构的重复查询的性能。

最后一件事就是@ulkas评论,批量插入。 LOAD CSV更快的一个原因是它在一个事务中执行多个操作。您可以使用事务性密码端点执行类似操作。然后,您可以为每个事务执行几千个小语句,这对于在数据库上操作的性能要高得多,并且还将减少线路上的开销。为事务端点设计有效负载以及处理异常稍微复杂一些。下面是一个简单示例,您可以在Neo4j manual pages

中详细了解它
POST http://localhost:7474/db/data/transaction
Accept: application/json; charset=UTF-8
Content-Type: application/json
{"statements":[
    {"statement":"MATCH (a:Concept {ConceptId: {a}}), (b:Concept {ConceptId: {b}}) CREATE (a)-[:Is_a]->(b) RETURN a","parameters":{"a":"280844000","b":"71737002"}},
    {"statement":"MATCH (a:Concept {ConceptId: {a}}), (b:Concept {ConceptId: {b}}) CREATE (a)-[:Is_a]->(b) RETURN a","parameters":{"a":"199401294","b":"51233509"}}
]}

服务器返回新事务的location,例如"http://localhost:7474/db/data/transaction/1"。您可以继续在同一事务中执行语句

POST http://localhost:7474/db/data/transaction/1
Accept: application/json; charset=UTF-8
Content-Type: application/json
{"statements":[...]}

当你完成后,你承诺。提交调用也可以包含语句。

POST http://localhost:7474/db/data/transaction/1/commit
Accept: application/json; charset=UTF-8
Content-Type: application/json
{"statements":[...]}

答案 1 :(得分:3)

如果您使用的是Neo4j 2.1+,我认为您最好的选择是使用LOAD CSV

然后您可以使用如下语法

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:/path/to/file.csv" AS csvLine
MATCH (a{ConceptId: csvLine.aId}), (b{ConceptId: csvLine.bId})
CREATE (a)-[:Is_a]->(b)

我建议您查看docs for importing csv files