如何使用 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)
我正在尝试使用 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)