Как сделать эффективный и быстрый длинный запрос для Neo4J: оптимизировать Cypher или улучшить конструктор Javascript / Node.Js? - PullRequest
0 голосов
/ 20 января 2019

У меня есть задача для приложения Node.Js, которое преобразует текст в сеть (слова - это узлы, а их совместные вхождения - нескольких весов - это соединения в сетевом графе), где мне нужно сохранить все данные в базу данных Neo4J.

Как вы можете себе представить, хотя это работает и для коротких операторов, как только они становятся длиннее, например, 5000 слов, где словарь составляет около 500 уникальных слов, мне нужно сохранить много узлов и много соединения в базу данных.

На данный момент у меня есть запрос такого типа:

MATCH (u:User {uid: "15229100-b20e-11e3-80d3-6150cb20a1b9"}) 
MERGE (c_0:Context {name:"st",by:u.uid,uid:"d0342000-1c4c-11e9-b9f6-e1addb3b0fa7"}) 
ON CREATE SET c_0.timestamp="15479451847980000" MERGE (c_0)-[:BY{timestamp:"15479451847980000"}]->(u) 
CREATE (s:Statement {name:"#apple #orange #fruit", text:"apples and oranges are fruits", uid:"d0390200-1c4c-11e9-b9f6-e1addb3b0fa7", timestamp:"15479451847980000"}) 
CREATE (s)-[:BY {context:c_0.uid,timestamp:s.timestamp}]->(u) 
CREATE (s)-[:IN {user:u.id,timestamp:s.timestamp}]->(c_0) 
MERGE (cc_0:Concept {name:"apple"}) 
ON CREATE SET cc_0.uid="d0390201-1c4c-11e9-b9f6-e1addb3b0fa7" 
MERGE (cc_1:Concept {name:"orange"}) 
ON CREATE SET cc_1.uid="d0390204-1c4c-11e9-b9f6-e1addb3b0fa7" 
MERGE (cc_2:Concept {name:"fruit"}) 
ON CREATE SET cc_2.uid="d0390207-1c4c-11e9-b9f6-e1addb3b0fa7" 
CREATE (cc_0)-[:BY {context:c_0.uid,timestamp:s.timestamp,statement:s.uid}]->(u) 
CREATE (cc_0)-[:OF {context:c_0.uid,user:u.uid,timestamp:s.timestamp}]->(s)  
CREATE (cc_0)-[:AT {user:u.uid,timestamp:s.timestamp,context:c_0.uid,statement:s.uid}]->(c_0) 
CREATE (cc_0)-[:TO {context:c_0.uid,statement:s.uid,user:u.uid,timestamp:"15479451847980000",uid:"d0390205-1c4c-11e9-b9f6-e1addb3b0fa7",gapscan:"2",weight:"3"}]->(cc_1) 
CREATE (cc_1)-[:BY {context:c_0.uid,timestamp:"15479451847980000",statement:s.uid}]->(u) CREATE (cc_1)-[:OF {context:c_0.uid,user:u.uid,timestamp:"15479451847980000"}]->(s) 
CREATE (cc_1)-[:AT {user:u.uid,timestamp:"15479451847980000",context:c_0.uid,statement:s.uid}]->(c_0) 
CREATE (cc_1)-[:TO {context:c_0.uid,statement:s.uid,user:u.uid,timestamp:"15479451847980002",uid:"d0390208-1c4c-11e9-b9f6-e1addb3b0fa7",gapscan:"2",weight:"3"}]->(cc_2) 
CREATE (cc_0)-[:TO {context:c_0.uid,statement:s.uid,user:u.uid,timestamp:"15479451847980002",uid:"d039020a-1c4c-11e9-b9f6-e1addb3b0fa7",gapscan:"4",weight:"2"}]->(cc_2) 
CREATE (cc_2)-[:BY {context:c_0.uid,timestamp:"15479451847980002",statement:s.uid}]->(u) 
CREATE (cc_2)-[:OF {context:c_0.uid,user:u.uid,timestamp:"15479451847980002"}]->(s) 
CREATE (cc_2)-[:AT {user:u.uid,timestamp:"15479451847980002",context:c_0.uid,statement:s.uid}]->(c_0)  
RETURN s.uid;

Для этого абзаца текста:

apples and oranges are fruits

Как видите, это оказывается намного дольше, чем необходимо.

В настоящее время для более длинных текстов я просто делю запрос Cypher на более мелкие куски и передаю их в БД в транзакции.

Однако, это все еще довольно медленно - около секунды на каждый КБ текста.

Мой запрос строится в Javascript / Node.Js здесь: https://github.com/noduslabs/infranodus/blob/master/lib/db/neo4j.js#L116

Основная логика:

Если есть предложение типа apples and oranges are fruits

  1. Мне нужно создать узел для каждого, связать их с user, который их создал, а также с самим statement и graph (график может иметь несколько операторов).

  2. Тогда мне нужно создать связи между этими словами с разными весами:

    [яблоки - апельсины]

    [апельсины - фрукты]

    [яблоки - фрукты]

...

Какой эффективный способ сделать это для последовательности, скажем, 300 слов?

Я знаю, что мог бы использовать FOREACH циклов и params, а также apoc для генерации UID, но действительно ли это сделает запрос более эффективным по сравнению с его построением с использованием JavaScript? Я не совсем понимаю, как это сделать на моем множестве и поможет ли это решить проблему слишком большого количества словосочетаний для 300+.

Могут ли эти практики помочь и как я могу внедрить их в этот запрос Cypher?

1 Ответ

0 голосов
/ 21 января 2019

Я думаю, что проблема заключается в огромных операторах, которые должны быть проанализированы, скомпилированы и спланированы.

Лучше использовать пакеты параметров в качестве входных данных и позволить cypher выполнять итерациюсм.

https://medium.com/neo4j/5-tips-tricks-for-fast-batched-updates-of-graph-structures-with-neo4j-and-cypher-73c7f693c8cc

Для чего вам нужны все UUID?

У вас установлены индексы и ограничения для операций MERGE?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...