aplbrain / grand-cypher

Implementation of the Cypher language for searching NetworkX graphs
Apache License 2.0
78 stars 8 forks source link

Filtering within multiedges #48

Closed jackboyla closed 3 months ago

jackboyla commented 3 months ago

Mentioned in #47, if one edge satisfies a query constraints, ALL edges between the same two nodes are returned. This means the results are correct but they also come with information we didn't ask for:

from grandcypher import GrandCypher
import networkx as nx

host = nx.MultiDiGraph()
host.add_node("a", name="Alice", age=25)
host.add_node("b", name="Bob", age=30)
host.add_edge("a", "b", __labels__={"paid"}, amount=12, date="12th June")
host.add_edge("b", "a", __labels__={"paid"}, amount=6)
host.add_edge("b", "a", __labels__={"paid"}, value=14)
host.add_edge("a", "b", __labels__={"friends"}, years=9)
host.add_edge("a", "b", __labels__={"paid"}, amount=40)

qry = """
MATCH (n)-[r:paid]->(m)
RETURN n.name, m.name, r.amount
"""
res = GrandCypher(host).run(qry)
print(res)

'''
{
   'n.name': ['Alice', 'Bob'], 
   'm.name': ['Bob', 'Alice'], 
   'r.amount': [{(0, 'paid'): 12, (1, 'friends'): None, (2, 'paid'): 40}, {(0, 'paid'): 6, (1, 'paid'): None}]
}
'''

This PR should fix this, for both edge labels [r:paid] but also WHERE conditions:

from grandcypher import GrandCypher
import networkx as nx

host = nx.MultiDiGraph()
host.add_node("a", name="Alice", age=25)
host.add_node("b", name="Bob", age=30)
host.add_edge("a", "b", __labels__={"paid"}, value=20)
host.add_edge("a", "b", __labels__={"paid"}, amount=12, date="12th June")
host.add_edge("b", "a", __labels__={"paid"}, amount=6)
host.add_edge("b", "a", __labels__={"paid"}, value=14)
host.add_edge("a", "b", __labels__={"friends"}, years=9)
host.add_edge("a", "b", __labels__={"paid"}, amount=40)

qry = """
MATCH (n)-[r:paid]->(m)
WHERE r.amount > 12
RETURN n.name, m.name, r.amount
"""
res = GrandCypher(host).run(qry)
print(res)

'''
{
   'n.name': ['Alice'], 
   'm.name': ['Bob'], 
   'r.amount': [{(0, 'paid'): 40}]
}
'''