neomodel icon indicating copy to clipboard operation
neomodel copied to clipboard

allShortestPaths

Open maxtepkeev opened this issue 10 years ago • 3 comments

Hi!

Thanks for the great package!

I'm trying to get allShortestPaths between two nodes with the following cypher query:

results, _ = db.cypher_query(
    "MATCH "
    "(from:Point {system_name: 'Point1'}), "
    "(to:Point {system_name: 'Point10'}), "
    "p = allShortestPaths(from-[:NEXT|CONNECTS_WITH*..100]-to) RETURN p"
)
print([Point.inflate(row[0]) for row in results])

During db.cypher_query execution the following exception is raised:

Traceback (most recent call last):
  File "/usr/local/projects/neo4j/python/lib/python3.4/site-packages/neomodel/util.py", line 195, in cypher_query
    results = self._execute_query(query, params)
  File "/usr/local/projects/neo4j/python/lib/python3.4/site-packages/neomodel/util.py", line 189, in _execute_query
    result = neo4j.CypherResults(cq._cypher._post({'query': query, 'params': params or {}}))
  File "/usr/local/projects/neo4j/python/lib/python3.4/site-packages/py2neo/neo4j.py", line 1139, in __init__
    for row in content["data"]
  File "/usr/local/projects/neo4j/python/lib/python3.4/site-packages/py2neo/neo4j.py", line 1139, in <listcomp>
    for row in content["data"]
  File "/usr/local/projects/neo4j/python/lib/python3.4/site-packages/neomodel/util.py", line 77, in _hydrated
    return type(data)([_hydrated(datum) for datum in data])
  File "/usr/local/projects/neo4j/python/lib/python3.4/site-packages/neomodel/util.py", line 77, in <listcomp>
    return type(data)([_hydrated(datum) for datum in data])
  File "/usr/local/projects/neo4j/python/lib/python3.4/site-packages/neomodel/util.py", line 75, in _hydrated
    raise NotImplemented("Don't know how to inflate: " + repr(data))
TypeError: 'NotImplementedType' object is not callable

Am I doing something wrong ?

maxtepkeev avatar Oct 05 '14 14:10 maxtepkeev

Hi @maxtepkeev could you provide a very simple test case for this?

I believe I need to add support for paths to neomodel

robinedwards avatar Oct 21 '14 18:10 robinedwards

hi @robinedwards I'm having the same error. Here is a stripped down version of the code which seems to be causing an error. I also have included the errors below, but they are: neo4j-community version 2.1.5 and neomodel 1.0.2

Let me know if you have any suggestions or if I'm just not doing this properly. Thanks


# pymodel example illustrating issues I've been having with getting shortest paths, or all shortest paths.

from neomodel import db
from neomodel import (StructuredNode, StringProperty, IntegerProperty, RelationshipTo, RelationshipFrom)


class Thing(StructuredNode):
    text = StringProperty(unique_index=True, required=True)
    connection = RelationshipFrom('Thing', 'connects')


def create_nodes():
    r = Thing(text="r").save()          # should be Node(0)
    e = Thing(text="e").save()          # should be Node(1)
    a = Thing(text="a").save()          # should be Node(2)
    d = Thing(text="d").save()          # should be Node(3)

    # let's make the word 'red'
    r.connection.connect(e)
    e.connection.connect(d)

    # let's make the word 'read'
    e.connection.connect(a)
    a.connection.connect(d)


def raw_cypher(query_string):
    return db.cypher_query(query_string)


def nm_cypher(query_string):
    results, meta = db.cypher_query(query_string)
    return [Thing.inflate(row[0]) for row in results]


def shortestPath(node1, node2):
    query_string = "START beginning=node("+str(node1)+"), end=node("+str(node2)+") MATCH p = shortestPath(beginning-[*..500]-end) RETURN p"
    raw_cypher(query_string)


"""
Test Commands:
# using neo4j-community version 2.1.5 and neomodel 1.0.2
$ export NEO4J_REST_URL=http://localhost:7474/db/data/
$ python

>> from pymodel_example import *
>> create_nodes()
>> shortestPath(0, 3)

Error:
Traceback (most recent call last):
  File "pymodel_example.py", line 46, in <module>
    shortestPath(0, 3)
  File "pymodel_example.py", line 38, in shortestPath
    raw_cypher(query_string)
  File "pymodel_example.py", line 28, in raw_cypher
    return db.cypher_query(query_string)
  File "/Library/Python/2.7/site-packages/neomodel/util.py", line 195, in cypher_query
    results = self._execute_query(query, params)
  File "/Library/Python/2.7/site-packages/neomodel/util.py", line 189, in _execute_query
    result = neo4j.CypherResults(cq._cypher._post({'query': query, 'params': params or {}}))
  File "/Library/Python/2.7/site-packages/py2neo/neo4j.py", line 1139, in __init__
    for row in content["data"]
  File "/Library/Python/2.7/site-packages/neomodel/util.py", line 77, in _hydrated
    return type(data)([_hydrated(datum) for datum in data])
  File "/Library/Python/2.7/site-packages/neomodel/util.py", line 75, in _hydrated
    raise NotImplemented("Don't know how to inflate: " + repr(data))
TypeError: 'NotImplementedType' object is not callable
"""

richardschwab avatar Oct 26 '14 07:10 richardschwab

@maxtepkeev, @richardschwab

This is an interesting feature for a number of reasons but while it is impossible to do exactly what you are after at the moment, writing a response for it made me realise a short and long term improvement we could have in neomodel.

So, the situation is this: Indeed, at the moment we are not resolving the Path data type which is what the Neo4j driver would return from the database for the sort of queries you indicate there. So:

  1. In the short term, you will be able to "unroll" the Path's relationships with the addition of something like return extract(rel in relationships(p)|rel). If you perform a neomodel.db.cypher_query with resolve_objects = True, this will return a list of your data model's relationship classes which naturally have their start and end nodes at their start_node, end_node attributes. This will be available after finalising this PR.

    • Also in the short term, I have been in the position where I had to return allShortestPaths results and I realised that I did not need all of the data from the path. I was able to return specific properties from the nodes and relationships of the path (again, via a cypher_query) which was enough for my use case.
  2. In the long term, it will be possible to resolve the Path data type. This is not too difficult, but in that case, the Path could present itself to the user as a starting Node. Anything contained in the Path would be readily available (because it has travelled from the db to the client) and anything else required would have to be fetched from the dbms with a request (e.g. upon hitting a node, a refresh() could be performed at will, to ensure that the Node is fully loaded from the db.).

Hope this helps.

aanastasiou avatar Mar 06 '19 16:03 aanastasiou

@aanastasiou didn't we recently merge something where we can now resolve Path objects ? If so, then I think we can close this.

mariusconjeaud avatar Sep 26 '23 15:09 mariusconjeaud

@mariusconjeaud , @maxtepkeev Yes, I just tried this and it should work from 5.1.1 owards.

aanastasiou avatar Oct 02 '23 15:10 aanastasiou