Neo4j 当可选匹配为null时,如何编写cypher语句来合并节点? 背景

Neo4j 当可选匹配为null时,如何编写cypher语句来合并节点? 背景,neo4j,cypher,match,optional,Neo4j,Cypher,Match,Optional,大家好,我目前正在尝试编写一个cypher语句,它允许我从一个起点在地图上找到一组路径我希望我的搜索结果始终返回5个节点内的连接街道。或者,如果附近有医院,我希望我的搜索模式也能指示附近的医院。 主要问题 因为当前街道附近并不总是有医院,有时我的可选匹配搜索模式返回为空。下面是我正在使用的当前cypher语句: MATCH path=(a:Street {id: 123})-[:CONNECTED_TO*..5]-(b:Street) OPTIONAL MATCH optionalPath=(b

大家好,我目前正在尝试编写一个cypher语句,它允许我从一个起点在地图上找到一组路径我希望我的搜索结果始终返回5个节点内的连接街道。或者,如果附近有医院,我希望我的搜索模式也能指示附近的医院。

主要问题 因为当前街道附近并不总是有医院,有时我的可选匹配搜索模式返回为空。下面是我正在使用的当前cypher语句:

MATCH path=(a:Street {id: 123})-[:CONNECTED_TO*..5]-(b:Street)
OPTIONAL MATCH optionalPath=(b)-[:CONNECTED_TO]->(hospital:Hospital)
WHERE ALL (x IN nodes(path) WHERE (x:Street))
WITH DISTINCT nodes(path) + nodes(optionalPath) as n
UNWIND n as nodes
RETURN DISTINCT nodes;
但是,此语法仅在
optionalPath
包含节点时有效。如果没有,则语句
nodes(path)+nodes(optionalPath)
是一个添加null的操作,我没有得到任何记录。即使
节点(路径)
术语也包含节点,这一点也是正确的


解决此问题的最佳方法是什么?

您可以使用
COALESCE
NULL
替换为其他值。例如:

MATCH path=(:Street {id: 123})-[:CONNECTED_TO*..5]-(b:Street)
WHERE ALL (x IN nodes(path) WHERE x:Street)
OPTIONAL MATCH optionalPath=(b)-[:CONNECTED_TO]->(hospital:Hospital)
WITH nodes(path) + COALESCE(nodes(optionalPath), []) as n
UNWIND n as nodes
RETURN DISTINCT nodes;
我还做了一些其他改进:

  • WHERE
    子句在第一个
    MATCH
    之后被上移。这将立即消除不需要的
    路径
    值。原始查询将获得所有
    path
    值(甚至是不需要的值),并始终执行第二个
    匹配
    查询,然后仅消除不需要的路径。(但是,实际上还不清楚您是否需要
    WHERE
    子句;例如,如果
    CONNECTED_TO
    关系仅在
    Street
    节点之间使用。)

  • WITH
    子句中的
    DISTINCT
    可以防止重复的
    n
    集合,但是集合内部可能有重复的路径。这可能不是你想要的


  • 您可以使用
    COALESCE
    NULL
    替换为其他值。例如:

    MATCH path=(:Street {id: 123})-[:CONNECTED_TO*..5]-(b:Street)
    WHERE ALL (x IN nodes(path) WHERE x:Street)
    OPTIONAL MATCH optionalPath=(b)-[:CONNECTED_TO]->(hospital:Hospital)
    WITH nodes(path) + COALESCE(nodes(optionalPath), []) as n
    UNWIND n as nodes
    RETURN DISTINCT nodes;
    
    我还做了一些其他改进:

  • WHERE
    子句在第一个
    MATCH
    之后被上移。这将立即消除不需要的
    路径
    值。原始查询将获得所有
    path
    值(甚至是不需要的值),并始终执行第二个
    匹配
    查询,然后仅消除不需要的路径。(但是,实际上还不清楚您是否需要
    WHERE
    子句;例如,如果
    CONNECTED_TO
    关系仅在
    Street
    节点之间使用。)

  • WITH
    子句中的
    DISTINCT
    可以防止重复的
    n
    集合,但是集合内部可能有重复的路径。这可能不是你想要的


  • 看起来你并不真的想要路径,只是5步以内的所有街道节点,加上任何连接的医院。因此,我会将您的查询简化为这一点,然后将3列压缩为1列

    MATCH (a:Street {id: 123})-[:CONNECTED_TO*..5]-(b:Street)
    OPTIONAL MATCH (b)-[:CONNECTED_TO]->(hospital:Hospital)
    WITH collect(a) + collect(b) + collect(hospital) as n
    UNWIND n as nodez
    RETURN DISTINCT nodez;
    
    如果街道可以间接连接(医院之间),我会这样调整

    MATCH (a:Street {id: 123})-[:CONNECTED_TO]-(b:Street)
    WITH a as nodez, b as a
    MATCH (a)-[:CONNECTED_TO]-(b:Street)
    WITH nodez+collect(b) as nodez, b as a
    MATCH (a)-[:CONNECTED_TO]-(b:Street)
    WITH nodez+collect(b) as nodez, b as a
    MATCH (a)-[:CONNECTED_TO]-(b:Street)
    WITH nodez+collect(b) as nodez, b as a
    MATCH (a)-[:CONNECTED_TO]-(b:Street)
    WITH nodez+collect(b) as nodez, b as a
    OPTIONAL MATCH (b)-[:CONNECTED_TO]->(hospital:Hospital)
    WITH nodez + collect(hospital) as n
    UNWIND n as nodez
    RETURN DISTINCT nodez;
    

    它有点冗长,但只说了您想要的内容(还将开始节点添加到医院检查列表中)

    似乎您并不真正想要路径,只需要5个步骤内的所有街道节点,以及任何连接的医院。因此,我会将您的查询简化为这一点,然后将3列压缩为1列

    MATCH (a:Street {id: 123})-[:CONNECTED_TO*..5]-(b:Street)
    OPTIONAL MATCH (b)-[:CONNECTED_TO]->(hospital:Hospital)
    WITH collect(a) + collect(b) + collect(hospital) as n
    UNWIND n as nodez
    RETURN DISTINCT nodez;
    
    如果街道可以间接连接(医院之间),我会这样调整

    MATCH (a:Street {id: 123})-[:CONNECTED_TO]-(b:Street)
    WITH a as nodez, b as a
    MATCH (a)-[:CONNECTED_TO]-(b:Street)
    WITH nodez+collect(b) as nodez, b as a
    MATCH (a)-[:CONNECTED_TO]-(b:Street)
    WITH nodez+collect(b) as nodez, b as a
    MATCH (a)-[:CONNECTED_TO]-(b:Street)
    WITH nodez+collect(b) as nodez, b as a
    MATCH (a)-[:CONNECTED_TO]-(b:Street)
    WITH nodez+collect(b) as nodez, b as a
    OPTIONAL MATCH (b)-[:CONNECTED_TO]->(hospital:Hospital)
    WITH nodez + collect(hospital) as n
    UNWIND n as nodez
    RETURN DISTINCT nodez;
    

    这有点冗长,但只说了您想要的内容(还将开始节点添加到医院检查列表中)

    我认为这正是我想要的,您的改进非常好。Re:(1)这是有意义的,并将缩短查询搜索时间;此外,我的数据集非常丰富(只是在这里简化了它,以便发布问题),我发现,除非我指定路径中的所有节点都必须是Street类型,否则我将获得遍历其他类型节点的路径;(2) 谢谢你指出这一点。我仍在学习密码,所以有些错误不会立即在我面前显现出来。太好了。当你问问题时,请记住最好的答案。快速跟进。我做了一些测试,如果我在路径不为null时使用COALESCE(路径,[]),我会得到一个类型错误:“类型不匹配:预期的节点,但为Any,Map,Node”。我认为COALESCE获取了第一个非空条目并继续执行查询。首先,
    COALESCE(path,[])
    毫无意义,因为路径不是集合;您需要确保这两个参数的类型相同,否则其余的密码将不会始终获得预期的类型。此外,错误可能来自试图利用
    合并的结果的子句。如果你仍然有问题,这听起来像是一个新问题。我想这正是我想要的,你的改进非常好。Re:(1)这是有意义的,并将缩短查询搜索时间;此外,我的数据集非常丰富(只是在这里简化了它,以便发布问题),我发现,除非我指定路径中的所有节点都必须是Street类型,否则我将获得遍历其他类型节点的路径;(2) 谢谢你指出这一点。我仍在学习密码,所以有些错误不会立即在我面前显现出来。太好了。当你问问题时,请记住最好的答案。快速跟进。我做了一些测试,如果我在路径不为null时使用COALESCE(路径,[]),我会得到一个类型错误:“类型不匹配:预期的节点,但为Any,Map,Node”。我认为COALESCE获取了第一个非空条目并继续执行查询。首先,
    COALESCE(path,[])
    毫无意义,因为路径不是集合;您需要确保这两个参数是同一类型的,否则您的Cypher wi的其余部分都是相同的