Запрос Neo4j с логическими операциями между узлами - PullRequest
0 голосов
/ 22 мая 2018

У нас есть граф БД с узлами: Resume и Skill.Узел умений содержит свойство - «Имя».Он имеет типовые значения, такие как Java, C ...

И мы создали отношение has_skill между узлами Resume и Skill.И каждый узел Resume может содержать любое количество узлов Skill с отношением has_skill.

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

((JAVA AND MYSQL) OR (C AND MSSQL)) AND HTML 

Мы попробовали следующееquery

match(n:Skill)--(n1:PannaResume)
where ((n.name contains "java" AND n.name contains "mysql")
OR (n.name contains "c" AND n.name contains "mssql")) 
AND n.name contains "html"
return n1

Но это не дает ожидаемого результата.Пожалуйста, предложите правильный запрос.

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Ваш запрос не выполняется, потому что вы просите Neo4j найти человека, у которого есть навык, то есть как минимум 3 навыка одновременно.Очевидно, что, учитывая навык n, это никогда не будет java, mysql и html.(Я предполагаю, что вы используете содержимое для «удаления» любой информации о версии, которую они могли добавить к названию навыка, например, javaee или java 8. Просто помните, что это также будет соответствовать javascript. Однако я бы порекомендовал вам получать эти данные в Neo4j, чтобыпусть он разберет общее имя в отдельном поле. Если вы рассматриваете имя как массив умений, то у вас, вероятно, нет совпадений, и ваша схема слишком хрупкая, чтобы делать с ней что-нибудь полезное)

Я бы порекомендовалэтот шаблон соответствия, так что Neo4j проверяет наличие любого действительного узла навыка

MATCH (n:Skill)<--(n1:PannaResume)
WITH n1, COLLECT(n.name) as skills
WHERE ANY(name in skills WHERE name contains "html")
AND (ANY(name in skills WHERE name contains "java")
 OR ANY(name in skills WHERE name contains "mysql")
)
OR (
(ANY(name in skills WHERE name contains "c")
 OR ANY(name in skills WHERE name contains "mssql")
))

, конечно, чем точнее, тем лучше.Это будет работать намного лучше.

MATCH (n1:PannaResume)-[:has_skill]->(:Skill {name : "html"})
WHERE ((n1)-[:has_skill]->(:Skill {name : "java"}) AND (n1)-[:has_skill]->(:Skill {name : "mysql"}))
OR ((n1)-[:has_skill]->(:Skill {name : "c"}) AND (n1)-[:has_skill]->(:Skill {name : "mssql"}))
RETURN n1

Но вы также можете немного упростить (и упростить планировщик Cypher), разделив ваш запрос на набор отдельных запросов, и объединить результаты, подобные этим

MATCH (n1:PannaResume)-[:has_skill]->(:Skill {name : "html"})
WHERE (n1)-[:has_skill]->(:Skill {name : "java"}) 
  AND (n1)-[:has_skill]->(:Skill {name : "mysql"})
RETURN n1
UNION
MATCH (n1:PannaResume)-[:has_skill]->(:Skill {name : "html"})
WHERE (n1)-[:has_skill]->(:Skill {name : "c"})
  AND (n1)-[:has_skill]->(:Skill {name : "mssql"})
RETURN n1

Это должно быть эквивалентно предыдущим запросам, но может быть более эффективным в зависимости от того, что вы делаете / версия Neo4j.WITH будет разбивать запрос на несколько этапов, поэтому планировщик Cypher сначала найдет узлы навыков, а затем найдет человека, связанного с этими навыками.

MATCH (html:Skill {name : "html"}), (java:Skill {name : "java"}), (c:Skill {name : "c"}), (mysql:Skill {name : "mysql"}), (mssql:Skill {name : "mssql"})
WITH *
MATCH (n1:PannaResume)-[:has_skill]->(html)
WHERE ((n1)-[:has_skill]->(java) AND (n1)-[:has_skill]->(mysql)
OR ((n1)-[:has_skill]->(c) AND (n1)-[:has_skill]->(mssql)
RETURN n1

Если вам нужно беспокоиться об эффективности,Вы должны поэкспериментировать с разными запросами, используя ключевое слово PROFILE .Главное, что вы пытаетесь сделать, это минимизировать количество строк, которое производит каждая «стадия» запроса, поскольку каждая последующая стадия будет умножена на количество строк, произведенных предыдущей стадией.(Планировщик Cypher может выбрать выполнение нескольких запросов параллельно, а затем найти их пересечение. Поэтому не очевидно, как изменение Cypher повлияет на план. PROFILE покажет неэффективность вашего запроса, поэтому обратите внимание на шаги свысокая dbhits или результат в большом количестве строк.)

0 голосов
/ 22 мая 2018

Вы можете попробовать проверить по существованию шаблона:

match (n1:PannaResume)-[:has_skill]->(n:Skill)
where ((n1)-[:has_skill]->(:Skill {name : "java"}) and (n1)-[:has_skill]->(:Skill {name : "mysql"}))
OR ((n1)-[:has_skill]->(:Skill {name : "c"}) and (n1)-[:has_skill]->(:Skill {name : "mssql"}))
AND (n1)-[:has_skill]->(:Skill {name : "HTML"})
RETURN n1
...