为什么neo4j循环表达式存在(()-->(N))求值为假,而实际上它为真?

v09wglhw  于 2022-10-21  发布在  其他
关注(0)|答案(1)|浏览(130)

我有这样一个图表

每个节点都有唯一的nodeId属性,该属性由Neo4j约束保证。每个关系都有唯一的id属性。Ne4j的版本为4.3.7。
浅绿色节点是公司,粉色节点是人,其他节点是不能存储在节点内的附加信息。在这里,“彼得公司”有两个费用,主要地址,次要地址,成立日期和终止日期。
我想删除“彼得公司”及其董事的旧信息。为此,我使用了这样一个查询:

UNWIND $batch AS data 
MATCH (n:Entity { nodeId: data.entityId }) 
OPTIONAL MATCH (n)-[rel]->(prop:Property) 
WHERE NOT prop.nodeId IN data.propertyIds
DELETE rel
WITH prop
WHERE NOT exists(()-->(prop))
DELETE prop

其中,本例中的$batch

[
    {
        'entityId':    '0000',
        'propertyIds': ['0002', '0003', '0004', '0005', '0006', '0009']
    },
    {
        'entityId':    '0001',
        'propertyIds': ['0004', '0010']
    },
]

entityId是节点的nodeIdpropertyIds是当前附加信息(属性)的nodeId。如果存在从实体到ID不在propertyIds中的属性的连接,则这是旧信息,必须删除它们之间的边。此外,如果特性在此之后没有更多的传入边(它只能具有传入边),则会将其删除。
上面的列表包含公司及其董事的ID及其当前财产的ID。与“其他公司”有关联的日期对“Peter Company”已过时,其nodeId不在上面的批次中。作为查询的结果,我预计必须删除从公司到旧物业的连接,而不删除该物业。
但我得到了一个错误:

Cannot delete node<18>, because it still has relationships. To delete this node, you must first delete its relationships.

为什么我收到一个错误?节点18有一个来自“Other Company”的传入连接,因此exists(()-->(prop))必须返回true
如果将该表达式更改为exists(()--(prop)),则不会出现错误。
如果我在查询中将DELETE替换为SET

UNWIND $batch AS data 
MATCH (n:Entity { nodeId: data.entityId }) 
OPTIONAL MATCH (n)-[rel]->(prop:Property) 
WHERE NOT prop.nodeId IN data.propertyIds
SET rel.toPrune = true
WITH prop
WHERE NOT exists(()-->(prop))
SET prop.toPrune = true

则标记关系而不标记节点,即,exists(()-->(prop))返回true
我用Python语言创建了一个重现该问题的示例:

from neo4j import GraphDatabase

with GraphDatabase.driver("bolt://localhost:7687", auth=('neo4j', 'neo')) as driver, \
        driver.session() as session:

    create_graph = """
    MERGE (n1:Test:Entity:Company {nodeId: "0000"}) SET n1.name = "Peter company"
    MERGE (n2:Test:Entity:Person {nodeId: "0001"}) SET n2.name = "Peter"
    MERGE (n3:Test:Property:Charge {nodeId: "0002"}) SET n3.status = "closed"
    MERGE (n4:Test:Property:Charge {nodeId: "0003"}) SET n4.status = "opened"
    MERGE (n5:Test:Property:Address {nodeId: "0004"}) SET n5.country = "France"
    MERGE (n6:Test:Property:Address {nodeId: "0005"})
        SET n6.country = "France"
        SET n6.city = "Ham Les Varennes"
    MERGE (n7:Test:Property:Date {nodeId: "0006"})
        SET n7.date = datetime("2014-09-04T00:00:00")
        SET n7.monthIsKnown = true
        SET n7.dayIsKnown = true
    MERGE (n8:Test:Property:Date {nodeId: "0007"})
        SET n8.date = datetime("1962-01-01T00:00:00")
        SET n8.monthIsKnown = false
        SET n8.dayIsKnown = false
    MERGE (n9:Test:Entity:Company {nodeId: "0008"}) SET n9.name = "Other company"
    MERGE (n10:Test:Property:Date {nodeId: "0009"})
        SET n10.date = datetime("1962-01-01T00:00:00")
        SET n10.monthIsKnown = false
        SET n10.dayIsKnown = false
    MERGE (n11:Test:Property:Date {nodeId: "0010"})
        SET n11.date = datetime("1976-01-01T00:00:00")
        SET n11.monthIsKnown = false
        SET n11.dayIsKnown = false

    MERGE (n1)-[:HAS_CHARGE {id: 1}]->(n3)
    MERGE (n1)-[:HAS_CHARGE {id: 2}]->(n4)
    MERGE (n1)-[:HAS_PRIMARY_ADDRESS {id: 3}]->(n5)
    MERGE (n1)-[:HAS_SECONDARY_ADDRESS {id: 4}]->(n6)
    MERGE (n1)-[:HAS_TERMINATION_DATE {id: 5}]->(n7)
    MERGE (n1)-[:HAS_CREATION_DATE {id: 6}]->(n8)
    MERGE (n1)-[:HAS_CREATION_DATE {id: 7}]->(n10)

    MERGE (n2)-[:FR_DIRECTOR {id: 8}]->(n1)
    MERGE (n2)-[:HAS_COUNTRY_OF_RESIDENCE {id: 9}]->(n5)
    MERGE (n2)-[:HAS_DATE_OF_BIRTH {id: 10}]->(n11)

    MERGE (n9)-[:HAS_CREATION_DATE {id: 11}]->(n8)
    """

    with session.begin_transaction() as tx:
        tx.run(create_graph)

    batch = [
        {
            'entityId':    '0000',
            'propertyIds': ['0002', '0003', '0004', '0005', '0006', '0009']
            },
        {
            'entityId':    '0001',
            'propertyIds': ['0004', '0010']
            },
        ]

    clean_old_properties = """
    UNWIND $batch AS data 
    MATCH (n:Entity { nodeId: data.entityId }) 
    OPTIONAL MATCH (n)-[rel]->(prop:Property) 
    WHERE NOT prop.nodeId IN data.propertyIds
    DELETE rel
    WITH prop
    WHERE NOT exists(()-->(prop))
    DELETE prop
    """

    with session.begin_transaction() as tx:
        tx.run(clean_old_properties, dict(batch=batch))

一个有趣的注意事项:如果本例中的两个查询都在一个事务中执行,则不会发出错误。

xzv2uavs

xzv2uavs1#

该错误是由Neo4j内核中的错误引起的。该问题已在版本4.4.12中修复。

内核

  • 修复在同一交易中删除关系时的节点度计算

更改日志
Related issue

相关问题