finding shortest path that excludes particular edges?

◇◆丶佛笑我妖孽 提交于 2020-01-04 09:57:50

问题


I'm using Py2neo, but that probably doesn't matter since this will most likely need to be done by writing a Cypher query.

Essentially, I want to find a shortest path in a subgraph, where the subgraph is most of the whole graph but with a very small fraction (a millionth or less) of the edges removed.

For example, say I have nodes A, B, and C, and edges (A->B), (A->C), (B->C). Of course, the shortest path from A to C is via the direct connection. But if I wanted to find the shortest path that doesn't use that edge, it would have to be A B C.

Also, this will be something that a user can specify in a multi-user (web) application. So I can't really alter the database itself...if that weren't an issue, I could maybe create a property on edges "allow: true/false" and set it to false, but that would mess with application behavior for all current users.

A variation on that would be to have "disallow: sessionID1, sessionID230, sessionID1010", i.e. actually store which application sessions want to exclude that edge in the edge itself, but this also does not seem ideal.

Of course, I could actually implement the BFS in python by getting nodes as needed from neo4j and keeping them on a queue instead of having neo4j do the search, but surely that would be much slower, right?

Any thoughts? Thanks

EDIT: request to see code.

Below is how I'm currently getting the shortest path between two nodes that I first look up in an index. Now image there's also a list of edges (that is, unique relationships) that have to be ignored in the shortest path search.

from py2neo import neo4j

g = neo4j.GraphDatabaseService()

def shortest_path(a, b):
    a = g.get_indexed_node("worddex", "word", a)
    b = g.get_indexed_node("worddex", "word", b)
    if not a and b: return None
    query_string = "START beginning=node(%d), end=node(%d) MATCH p = shortestPath(beginning-[*..100]-end) RETURN p" % (a._id, b._id)
    result = neo4j.CypherQuery(g, query_string).execute()
    if not len(result): return None
    p = result[0].p
    ret = []
    for node in p.nodes:
        ret.append(node["word"])
    return ret

EDIT 2: example console: http://console.neo4j.org/r/3c1rgn

It's easy to find a shortest "friendship path" between any two people, but what if we want to find a shortest friendship path that doesn't involve a particular friendshi rel (or particular set of friendship rels), but without modifying the database first? e.g., we want to find the shortest friendship path from bob to joe wherein we momentarily assume bob and joe aren't friends themselves, nor are alice and janet.


回答1:


Can't you use the 'allShortestPaths' option in cypher and use it to reject paths which contain some specific rel types or node types using python? I guess it would depend on how and on what parameters you want to restrict results, and whether they can be detected using only what cypher returns to python in the form of a path.

Another way to do it would be to instruct Cypher to return ALL POSSIBLE PATHS from a node to another (some smart restrictions can be applied within the query itself here).

Then based on the collection of paths Cypher returns, you can run some Python code to reject paths which contain, say, a particular rel type or a node type that you are not interested in. You will then be left with a collection of possible paths fitting your acceptance criteria (except the shortest condition). You can then simply calculate the length of the path using python and use the smallest.

In fact, the length of the path can be returned by Cypher itself for all paths. This has already been asked before, so here is the question for your reference. The accepted answer to that question is what I am talking about.



来源:https://stackoverflow.com/questions/23239167/finding-shortest-path-that-excludes-particular-edges

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!