private IObject GetDbos(IDChainDefinition myIDChainDefinition, DBObjectStream myDBObjectStream, DBContext dbContext, SessionSettings mySessionToken, DBObjectCache dbObjectCache) { if (myIDChainDefinition.LastAttribute.IsBackwardEdge) { var contBackwardExcept = myDBObjectStream.ContainsBackwardEdge(myIDChainDefinition.LastAttribute.BackwardEdgeDefinition, dbContext, dbObjectCache, myIDChainDefinition.LastAttribute.GetRelatedType(dbContext.DBTypeManager)); if (contBackwardExcept.Failed()) throw new GraphDBException(contBackwardExcept.IErrors); if (contBackwardExcept.Value) { var beStream = dbObjectCache.LoadDBBackwardEdgeStream(myIDChainDefinition.LastType, myDBObjectStream.ObjectUUID).Value; if (beStream.ContainsBackwardEdge(myIDChainDefinition.LastAttribute.BackwardEdgeDefinition)) return beStream.GetBackwardEdges(myIDChainDefinition.LastAttribute.BackwardEdgeDefinition); else return null; } else { return null; } } else { if (myIDChainDefinition.LastAttribute.KindOfType == KindsOfType.SpecialAttribute) { return myDBObjectStream.GetAttribute(myIDChainDefinition.LastAttribute.UUID, myIDChainDefinition.LastAttribute.GetRelatedType(dbContext.DBTypeManager), dbContext); } else { return myDBObjectStream.GetAttribute(myIDChainDefinition.LastAttribute.UUID); } } }
/// <summary> /// Searches shortest, all shortest or all paths starting from "myStart" to "myEnd". /// </summary> /// <param name="myTypeAttribute">The Attribute representing the edge to follow (p.e. "Friends")</param> /// <param name="myTypeManager">The TypeManager for the Node type</param> /// <param name="myDBObjectCache">The Object Cache for faster object lookup</param> /// <param name="myStart">The start node</param> /// <param name="myEnd">The end node</param> /// <param name="shortestOnly">true, if only shortest path shall be found</param> /// <param name="findAll">if true and shortestOnly is true, all shortest paths will be found. if true, and shortest only is false, all paths will be searched</param> /// <param name="myMaxDepth">The maximum depth to search</param> /// <param name="myMaxPathLength">The maximum path length which shall be analyzed</param> /// <returns>A HashSet which contains all found paths. Every path is represented by a List of ObjectUUIDs</returns> public HashSet<List<ObjectUUID>> Find(TypeAttribute myTypeAttribute, DBTypeManager myTypeManager, DBObjectCache myDBObjectCache, DBObjectStream myStart, DBObjectStream myEnd, bool shortestOnly, bool findAll, byte myMaxDepth, byte myMaxPathLength) { #region data //queue for BFS Queue<Node> queue = new Queue<Node>(); //Dictionary to store visited TreeNodes BigDictionary<ObjectUUID, Node> visitedNodes = new BigDictionary<ObjectUUID, Node>(); //current depth byte depth = 0; //first node in path tree, the start of the select Node root = new Node(myStart.ObjectUUID); //root changed in Dictionary because of BidirectionalBFS HashSet<ObjectUUID> rootFriends = new HashSet<ObjectUUID>(); //target node, the target of the select Node target = new Node(myEnd.ObjectUUID); //holds the key of the backwardedge EdgeKey edgeKey = new EdgeKey(myTypeAttribute); //dummy node to check in which level the BFS is Node dummy = new Node(); //if the maxDepth is greater then maxPathLength, then set maxDepth to maxPathLength if (myMaxDepth > myMaxPathLength) { myMaxDepth = myMaxPathLength; } //enqueue first node to start the BFS queue.Enqueue(root); queue.Enqueue(dummy); //add root to visitedNodes visitedNodes.Add(root.Key, root); //holds the actual DBObject Exceptional<DBObjectStream> currentDBObject; #endregion #region BFS //Log start ////_Logger.Info("Starting BFS.."); //check if root node has edge and target has backwardedge var dbObject = myDBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myTypeManager), root.Key); if (dbObject.Failed()) { throw new NotImplementedException(); } if (!dbObject.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myTypeManager))) { ////_Logger.Info("Abort search! Start object has no edge!"); //Console.WriteLine("No paths found!"); return null; } var be = myDBObjectCache.LoadDBBackwardEdgeStream(myTypeAttribute.GetRelatedType(myTypeManager), target.Key); if (be.Failed()) { throw new NotImplementedException(); } if (!be.Value.ContainsBackwardEdge(edgeKey)) { ////_Logger.Info("Abort search! End object has no backwardedge!"); //Console.WriteLine("No paths found!"); return null; } //if there is more than one object in the queue and the actual depth is less than MaxDepth while ((queue.Count > 0) && (depth <= myMaxDepth)) { //get the first Object of the queue Node current = queue.Dequeue(); //dummy if (current.Key == null) { break; } //load DBObject currentDBObject = myDBObjectCache.LoadDBObjectStream(myTypeAttribute.GetRelatedType(myTypeManager), current.Key); if (currentDBObject.Failed()) { throw new NotImplementedException(); } if (currentDBObject.Value.HasAttribute(myTypeAttribute.UUID, myTypeAttribute.GetRelatedType(myTypeManager))) { if (myTypeAttribute.EdgeType is ASetOfReferencesEdgeType) { //get all referenced ObjectUUIDs using the given Edge var objectUUIDs = (currentDBObject.Value.GetAttribute(myTypeAttribute.UUID) as ASetOfReferencesEdgeType).GetAllReferenceIDs(); Node currentNode; foreach(ObjectUUID dbo in objectUUIDs) { //only for debug //var currentNodeObject = myTypeManager.LoadDBObject(myTypeAttribute.RelatedGraphType, dbo); //create a new node and set current = parent, currentNode = child currentNode = new Node(dbo, current); //if the child is the target if (currentNode.Key.Equals(myEnd.ObjectUUID)) { //node points on the target target.Parents.Add(current); //if shortestOnly == true we are finished here if(shortestOnly) { if (findAll) { //continue searching the current depth if there are any other shortest paths myMaxDepth = Convert.ToByte(depth); myMaxPathLength = Convert.ToByte(depth + 2); } else { ////_Logger.Info("found shortest path."); //got the shortest, finished return new TargetAnalyzer(root, rootFriends, target, myMaxPathLength, shortestOnly, findAll).getPaths(); } } } else { //been there before if (visitedNodes.ContainsKey(currentNode.Key)) { //if currentNode.Key isn't root set parent if (!rootFriends.Contains(currentNode.Key)) { //node has more then one parent visitedNodes[currentNode.Key].Parents.Add(current); } continue; } //never seen before //mark the node as visited visitedNodes.Add(currentNode.Key, currentNode); //and look what comes on the next level of depth queue.Enqueue(currentNode); //some logging if (queue.Count % 10000 == 0) { ////_Logger.Info(queue.Count + " elements enqueued.."); } } } } else if (myTypeAttribute.EdgeType is ASingleReferenceEdgeType) { throw new NotImplementedException(); } else { throw new NotImplementedException(); } } //if a new depth is reached if (queue.First() == dummy) { //enqueue the dummy at the end of to mark the next depth queue.Enqueue(queue.Dequeue()); //one step deeper in the dungen depth++; ////_Logger.Info("going deeper in the dungeon.. current level: " + depth); } } #endregion ////_Logger.Info("finished building path-graph.. starting analyzer"); //analyze paths return new TargetAnalyzer(root, rootFriends, target, myMaxPathLength, shortestOnly, findAll).getPaths(); }