如何使用 Py2neo 对关系属性执行原子更新

How to perform an atomic update on relationship properties with Py2neo

我正在尝试使用 Py2neo 更新 Neo4j 图中的一些属性。我想执行一个原子计数器增量,然后仅当计数器为某个值时才更新一些其他属性。我还需要以线程安全的方式执行此操作,以便其他代理不会弄乱增量,或在提交整组值之前覆盖 属性 值。我相信它看起来像这样:

tx = graph.cypher.begin()
try:
    tx.acquireWriteLock(relationship) # from Java, not sure what this is in py2neo
    count = relationship.getProperty("count", 1);
    relationship.setProperty("count", count+1 );
    if count == threshold:
        relationship.setProperty("another_property", some_value );
    tx.success();
finally:
    tx.finish();

上面的一些代码是猜测的或取自 Java 示例,如果有人可以帮助 python 等价物或指出一些与我相同的示例代码的方向我'非常感谢。

事务仅在 Py2neo 中适用于 Cypher 语句,因此您需要使用 Cypher 来增加计数器和更新属性。

在此示例中,您将执行一条 Cypher 语句来增加计数器和 return 新值,将该新值与阈值进行比较,然后可选择执行另一条语句来更新关系 属性 如果超过该阈值。调用 tx.process 将允许您执行第一条语句,但不提交事务,从而启用与阈值的比较:

THRESHOLD = 10

tx = graph.cypher.begin()

statement = '''
MATCH (:Person {name: 'Bob'})-[r:EATS]->(:Food {name: 'Bagel'})
SET r.count = r.count + 1
RETURN r.count AS count_value
'''

tx.append(statement)
result = tx.process()

for record in result:
    count = record.one

    if count > THRESHOLD:
        update_statement = '''
        MATCH (:Person {name: 'Bob'})-[r:EATS]->(:Food {name: 'Bagel'})
        SET r.another_property = 'some value'
        '''
        tx.append(update_statement)
        tx.process()

tx.commit()

单个 Cypher 语句

请注意,您也可以使用单个 Cypher 语句完成此操作:

MATCH (:Person {name: 'Bob'})-[r:EATS]->(:Food {name: 'Bagel'})
SET r.count = r.count + 1
WITH r,
CASE WHEN r.count > 10 THEN [1]
ELSE [] END
AS exceeded
FOREACH (i IN exceeded | SET r.another_property = "some value")

我最终找到了一种更简洁、更线程安全的方法来使用 Cypher 来完成我的要求。感谢 neo4j-users Slack 频道,我被告知需要获取锁以避免在这样的并发用例中出现 'lost updates'。 Cypher 没有明确的锁定节点的能力,但是添加或实际上删除不存在的 属性 将导致 Cypher 锁定节点以进行更新。这在这里讨论:http://neo4j.com/docs/stable/transactions-isolation.html

我的 Cypher 查询最终看起来像这样:

MATCH (a:Person {name: 'a'}), (b:Person {name: 'b'})
REMOVE a.__notexisitng__, b.__notexisiting__
WITH a,b
MATCH (a)-[r:KNOWS]-(b)
SET r.count = r.count + 1
WHERE r.count = threshold 
SET r.another_property = 'some value'

为了 运行 在 py2neo 中,下面的代码完成了这项工作:

statement = "cypher query above ^"
parameters = {}
response = graph.cypher.post(statement, parameters)