Cypher Neo4J - 使用 MERGE 的 CASE 表达式

Posted

技术标签:

【中文标题】Cypher Neo4J - 使用 MERGE 的 CASE 表达式【英文标题】:Cypher Neo4J - CASE Expression with MERGE 【发布时间】:2015-02-19 00:03:06 【问题描述】:

我正在尝试在 Cypher 中实现逻辑,根据特定条件(CASE 语句),我将创建一些节点和关系;代码如下

MATCH (g:Game)-[:PLAYER]->(u:User)-[r1:AT]->(b1:Block)-[:NEXT]->(b2:Block) 
WHERE g.game_id='G222' and u.email_id = 'xyz@example.com' and b1.block_id='16' 
SET r1.status='Skipped', r1.enddate=20141225
WITH u, b2,b1, g, r1
SET b1.test = CASE b2.fork 
WHEN 'y' THEN
     MERGE (u)-[r2:STAGE startdate:20141225, enddate:'99999999', status:'InProgress']->(b2     fork:'fail') RETURN 1
ELSE 
     MERGE (u)-[r2:STAGE startdate:20141225, enddate:'99999999', status:'InProgress']->(b2)   RETURN 2
END
WITH u, g
MATCH (u)-[:TIME]->(h:Time)<-[:TIME]-(g)
SET h.after = 0
SET h.before = h.before + 1

在这个查询中,WHEN 'y' THEN 中有一个merge 语句,这个查询抛出一个错误:

无效的输入“]”:预期的空白或关系模式(第 7 行,第 82 列) "合并 (u)-[r2:STAGE startdate:20141225, enddate:'99999999', status:'InProgress']->(b2 fork:'fail') 返回 1"

基本上,我正在尝试基于属性(即CASE 语句中的MERGE)创建关系,我尝试了不同的方法来使其正常工作,例如返回,以便在返回某些值等情况下进行。到目前为止没有任何效果。

这个查询可能有什么问题?

【问题讨论】:

【参考方案1】:

要执行条件写入操作,您需要使用FOREACH 技巧。使用 CASE 您可以返回一个元素数组或一个空数组。 FOREACH 迭代 CASE 表达式,因此有条件地执行操作。如果您还想要一个ELSE 部分,则需要使用CASE 中的逆条件来创建另一个FOREACH。例如,而不是

WHEN 'y' THEN
   MERGE (u)-[r2:STAGE startdate:20141225, enddate:'99999999', status:'InProgress']->(b2     fork:'fail') RETURN 1
ELSE 
    MERGE (u)-[r2:STAGE startdate:20141225, enddate:'99999999', status:'InProgress']->(b2)   RETURN 2
END

使用

FOREACH(ignoreMe IN CASE WHEN 'y' THEN [1] ELSE [] END | 
    MERGE (u)-[r2:STAGE startdate:20141225, enddate:'99999999', status:'InProgress']->(b2 fork:'fail')
)
FOREACH(ignoreMe IN CASE WHEN NOT 'y' THEN [1] ELSE [] END | 
    MERGE (u)-[r2:STAGE startdate:20141225, enddate:'99999999', status:'InProgress']->(b2)
)

另请参阅Mark's blog post。

【讨论】:

谢谢Stefan,是的,你是对的,看来我们需要使用FOREACH,我还参考了你之前在***中的一篇文章,逻辑最终是这样的 WITH u, b2,b1, g , r1, CASE WHEN (b1.fork='y' and b2.fork='success') or (b1.fork='n') or (b1.fork='success') THEN ['ok'] ELSE [ ] END as array1 FOREACH (el1 in array1 | MERGE (u)-[r2:STAGE startdate:20141225, enddate:99999999, status:'InProgress']->(b2)) 好戏,但你能解释一下THEN [1] ELSE []是什么意思,ignoreMe是什么意思(对不起,我不能忽略你)?跨度> Cypher 没有更新让我们忘记这个黑客?我真的很想知道,这个回复在 2018 年已经过时了。 @HerrIvan 这仍然是有条件合并的唯一方法吗? @bigmadwolf:是的。这是我一年前的问题。但从那以后就没有答案了……也许 Stefan Armbruster 知道得更清楚。【参考方案2】:

修复如下问题

WITH u, b2,b1, g, r1, CASE  WHEN (b1.fork='y' and b2.fork='success') or (b1.fork='n') or   (b1.fork='success') THEN ['ok'] ELSE [] END as array1
FOREACH (el1 in array1 | MERGE (u)-[r2:STAGE startdate:20141225, enddate:99999999, status:'InProgress']->(b2))

即使用 CASE WHEN 创建一个虚拟数组,该数组在某种程度上具有与匹配计数匹配的虚拟元素,然后使用 FOREACH 遍历结果。

再次感谢 Stefan 的创意...

深度学习

【讨论】:

不把长长的业务逻辑放到CQL里面会更整洁。【参考方案3】:

APOC 插件支持Conditional Cypher Execution,现在我们可以避免使用FOREACH 解决方法。

例如,您可以这样做:

MATCH (g:Game)-[:PLAYER]->(u:User)-[r1:AT]->(b1:Block)-[:NEXT]->(b2:Block) 
WHERE g.game_id='G222' AND u.email_id = 'xyz@example.com' AND b1.block_id='16' 
SET r1.status='Skipped', r1.enddate=20141225
WITH u, b2, g
CALL apoc.do.when(
  b2.fork = 'y',
  "MERGE (u)-[:STAGE startdate:20141225, enddate:'99999999', status:'InProgress']->(b2     fork:'fail')",
  "MERGE (u)-[:STAGE startdate:20141225, enddate:'99999999', status:'InProgress']->(b2)",
  u: u, b2: b2) YIELD value
WITH u, g
MATCH (u)-[:TIME]->(h:Time)<-[:TIME]-(g)
SET h.after = 0
SET h.before = h.before + 1

【讨论】:

【参考方案4】:

虽然这个答案对我有帮助,但我发现语法很难理解。所以这就是我写自己的答案的原因。在这里,我读取了一个 tsv 文件并生成了多种类型的边。

LOAD CSV WITH HEADERS FROM 'file:///data.tsv' AS r FIELDTERMINATOR '\t'
WITH r.movie_id as movie_id, r.person_id as person_id, r.category as category
MATCH (p:Person person_id:person_id)
MATCH (m:Movie movie_id:movie_id)
FOREACH (_ IN CASE WHEN category='actress' THEN [1] ELSE [] END |
  MERGE (p)-[:ACTRESS ]->(m)
)
FOREACH (_ IN CASE WHEN category='director' THEN [1] ELSE [] END |
  MERGE (p)-[:DIRECTOR ]->(m)
)    
FOREACH (_ IN CASE WHEN category='cinematographer' THEN [1] ELSE [] END |
  MERGE (p)-[:CINEMATOGRAPHER ]->(m)
)
FOREACH (_ IN CASE WHEN category='actor' THEN [1] ELSE [] END |
  MERGE (p)-[:ACTOR ]->(m)
)

这里_ 是一些变量,它根本不在任何地方使用,而是密码语法的必需品

【讨论】:

以上是关于Cypher Neo4J - 使用 MERGE 的 CASE 表达式的主要内容,如果未能解决你的问题,请参考以下文章

Neo4J 在 Cypher 中创建临时变量

知识图谱Neo4j Cypher查询语言详解

Neo4j 第三篇:Cypher查询入门

neo4j初次使用学习简单操作-cypher语言使用

Neo4j - Cypher vs Gremlin 查询语言

使用 Cypher 从 Neo4j 图中提取子图