public IPathResult FindPaths(int node1Id, int node2Id, IPathFinderSettings settings) { if (settings == null) settings = PathFinderSettings.Default; var pathSteps = _pathFinderAuxiliaries.CacheService.GetMonitored(_graphDescriptor, MakeCacheKey("FindPaths.PathSteps." + node1Id + "/" + node2Id, settings), () => { TryInit(); var paths = _graphClient.Cypher .Start( new CypherStartBitWithNodeIndexLookupWithSingleParameter("n", WellKnownConstants.NodeIdIndexName, "id:" + node1Id), new CypherStartBitWithNodeIndexLookupWithSingleParameter("t", WellKnownConstants.NodeIdIndexName, "id:" + node2Id) ) .Match("path = (n)-[:" + WellKnownConstants.RelationshipTypeKey + "*1.." + settings.MaxDistance + "]-(t)") .Return<Path>("nodes(path) AS Nodes", CypherResultMode.Projection) // Taken from: http://craigbrettdevden.blogspot.co.uk/2013/03/retrieving-paths-in-neo4jclient.html .Results; return PathsToPathSteps(paths); }); return new Associativy.Services.PathFinderAuxiliaries.PathResult { SucceededPaths = pathSteps, SucceededGraph = PathToGraph(pathSteps, "PathToGraph:" + node1Id + "/" + node2Id, settings) }; }
public IQueryableGraph<int> GetPartialGraph(int centralNodeId, IPathFinderSettings settings) { if (settings == null) settings = PathFinderSettings.Default; return _pathFinderAuxiliaries.QueryableFactory.Create<int>((parameters) => { var graph = _pathFinderAuxiliaries.CacheService.GetMonitored(_graphDescriptor, QueryableGraphHelper.MakeCacheKey(MakeCacheKey("GetPartialGraph.BaseGraph." + centralNodeId, settings), parameters), () => { TryInit(); var paths = _graphClient.Cypher .StartWithNodeIndexLookup("n", WellKnownConstants.NodeIdIndexName, "id:" + centralNodeId) .Match("path = (n)-[:" + WellKnownConstants.RelationshipTypeKey + "*1.." + settings.MaxDistance + "]-()") .Return<Path>("nodes(path) AS Nodes", CypherResultMode.Projection) // Taken from: http://craigbrettdevden.blogspot.co.uk/2013/03/retrieving-paths-in-neo4jclient.html .Skip(parameters.Paging.SkipConnections) .Limit(parameters.Paging.TakeConnections) .Results; return _pathFinderAuxiliaries.PathToGraph(PathsToPathSteps(paths)); }); return QueryableGraphHelper.LastSteps(new LastStepParams { CacheService = _pathFinderAuxiliaries.CacheService, GraphEditor = _pathFinderAuxiliaries.GraphEditor, GraphDescriptor = _graphDescriptor, ExecutionParameters = parameters, Graph = graph, BaseCacheKey = MakeCacheKey("GetPartialGraph." + centralNodeId + ".PathToGraph.", settings) }); }); }
/// <summary> /// Returns a partial graph of the graph that starts from the center node and contains all paths within the specified range, containing the ids of the content items /// </summary> /// <param name="centralNodeId">The node paths will be calculated from</param> /// <param name="settings"></param> public static IQueryableGraph<int> GetPartialGraph(this IPathFinder pathFinder, IContent centralNode, IPathFinderSettings settings) { return pathFinder.GetPartialGraph(centralNode.ContentItem.Id, settings); }
private IQueryableGraph<int> PathToGraph(IEnumerable<IList<int>> succeededPaths, string baseCacheKey, IPathFinderSettings settings) { return _pathFinderAuxiliaries.QueryableFactory.Create<int>((parameters) => { var graph = _pathFinderAuxiliaries.CacheService.GetMonitored(_graphDescriptor, MakeCacheKey(baseCacheKey + "BaseGraph.", settings), () => { return _pathFinderAuxiliaries.PathToGraph(succeededPaths); }); return LastStepsWithPaging(parameters, graph, baseCacheKey, settings); }); }
private string MakeCacheKey(string name, IPathFinderSettings settings) { return CacheKeyPrefix + _graphDescriptor.Name + "." + name + ".PathFinderSettings:" + settings.MaxDistance + "."; }
private dynamic LastStepsWithPaging(IExecutionParams parameters, IUndirectedGraph<int, IUndirectedEdge<int>> graph, string cacheName, IPathFinderSettings settings) { return QueryableGraphHelper.LastStepsWithPaging(new LastStepParams { CacheService = _pathFinderAuxiliaries.CacheService, GraphEditor = _pathFinderAuxiliaries.GraphEditor, GraphDescriptor = _graphDescriptor, ExecutionParameters = parameters, Graph = graph, BaseCacheKey = MakeCacheKey(cacheName, settings) }); }
public virtual IPathResult FindPaths(int node1Id, int node2Id, IPathFinderSettings settings) { if (settings == null) settings = PathFinderSettings.Default; // This way we'll use the same cache no matter in which order the arguments are specified if (node2Id < node1Id) { var temp = node2Id; node2Id = node1Id; node1Id = temp; } var paths = _pathFinderAuxiliaries.CacheService.GetMonitored(_graphDescriptor, MakeCacheKey("FindPaths.Paths." + _graphDescriptor.Name + "/" + node1Id.ToString() + "/" + node2Id.ToString(), settings), () => { // This below is a depth-first search that tries to find all paths to the target node that are within the maximal length (maxDistance) and // keeps track of the paths found. var connectionManager = _graphDescriptor.Services.ConnectionManager; var explored = new Dictionary<int, PathNode>(); var succeededPaths = new List<List<int>>(); var frontier = new Stack<FrontierNode>(); var startNodeId = node1Id; var targetNodeId = node2Id; if (connectionManager.GetNeighbourCount(startNodeId) > connectionManager.GetNeighbourCount(targetNodeId)) { startNodeId = node2Id; targetNodeId = node1Id; } explored[startNodeId] = new PathNode(startNodeId) { MinDistance = 0 }; frontier.Push(new FrontierNode { Node = explored[startNodeId] }); FrontierNode frontierNode; PathNode currentNode; List<int> currentPath; int currentDistance; while (frontier.Count != 0) { frontierNode = frontier.Pop(); currentNode = frontierNode.Node; currentPath = frontierNode.Path; currentPath.Add(currentNode.Id); currentDistance = frontierNode.Distance; // We can't traverse the graph further if (currentDistance == settings.MaxDistance - 1) { // Target will be only found if it's the direct neighbour of current if (connectionManager.AreNeighbours(currentNode.Id, targetNodeId)) { if (!explored.ContainsKey(targetNodeId)) { explored[targetNodeId] = new PathNode(targetNodeId); } if (explored[targetNodeId].MinDistance > currentDistance + 1) { explored[targetNodeId].MinDistance = currentDistance + 1; } currentNode.Neighbours.Add(explored[targetNodeId]); currentPath.Add(targetNodeId); succeededPaths.Add(currentPath); } } // We can traverse the graph further else { // If we haven't already fetched current's neighbours, fetch them if (currentNode.Neighbours.Count == 0) { var neighbourIds = connectionManager.GetNeighbourIds(currentNode.Id); currentNode.Neighbours = new List<PathNode>(neighbourIds.Count()); foreach (var neighbourId in neighbourIds) { currentNode.Neighbours.Add(new PathNode(neighbourId)); } } foreach (var neighbour in currentNode.Neighbours) { // Target is a neighbour if (neighbour.Id == targetNodeId) { var succeededPath = new List<int>(currentPath) { targetNodeId }; // Since we will use currentPath in further iterations too succeededPaths.Add(succeededPath); } // We can traverse further, push the neighbour onto the stack else if (neighbour.Id != startNodeId) { neighbour.MinDistance = currentDistance + 1; if (!explored.ContainsKey(neighbour.Id) || neighbour.MinDistance >= currentDistance + 1) { frontier.Push(new FrontierNode { Distance = currentDistance + 1, Path = new List<int>(currentPath), Node = neighbour }); } } if (neighbour.Id != startNodeId) { // If this is the shortest path to the node, overwrite its minDepth if (neighbour.MinDistance > currentDistance + 1) { neighbour.MinDistance = currentDistance + 1; } explored[neighbour.Id] = neighbour; } } } } return succeededPaths; }); return new Associativy.Services.PathFinderAuxiliaries.PathResult { SucceededPaths = paths, SucceededGraph = PathToGraph(paths, "PathToGraph:" + node1Id + "/" + node2Id, settings) }; }
public virtual IQueryableGraph<int> GetPartialGraph(int centralNodeId, IPathFinderSettings settings) { if (settings == null) settings = PathFinderSettings.Default; return _pathFinderAuxiliaries.QueryableFactory.Create<int>((parameters) => { var graph = _pathFinderAuxiliaries.CacheService.GetMonitored(_graphDescriptor, MakeCacheKey("GetPartialGraph.BaseGraph." + centralNodeId, settings), () => { var connectionManager = _graphDescriptor.Services.ConnectionManager; var g = _pathFinderAuxiliaries.GraphEditor.GraphFactory<int>(); var visited = new Dictionary<int, PathNode>(); var frontier = new Stack<PathNode>(); frontier.Push(new PathNode(centralNodeId) { MinDistance = 0 }); while (frontier.Count != 0) { var current = frontier.Pop(); if (current.MinDistance == settings.MaxDistance) continue; if (!visited.ContainsKey(current.Id)) { visited[current.Id] = current; foreach (var neighbourId in connectionManager.GetNeighbourIds(current.Id)) { var neighbour = visited.ContainsKey(neighbourId) ? visited[neighbourId] : new PathNode(neighbourId); current.Neighbours.Add(neighbour); g.AddVerticesAndEdge(new UndirectedEdge<int>(current.Id, neighbourId)); } } var neighbourMinDistance = current.MinDistance + 1; foreach (var neighbour in current.Neighbours) { if (neighbourMinDistance < neighbour.MinDistance) { neighbour.MinDistance = neighbourMinDistance; frontier.Push(neighbour); } } } return g; }); return LastStepsWithPaging(parameters, graph, "GetPartialGraph." + centralNodeId + ".PathToGraph.", settings); }); }