Решение этой проблемы связано с объектами, возвращаемыми различными командами в py2neo v 4.1.0.Я попытался обобщить проблему / решение, чтобы она была полезной за пределами моего конкретного варианта использования.
Выполнение команды Cypher в браузере neo4j возвращает объект RECORD
и все узлы и ребра (и в браузерекажется, что все ребра среди всех найденных узлов, даже если вы не просили эти ребра).Браузер покажет вам все элементы в этой записи без необходимости делать что-то особенное (хотя вы можете ограничить то, что браузер возвращает, используя LIMIT
для числа и WHERE
для фильтрации меток и свойств).
Py2neo имеет множество опций для возврата объектов из запросов Cypher, ни один из которых не является хорошо документированным и ни один из которых не имеет полезных примеров или достаточных объяснений различий.Но после многих попыток и неудач мне удалось выяснить несколько вещей и заставить его работать.Я собираюсь поделиться тем, что я узнал, так что, надеюсь, кто-то еще, пытающийся использовать этот пакет, не потеряет часы из-за плохой документации.
Рассмотрим следующий метод, который вы можете использовать для извлечения узла из вашей базы данных.
import py2neo as pn
graph = pn.Graph("bolt://localhost:####/", user="neo4j", password="pwd")
theCypherQuery= '''MATCH (n:Label1) WHERE n.label1_name=$para1
OPTIONAL MATCH (n:Label1)<-[:REL1]-(n2:Label2) WHERE n2.label2_name = $para2
OPTIONAL MATCH (n:Label1)<-[:REL1]-(n3:Label3) WHERE n3.label3_name = $para2
RETURN n2, n3'''
def getNode(thisCypherQuery, parameter1, parameter2):
cypherResult = graph.evaluate(thisCypherQuery, parameters = {'para1':parameter1, 'para2':parameter2})
return cypherResult
someNode = getNode(theCypherQuery,firstParameter,secondParameter)
Если theCypherQuery
всегда возвращает ровно один узел, то graph.evaluate
будет работать, потому что фактически возвращает первый объект в записи, сгенерированной запросом.
Однако, если у вас более сложный запрос и / или база данных, которая потенциально возвращает несколько элементов (даже если все элементы, кроме одного, равны None
), вам нужно использовать graph.run
вместо graph.evaluate
.Но graph.run
возвращает объект записи, с которым вы не можете легко справиться в Python, поэтому есть варианты:
graph.run(theCypherQuery).data()
возвращает результат в виде списка из одного словаря отчетоввсе узлы вернулись в записи.
graph.run(theCypherQuery).table()
возвращает этот словарь в виде таблицы ключей и значений, что, по-видимому, наиболее полезно для печати на консоли.
graph.run(theCypherQuery).evaluate()
эквивалентно graph.evaluate(theCypherQuery)
выше и возвращает первый объект.
В моем реальном случае я хотел сопоставить имячерез узлы с различными видами меток, которые являются дочерними по отношению к другому узлу с определенной меткой.Мой запрос Cypher всегда возвращал правильный узел, но было также возвращено пять объектов None
(для других меток узлов), которые просто игнорировались в браузере, но нарушали мой код Python.Возможно, я мог бы изменить свой запрос Cypher, чтобы он возвращал только этот один узел, независимо от его типа метки, но независимо от того, что я решил, что это хорошая идея, чтобы научиться обращаться с этими объектами записи.
Вот пример манипуляциивозвратил объект записи в Python для извлечения узлов и исключения ответов None
.
def getNode(thisCypherQuery, parameter1, parameter2):
## The returned node is None by default
thisNode = None
## Retrieve the record object from the query, substituting in the parameter values.
## The .data() part returns a list containing a single dictionary.
## So I extract the dictionary by simply pulling item [0].
thisRecord = graph.run(theCypherQuery, parameters = {'para1':parameter1, 'para2':parameter2}).data()[0]
## Now I create a list of non-None values from the dictionary using "list comprehension".
theseNodes = [val for key,val in thisRecord .items() if val != None]
## Perhaps nothing was found, but if at least one item was found...
if len(theseNodes) > 0:
## Then return the first found object (which in my case is the unique matching node)
## Note that this is also necessary to convert the list into a node object.
thisNode = theseNodes[0]
return thisNode
Нет ничего особенно странного в сложном Python, если вы уже опытны, но без надлежащей документации может быть сложно понять структуры данных и то, что необходимо для их извлечения и манипулирования ими.В этом случае извлеченные объекты узлов совместимы с командами py2neo, такими как приведенные ниже, для создания связи между двумя найденными узлами на основе их имен (из другого источника данных).
firstNode = getNode(theCypherQuery,'UnitedStates','Georgia')
secondNode = getNode(theCypherQuery,'UnitedStates','Jacksonville')
graph.merge(pn.Relationship(firstNode,'BORDERING',secondNode))
Обратите внимание, что у меня нет 'Я еще не пытался возвращать и манипулировать объектом отношений, но, надеюсь, он не будет сильно отличаться от получения и использования объектов узла.И, надеюсь, вы можете изменить этот код, чтобы получать узлы и отношения в соответствии с вашими потребностями.