py2neo: Graph.find_one 有多个 key/values
py2neo: Graph.find_one with multiple key/values
我在查找 py2neo 和 find_one (http://py2neo.org/2.0/essentials.html)
时遇到了一些问题
我想要的 Cypher 是:
MATCH (p:Person) WHERE p.name='Alice' AND p.age=22 RETURN p
比如说,如果有多个 key/value 集(例如,如果图中有多个 'Alice')。
我的问题是我不知道该给什么graph.find_one,有效代码是:
graph.find_one('Person', 'name', 'Alice')
我想要的是(这不起作用!):
graph.find_one('Person', {'name': 'Alice', 'age': 22})
一个可能的(不好的)解决方案是制作一个 graph.find,然后遍历结果属性并查找年龄,但我不喜欢该解决方案。
奖励: graph.find 可以做年龄 > 25 的事情吗?
编辑:新 "solution"
find_person = "MATCH (p:Person) WHERE p.name = {N} AND p.age = {A} RETURN p"
>>> tx = graph.cypher.begin()
>>> tx.append(find_person, {'N': 'Alice', 'A': 22})
>>> res = tx.process()
>>> print(res[0][0][0])
(n423:Person {age:22,name:"Lisa"})
我不喜欢的是我错过了 Note 对象,(而且我不完全理解 RecordListList,以及如何导航它 nicley)
如果您查看 source code you will find that unfortunately find
and find_one
don't support that type of queries. You should directly use the Cypher interface:
d = {'name': 'Alice', 'age' : 22}
# quote string values
d = {k:"'{}'".format(v) if isinstance(v, basestring) else v
for k,v in d.items()}
cond = ' AND '.join("p.{}={}".format(prop, value) for prop, value in d.items())
query = "MATCH (p:Person) {condition} RETURN p"
query = query.format(condition=cond)
# "MATCH (p:Person) p.age=22 AND p.name='Alice' RETURN p"
results = graph.cypher.execute(query)
根据@elyase 的回答和原来的 py2neo.Graph.find,我制作了这段代码。请随时发表评论和改进.. :-)
def find_dict(graph, label, key_value=None, limit=None):
""" Iterate through a set of labelled nodes, optionally filtering
by property key/value dictionary
"""
if not label:
raise ValueError("Empty label")
from py2neo.cypher.lang import cypher_escape
if key_value is None:
statement = "MATCH (n:%s) RETURN n,labels(n)" % cypher_escape(label)
else:
# quote string values
d = {k: "'{}'".format(v) if isinstance(v, str) else v
for k, v in key_value.items()}
cond = ""
for prop, value in d.items():
if not isinstance(value, tuple):
value = ('=', value)
if cond == "":
cond += "n.{prop}{value[0]}{value[1]}".format(
prop=prop,
value=value,
)
else:
cond += " AND n.{prop}{value[0]}{value[1]}".format(
prop=prop,
value=value,
)
statement = "MATCH (n:%s ) WHERE %s RETURN n,labels(n)" % (
cypher_escape(label), cond)
if limit:
statement += " LIMIT %s" % limit
response = graph.cypher.post(statement)
for record in response.content["data"]:
dehydrated = record[0]
dehydrated.setdefault("metadata", {})["labels"] = record[1]
yield graph.hydrate(dehydrated)
response.close()
def find_dict_one(graph, label, key_value=None):
""" Find a single node by label and optional property. This method is
intended to be used with a unique constraint and does not fail if more
than one matching node is found.
"""
for node in find_dict(graph, label, key_value, limit=1):
return node
使用find_dict_one:
>>> a = find_dict_one(graph, 'Person', {'name': 'Lisa', 'age': 23})
>>> print(a)
(n1:Person {age:23,name:"Lisa"})
将 find_dict 与元组一起使用:
>>> a = find_dict(graph, 'Person', {'age': ('>', 21)}, 2) >>> for i in a:
>>> print(i)
(n2:Person {age:22,name:"Bart"})
(n1:Person {age:23,name:"Lisa"})
使用不带元组的 find_dict:
>>> a = find_dict(graph, 'Person', {'age': 22}, 2) >>> for i in a:
>>> print(i)
(n2:Person {age:22,name:"Bart"})
我在查找 py2neo 和 find_one (http://py2neo.org/2.0/essentials.html)
时遇到了一些问题我想要的 Cypher 是:
MATCH (p:Person) WHERE p.name='Alice' AND p.age=22 RETURN p
比如说,如果有多个 key/value 集(例如,如果图中有多个 'Alice')。
我的问题是我不知道该给什么graph.find_one,有效代码是:
graph.find_one('Person', 'name', 'Alice')
我想要的是(这不起作用!):
graph.find_one('Person', {'name': 'Alice', 'age': 22})
一个可能的(不好的)解决方案是制作一个 graph.find,然后遍历结果属性并查找年龄,但我不喜欢该解决方案。
奖励: graph.find 可以做年龄 > 25 的事情吗?
编辑:新 "solution"
find_person = "MATCH (p:Person) WHERE p.name = {N} AND p.age = {A} RETURN p"
>>> tx = graph.cypher.begin()
>>> tx.append(find_person, {'N': 'Alice', 'A': 22})
>>> res = tx.process()
>>> print(res[0][0][0])
(n423:Person {age:22,name:"Lisa"})
我不喜欢的是我错过了 Note 对象,(而且我不完全理解 RecordListList,以及如何导航它 nicley)
如果您查看 source code you will find that unfortunately find
and find_one
don't support that type of queries. You should directly use the Cypher interface:
d = {'name': 'Alice', 'age' : 22}
# quote string values
d = {k:"'{}'".format(v) if isinstance(v, basestring) else v
for k,v in d.items()}
cond = ' AND '.join("p.{}={}".format(prop, value) for prop, value in d.items())
query = "MATCH (p:Person) {condition} RETURN p"
query = query.format(condition=cond)
# "MATCH (p:Person) p.age=22 AND p.name='Alice' RETURN p"
results = graph.cypher.execute(query)
根据@elyase 的回答和原来的 py2neo.Graph.find,我制作了这段代码。请随时发表评论和改进.. :-)
def find_dict(graph, label, key_value=None, limit=None):
""" Iterate through a set of labelled nodes, optionally filtering
by property key/value dictionary
"""
if not label:
raise ValueError("Empty label")
from py2neo.cypher.lang import cypher_escape
if key_value is None:
statement = "MATCH (n:%s) RETURN n,labels(n)" % cypher_escape(label)
else:
# quote string values
d = {k: "'{}'".format(v) if isinstance(v, str) else v
for k, v in key_value.items()}
cond = ""
for prop, value in d.items():
if not isinstance(value, tuple):
value = ('=', value)
if cond == "":
cond += "n.{prop}{value[0]}{value[1]}".format(
prop=prop,
value=value,
)
else:
cond += " AND n.{prop}{value[0]}{value[1]}".format(
prop=prop,
value=value,
)
statement = "MATCH (n:%s ) WHERE %s RETURN n,labels(n)" % (
cypher_escape(label), cond)
if limit:
statement += " LIMIT %s" % limit
response = graph.cypher.post(statement)
for record in response.content["data"]:
dehydrated = record[0]
dehydrated.setdefault("metadata", {})["labels"] = record[1]
yield graph.hydrate(dehydrated)
response.close()
def find_dict_one(graph, label, key_value=None):
""" Find a single node by label and optional property. This method is
intended to be used with a unique constraint and does not fail if more
than one matching node is found.
"""
for node in find_dict(graph, label, key_value, limit=1):
return node
使用find_dict_one:
>>> a = find_dict_one(graph, 'Person', {'name': 'Lisa', 'age': 23})
>>> print(a)
(n1:Person {age:23,name:"Lisa"})
将 find_dict 与元组一起使用:
>>> a = find_dict(graph, 'Person', {'age': ('>', 21)}, 2) >>> for i in a:
>>> print(i)
(n2:Person {age:22,name:"Bart"})
(n1:Person {age:23,name:"Lisa"})
使用不带元组的 find_dict:
>>> a = find_dict(graph, 'Person', {'age': 22}, 2) >>> for i in a:
>>> print(i)
(n2:Person {age:22,name:"Bart"})