如何优化Neo4J Cypher查询?

时间:2018-03-02 09:47:34

标签: neo4j cypher query-optimization

我有一个将文本转换为网络的应用程序,因此当添加一个句子时,每个单词都是一个节点,每个单词的共同出现就是它们之间的连接。此信息对于更好地理解以下问题非常重要。

为了将每个句子添加到Neo4J数据库中,我在Neo4J中有以下Cypher查询,根据我的数据结构,它首先匹配添加节点的user,然后匹配制作语句的context(或列表),将其链接到用户,将语句链接到用户和上下文,然后在添加的每个节点(带属性),语句之间创建连接,其中他们被制作了以及制作它们的背景(列表)。

问题是此查询比句子本身长约100,因此如果文本是400Bytes,则查询大约为40K。当我想添加一个长文本时,Neo4J开始变得很慢。

因此 - 我的问题:如何以最佳方式优化此查询?你建议做一组交易吗?

例如,我可以将每个长查询分成多个部分,然后同时发送一些事务以节省时间吗?

我正在谈论一个大约100K长,可能更长的文本。这意味着总请求大约为10Mb。

MATCH (u:User {uid: "6e228580-1cb3-11e8-8271-891867c15336"}) 
MERGE (c_list:Context {name:"list",by:"6e228580-1cb3-11e8-8271-891867c15336",
uid:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47"}) 
ON CREATE SET c_list.timestamp="15199833288930000" 
MERGE (c_list)-[:BY{timestamp:"15199833288930000"}]->(u) 
CREATE (s:Statement {name:"#apple #orange #fruit", 
text:"apples and oranges are fruits", 
uid:"0b56a800-1dfd-11e8-802e-b5cbdf950c47", timestamp:"15199833288930000"}) 
CREATE (s)-[:BY {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",
timestamp:"15199833288930000"}]->(u) 
CREATE (s)-[:IN {user:"6e228580-1cb3-11e8-8271-891867c15336",
timestamp:"15199833288930000"}]->(c_list) 
MERGE (cc_apple:Concept {name:"apple"}) 
ON CREATE SET cc_apple.timestamp="15199833288930000", cc_apple.uid="0b56a801-1dfd-11e8-802e-b5cbdf950c47" 
MERGE (cc_orange:Concept {name:"orange"}) 
ON CREATE SET cc_orange.timestamp="15199833288930000", cc_orange.uid="0b56cf10-1dfd-11e8-802e-b5cbdf950c47" 
MERGE (cc_fruit:Concept {name:"fruit"}) 
ON CREATE SET cc_fruit.timestamp="15199833288930002", cc_fruit.uid="0b56cf13-1dfd-11e8-802e-b5cbdf950c47" 
CREATE (cc_apple)-[:BY {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",timestamp:"15199833288930000",
statement:"0b56a800-1dfd-11e8-802e-b5cbdf950c47"}]->(u) 
CREATE (cc_apple)-[:OF {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",user:"6e228580-1cb3-11e8-8271-891867c15336",timestamp:"15199833288930000"}]->(s)  
CREATE (cc_apple)-[:AT {user:"6e228580-1cb3-11e8-8271-891867c15336",timestamp:"15199833288930000",
context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",statement:"0b56a800-1dfd-11e8-802e-b5cbdf950c47"}]->(c_list) 
CREATE (cc_apple)-[:TO {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",
statement:"0b56a800-1dfd-11e8-802e-b5cbdf950c47",user:"6e228580-1cb3-11e8-8271-891867c15336",
timestamp:"15199833288930000",uid:"0b56cf11-1dfd-11e8-802e-b5cbdf950c47",gapscan:"2",weight:"3"}]->(cc_orange) 
CREATE (cc_orange)-[:BY {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",timestamp:"15199833288930000",statement:"0b56a800-1dfd-11e8-802e-b5cbdf950c47"}]->(u) 
CREATE (cc_orange)-[:OF {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",user:"6e228580-1cb3-11e8-8271-891867c15336",timestamp:"15199833288930000"}]->(s) 
CREATE (cc_orange)-[:AT {user:"6e228580-1cb3-11e8-8271-891867c15336",timestamp:"15199833288930000",
context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",statement:"0b56a800-1dfd-11e8-802e-b5cbdf950c47"}]->(c_list) 
CREATE (cc_orange)-[:TO {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",
statement:"0b56a800-1dfd-11e8-802e-b5cbdf950c47",user:"6e228580-1cb3-11e8-8271-891867c15336",
timestamp:"15199833288930002",uid:"0b56cf14-1dfd-11e8-802e-b5cbdf950c47",gapscan:"2",weight:"3"}]->(cc_fruit) 
CREATE (cc_apple)-[:TO {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",
statement:"0b56a800-1dfd-11e8-802e-b5cbdf950c47",user:"6e228580-1cb3-11e8-8271-891867c15336",
timestamp:"15199833288930002",uid:"0b56cf16-1dfd-11e8-802e-b5cbdf950c47",gapscan:"4",weight:"2"}]->(cc_fruit) 
CREATE (cc_fruit)-[:BY {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",
timestamp:"15199833288930002",statement:"0b56a800-1dfd-11e8-802e-b5cbdf950c47"}]->(u) 
CREATE (cc_fruit)-[:OF {context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",user:"6e228580-1cb3-11e8-8271-891867c15336",timestamp:"15199833288930002"}]->(s) 
CREATE (cc_fruit)-[:AT {user:"6e228580-1cb3-11e8-8271-891867c15336",
timestamp:"15199833288930002",context:"0b4fa320-1dfd-11e8-802e-b5cbdf950c47",
statement:"0b56a800-1dfd-11e8-802e-b5cbdf950c47"}]->(c_list)  
RETURN s.uid;

1 个答案:

答案 0 :(得分:1)

1)使用输入parameters

var params = {
    userId: "6e228580-1cb3-11e8-8271-891867c15336",
    contextName: "list",
    time: "15199833288930000",
    statementName: "#apple #orange #fruit",
    statementText: "apples and oranges are fruits",
    concepts: ["apple", "orange", "fruit"],
    conceptsRelations: [
        {from: "apple",  to: "orange", gapscan: 2, weight: 3},
        {from: "orange", to: "fruit",  gapscan: 2, weight: 3},
        {from: "apple",  to: "fruit",  gapscan: 4, weight: 2}
    ]
}
session.run(cypherQuery, params).then...

2)使用APOC library在数据库端生成唯一标识符:apoc.create.uuid()

3)使用循环(foreach和unwind)进行重复操作:

MATCH (u:User {uid: $userId})
MERGE (c_list:Context {name: $contextName, by: $userId})
    ON CREATE SET c_list.timestamp = $time,
                  c_list.uid = apoc.create.uuid()
MERGE (c_list)-[:BY{timestamp: $time}]->(u)

CREATE (s:Statement {name: $statementName, 
                     text: $statementText, uid:apoc.create.uuid(), timestamp: $time})
CREATE (s)-[:BY {context: c_list.uid, timestamp: $time}]->(u)
CREATE (s)-[:IN {user: u.uid, timestamp: $time}]->(c_list)

FOREACH (conceptName in $concepts|
    MERGE (concept:Concept {name: conceptName})
        ON CREATE SET concept.timestamp = $time,
                      concept.uid = apoc.create.uuid()
    CREATE (concept)-[:BY {context: c_list.uid, timestamp: $time, statement: s.uid}]->(u)
    CREATE (concept)-[:OF {context: c_list.uid, user: u.uid, timestamp: $time}]->(s)
    CREATE (concept)-[:AT {user: u.uid, timestamp: $time, 
                           context: c_list.uid, statement: s.uid}]->(c_list)
)

WITH u, c_list, s

UNWIND $conceptsRelations as conceptsRelation
  MATCH (c_from:Concept {name: conceptsRelation.from})
  MATCH (c_to:Concept {name: conceptsRelation.to})
  CREATE (c_from)-[:TO {context: c_list.uid, statement: s.uid, user: u.uid,
                        timestamp: $time, uid: apoc.create.uuid(), 
                        gapscan: conceptsRelation.gapscan, 
                        weight: conceptsRelation.weight}]->(c_to)
RETURN distinct s.uid;