Pregunta

Estoy intentando encontrar una solución al siguiente problema.Lo he visto casi descrito en este Entonces pregunta, pero realmente no respondió.

El siguiente código falla al comenzar con un gráfico nuevo:

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

En resumen, deseo, en una transacción por lotes, actualizar las propiedades de los nodos indexados existentes.La falla está ocurriendo en el batch.set_properties línea, y es porque el BatchRequest El objeto devuelto por la línea anterior no se interpreta como un nodo válido.Aunque no es del todo idéntico, parece que estoy intentando algo parecido a la respuesta publicada. aquí

Algunos detalles

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

Actualizar

Si divido el problema en lotes separados, entonces puede ejecutarse sin errores:

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()

Esto también funciona para muchos nodos.Aunque no me gusta la idea de dividir el lote, esta podría ser la única manera en este momento.¿Alguien tiene algunos comentarios sobre esto?

¿Fue útil?

Solución

Después de leer todas las características nuevas de Neo4j 2.0.0-M06, parece que el flujo de trabajo anterior de índices de relaciones y nodos está siendo reemplazado.Actualmente existe una cierta divergencia por parte de neo en la forma en que se realiza la indexación.A saber, etiquetas y índices de esquema.

Etiquetas

Las etiquetas se pueden adjuntar arbitrariamente a los nodos y pueden servir como referencia para un índice.

Índices

Los índices se pueden crear en Cypher haciendo referencia a etiquetas (aquí, User) y clave de propiedad del nodo, (screen_name):

CREATE INDEX ON :User(screen_name)

Cifrar MERGE

Además, el indexado get_or_create Los métodos ahora son posibles a través del nuevo cifrado. MERGE función, que incorpora etiquetas y sus índices de forma bastante sucinta:

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

Lote

Las consultas de este tipo se pueden agrupar en py2neo agregando una instancia de CypherQuery al objeto por lotes:

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"])

Limitación

Sin embargo, existe una limitación: no se puede hacer referencia a los resultados de una consulta cifrada en una transacción por lotes más adelante en la misma transacción.La pregunta original hacía referencia a la actualización de una colección de propiedades de usuario indexadas en una transacción por lotes.Por lo que puedo entender, esto todavía no es posible.Por ejemplo, el siguiente fragmento genera un error:

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()

Entonces, parece que aunque hay un poco menos de gastos generales en la implementación del get_or_create sobre un nodo etiquetado usando py2neo Debido a que los índices heredados ya no son necesarios, la pregunta original aún necesita 2 transacciones por lotes separadas para completarse.

Otros consejos

Tu problema parece no estar en batch.set_properties() sino más bien en la producción de batch.get_or_create_in_index().Si agrega el nodo con batch.create(), funciona:

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()

Si observa las propiedades del objeto BatchRequest devuelto por batch.create() y batch.get_or_create_in_index() hay una diferencia en el URI porque los métodos usan diferentes partes de la API REST de neo4j:

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()

Así que supongo batch.set_properties() ¿De alguna manera no puedes manejar el URI del nodo indexado?Es decir.¿Realmente no obtiene el URI correcto para el nodo?

¿No resuelve el problema, pero podría ser una indicación para alguien más;)?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top