【问题标题】:Failed WriteBatch Operation with py2neopy2neo 的 WriteBatch 操作失败
【发布时间】:2013-11-29 09:40:04
【问题描述】:

我正在尝试找到解决以下问题的方法。我在SO question 中看到了它的准描述,但没有真正回答。

以下代码失败,从一个新的图表开始:

from py2neo import neo4j

def add_test_nodes():
    # Add a test node manually
    alice = g.get_or_create_indexed_node("Users", "user_id", 12345, {"user_id":12345})

def do_batch(graph):
    # Begin batch write transaction
    batch = neo4j.WriteBatch(graph)

    # get some updated node properties to add
    new_node_data = {"user_id":12345, "name": "Alice"}

    # batch requests
    a = batch.get_or_create_in_index(neo4j.Node, "Users", "user_id", 12345, {})
    batch.set_properties(a, new_node_data)  #<-- I'm the problem

    # execute batch requests and clear
    batch.run()
    batch.clear()

if __name__ == '__main__':
    # Initialize Graph DB service and create a Users node index
    g = neo4j.GraphDatabaseService()
    users_idx = g.get_or_create_index(neo4j.Node, "Users")

    # run the test functions
    add_test_nodes()
    alice = g.get_or_create_indexed_node("Users", "user_id", 12345)
    print alice

    do_batch(g)

    # get alice back and assert additional properties were added
    alice = g.get_or_create_indexed_node("Users", "user_id", 12345)
    assert "name" in alice

简而言之,我希望在一批事务中更新现有的索引节点属性。故障发生在batch.set_properties 行,这是因为上一行返回的BatchRequest 对象未被解释为有效节点。虽然不完全一致,但感觉就像我正在尝试类似here@

发布的答案

一些细节

>>> import py2neo
>>> py2neo.__version__
'1.6.0'
>>> g = py2neo.neo4j.GraphDatabaseService()
>>> g.neo4j_version
(2, 0, 0, u'M06') 

更新

如果我将问题拆分为单独的批次,那么它可以正常运行:

def do_batch(graph):
    # Begin batch write transaction
    batch = neo4j.WriteBatch(graph)

    # get some updated node properties to add
    new_node_data = {"user_id":12345, "name": "Alice"}

    # batch request 1
    batch.get_or_create_in_index(neo4j.Node, "Users", "user_id", 12345, {})

    # execute batch request and clear
    alice = batch.submit()
    batch.clear()

    # batch request 2
    batch.set_properties(a, new_node_data)

    # execute batch request and clear
    batch.run()
    batch.clear()

这也适用于许多节点。虽然我不喜欢拆分批次的想法,但这可能是目前唯一的方法。有人有这方面的cmet吗?

【问题讨论】:

  • 感谢您提交问题。响应引导我找到了我正在寻找的解决方案

标签: python neo4j py2neo


【解决方案1】:

您的问题似乎不在batch.set_properties() 中,而是在batch.get_or_create_in_index() 的输出中。如果使用batch.create() 添加节点,它可以工作:

db = neo4j.GraphDatabaseService()

batch = neo4j.WriteBatch(db)
# create a node instead of getting it from index
test_node = batch.create({'key': 'value'})
# set new properties on the node
batch.set_properties(test_node, {'key': 'foo'})

batch.submit()

如果您查看 batch.create()batch.get_or_create_in_index() 返回的 BatchRequest 对象的属性,则会发现 URI 存在差异,因为这些方法使用 neo4j REST API 的不同部分:

test_node = batch.create({'key': 'value'})
print test_node.uri # node
print test_node.body # {'key': 'value'}
print test_node.method # POST

index_node = batch.get_or_create_in_index(neo4j.Node, "Users", "user_id", 12345, {})
print index_node.uri # index/node/Users?uniqueness=get_or_create
print index_node.body # {u'value': 12345, u'key': 'user_id', u'properties': {}}
print index_node.method # POST

batch.submit()

所以我猜batch.set_properties() 不知何故无法处理索引节点的 URI? IE。它并没有真正获得节点的正确 URI?

不能解决问题,但可以作为其他人的指针;)?

【讨论】:

  • 是的,这是真的。谢谢。我的问题是,我希望节点是唯一的,并且它们可能已经存在,因此对get_or_create_in_index() 的调用我希望它会返回现有节点或创建一个新节点并将实例返回到该节点.
  • 这正是get_or_create_in_index() 的用途。我认为它应该可以工作,我们可以称之为错误。我敢打赌,Nigel Small 一定会对此有所了解;)在此之前,检查 neo4j rest api 文档以获取线索可能有意义吗?
【解决方案2】:

在阅读了 Neo4j 2.0.0-M06 的所有新功能之后,似乎节点和关系索引的旧工作流程正在被取代。目前,neo 在完成索引的方式上存在一些分歧。即labelsschema indexes

标签

标签可以任意附加到节点上,并且可以作为索引的参考。

索引

可以通过引用标签(此处为User)和节点属性键(screen_name)在 Cypher 中创建索引:

CREATE INDEX ON :User(screen_name)

密码MERGE

此外,索引get_or_create 方法现在可以通过新的密码MERGE 函数实现,该函数非常简洁地结合了标签及其索引:

MERGE (me:User{screen_name:"SunPowered"}) RETURN me

批次

通过将 CypherQuery 实例附加到批处理对象,可以在 py2neo 中对此类查询进行批处理:

from py2neo import neo4j

graph_db = neo4j.GraphDatabaseService()
cypher_merge_user = neo4j.CypherQuery(graph_db, 
    "MERGE (user:User {screen_name:{name}}) RETURN user")

def get_or_create_user(screen_name):
    """Return the user if exists, create one if not"""
    return cypher_merge_user.execute_one(name=screen_name)

def get_or_create_users(screen_names):
    """Apply the get or create user cypher query to many usernames in a 
    batch transaction"""
    
    batch = neo4j.WriteBatch(graph_db)
    
    for screen_name in screen_names:
        batch.append_cypher(cypher_merge_user, params=dict(name=screen_name))

    return batch.submit()

root = get_or_create_user("Root")
users = get_or_create_users(["alice", "bob", "charlie"])

限制

但是,有一个限制,即批处理事务中密码查询的结果以后不能在同一事务中引用。最初的问题是关于在一批事务中更新索引用户属性的集合。据我所知,这仍然是不可能的。例如下面的 sn -p 会抛出错误:

batch = neo4j.WriteBatch(graph_db)
b1 = batch.append_cypher(cypher_merge_user, params=dict(name="Alice"))
batch.set_properties(b1, dict(last_name="Smith")})
resp = batch.submit()

因此,尽管由于不再需要旧索引,因此在使用 py2neo 的标记节点上实现 get_or_create 的开销似乎更少,但原始问题仍需要 2 个单独的批处理事务才能完成。

【讨论】:

  • 为了将标签应用到索引节点(也有同样的错误),我最终只创建了具有 __label 属性的节点,然后在修复标签后运行 Cypher 查询:@987654337 @。 +1以获得详细答案。我在同一时间遇到了完全相同的问题。很高兴看到别人的解决方案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-28
  • 2015-07-29
  • 2021-10-01
  • 1970-01-01
  • 2013-11-22
相关资源
最近更新 更多