Traversal API is giving different result for seemingly same declaration. In method 1. I took method 1 sample from neo4j's site. And tried to restructure it in method 2. However, apparently there is not difference, both methods are producing different output. Method2 is completely skipping LIKE relationship. Even if I change the sequence in method1 like putting depthFirst() in last, the output changes.
It will be great if someone could please help me understand this different output?
Method 1:
void depthFirst() {
GraphDatabaseBuilder graphDbBuilder = new GraphDatabaseFactory()
.newEmbeddedDatabaseBuilder(storeDir);
GraphDatabaseService graphDb = graphDbBuilder.newGraphDatabase();
String output = "";
int i = 0;
try (Transaction tx = graphDb.beginTx()) {
Node node = graphDb.findNode(LabelTyeps.Person, "name", "Joe");
for (Path position : graphDb.traversalDescription().depthFirst()
.relationships(RelationshipTypes.KNOWS)
.relationships(RelationshipTypes.LIKES, Direction.INCOMING)
.evaluator(Evaluators.toDepth(5)).traverse(node)) {
output += position.toString() + ":"
+ (String) position.endNode().getProperty("name")
+ "\n";
}
System.out.println(output);
}
graphDb.shutdown();
}
Output of method 1:
(3):Joe
(3)<--[LIKES,1]--(8):Lisa
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4):Lars
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4)--[KNOWS,4]-->(7):Dirk
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4)--[KNOWS,4]-->(7)--[KNOWS,5]-->(6):Peter
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4)--[KNOWS,4]-->(7)--[KNOWS,5]-->(6)--[KNOWS,7]-->(5):Sara
(3)<--[LIKES,1]--(8)--[KNOWS,2]-->(4)<--[KNOWS,3]--(9):Ed
Method 2 (Just changed the way travDesc is structured)
try (Transaction tx = graphDb.beginTx()) {
Node node = graphDb.findNode(LabelTyeps.Person, "name", "Joe");
TraversalDescription travDesc = graphDb.traversalDescription();
travDesc.depthFirst();
travDesc.relationships(RelationshipTypes.KNOWS);
travDesc.relationships(RelationshipTypes.LIKES, Direction.INCOMING);
travDesc.evaluator(Evaluators.toDepth(5));
for (Path position : travDesc.traverse(node)) {
// System.out.println("Loop count: " + ++i);
output += position.toString() + ":"
+ (String) position.endNode().getProperty("name")
+ "\n";
// System.out.println(output);
}
System.out.println(output);
}
Output of method 2
(3):Joe
(3)--[KNOWS,6]-->(5):Sara
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6):Peter
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6)<--[KNOWS,5]--(7):Dirk
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6)<--[KNOWS,5]--(7)<--[KNOWS,4]--(4):Lars
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6)<--[KNOWS,5]--(7)<--[KNOWS,4]--(4)<--[KNOWS,3]--(9):Ed
(3)--[KNOWS,6]-->(5)<--[KNOWS,7]--(6)<--[KNOWS,5]--(7)<--[KNOWS,4]--(4)<--[KNOWS,2]--(8):Lisa
Sample data:
create (:Person {name:"Joe"})
,(:Person{name:"Lars"})
,(:Person{name:"Sara"})
,(:Person{name:"Peter"})
,(:Person{name:"Dirk"})
,(:Person{name:"Lisa"})
,(:Person{name:"Ed"})
match (a:Person{name:"Lisa"}), (b:Person{name:"Joe"}) create (a) - [:LIKES] -> (b)
match (a:Person{name:"Lisa"}), (b:Person{name:"Lars"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Ed"}), (b:Person{name:"Lars"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Lars"}), (b:Person{name:"Dirk"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Dirk"}), (b:Person{name:"Peter"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Joe"}), (b:Person{name:"Sara"}) create (a) - [:KNOWS] -> (b)
match (a:Person{name:"Peter"}), (b:Person{name:"Sara"}) create (a) - [:KNOWS] -> (b)
TraversalDescription is a immutable fluent API, quoting form http://neo4j.com/docs/java-reference/current/javadocs/org/neo4j/graphdb/traversal/TraversalDescription.html
A traversal description is immutable and each method which adds or modifies the behavior returns a new instances that includes the new modification, leaving the instance which returns the new instance intact.
Related
I'am trying to develop an algorithm using Pseudo code to display all possible routes between 2 Nodes. I have looked at the dijkstra algorithm but I'am having some difficulty trying to create an algorithm using only Pseudo Code.
Possible Routes Between node 7 and 5
I have identified all the possible Routes (Without passing the same node twice)
7 -> 4 -> 5
7 -> 6 -> 2 ->1 -> 8 -> 5
7-> 6 -> 4 -> 5
7 -> 6 -> 2 -> 1 -> 3 -> 5
Set of Nodes: 1,2,3,4,5,6,7,8
Link between Nodes 1+2, 1+3, 1+8, 2+6, 3+5, 4+5, 4+6, 4+7, 5+8, 6+7.
Using DFS: The idea is to do Depth First Traversal of given directed
graph. Start the traversal from source. Keep storing the visited
vertices in an array say ‘path[]’. If we reach the destination vertex,
print contents of path[]. The important thing is to mark current
vertices in path[] as visited also, so that the traversal doesn’t go
in a cycle.
Java Implementation:
// Prints all paths from
// 's' to 'd'
public void printAllPaths(int s, int d)
{
boolean[] isVisited = new boolean[v];
ArrayList pathList = new ArrayList<>();
//add source to path[]
pathList.add(s);
//Call recursive utility
printAllPathsUtil(s, d, isVisited, pathList);
}
// A recursive function to print
// all paths from 'u' to 'd'.
// isVisited[] keeps track of
// vertices in current path.
// localPathList<> stores actual
// vertices in the current path
private void printAllPathsUtil(Integer u, Integer d,
boolean[] isVisited,
List localPathList) {
// Mark the current node
isVisited[u] = true;
if (u.equals(d))
{
System.out.println(localPathList);
}
// Recur for all the vertices
// adjacent to current vertex
for (Integer i : adjList[u])
{
if (!isVisited[i])
{
// store current node
// in path[]
localPathList.add(i);
printAllPathsUtil(i, d, isVisited, localPathList);
// remove current node
// in path[]
localPathList.remove(i);
}
}
// Mark the current node
isVisited[u] = false;
}
You can check another ways here https://efficientcodeblog.wordpress.com/2018/02/15/finding-all-paths-between-two-nodes-in-a-graph/
I'm currently working on a graph where nodes are connected via probabilistic edges. The weight on each edge defines the probability of existence of the edge.
Here is an example graph to get you started
(A)-[0.5]->(B)
(A)-[0.5]->(C)
(B)-[0.5]->(C)
(B)-[0.3]->(D)
(C)-[1.0]->(E)
(C)-[0.3]->(D)
(E)-[0.3]->(D)
I would like to use the Neo4j Traversal Framework to traverse this graph starting from (A) and return the number of nodes that have been reached based on the probability of the edges found along the way.
Important:
Each node that is reached can only be counted once. -> If (A) reaches (B) and (C), then (C) need not reach (B). On the other hand if (A) fails to reach (B) but reaches (C) then (C) will attempt to reach (B).
The same goes if (B) reaches (C), (C) will not try and reach (B) again.
This is a discrete time step function, a node will only attempt to reach a neighboring node once.
To test the existence of an edge (whether we traverse it) we can generate a random number and verify if it's smaller than the edge weight.
I have already coded part of the traversal description as follows. (Here it is possible to start from multiple nodes but that is not necessary to solve the problem.)
TraversalDescription traversal = db.traversalDescription()
.breadthFirst()
.relationships( Rels.INFLUENCES, Direction.OUTGOING )
.uniqueness( Uniqueness.NODE_PATH )
.uniqueness( Uniqueness.RELATIONSHIP_GLOBAL )
.evaluator(new Evaluator() {
#Override
public Evaluation evaluate(Path path) {
// Get current
Node curNode = path.endNode();
// If current node is the start node, it doesn't have previous relationship,
// Just add it to result and keep traversing
if (startNodes.contains(curNode)) {
return Evaluation.INCLUDE_AND_CONTINUE;
}
// Otherwise...
else {
// Get current relationhsip
Relationship curRel = path.lastRelationship();
// Instantiate random number generator
Random rnd = new Random();
// Get a random number (between 0 and 1)
double rndNum = rnd.nextDouble();
// relationship wc is greater than the random number
if (rndNum < (double)curRel.getProperty("wc")) {
String info = "";
if (curRel != null) {
Node prevNode = curRel.getOtherNode(curNode);
info += "(" + prevNode.getProperty("name") + ")-[" + curRel.getProperty("wc") + "]->";
}
info += "(" + curNode.getProperty("name") + ")";
info += " :" + rndNum;
System.out.println(info);
// Keep node and keep traversing
return Evaluation.INCLUDE_AND_CONTINUE;
} else {
// Don't save node in result and stop traversing
return Evaluation.EXCLUDE_AND_PRUNE;
}
}
}
});
I keep track of the number of nodes reached like so:
long score = 0;
for (Node currentNode : traversal.traverse( nodeList ).nodes())
{
System.out.print(" <" + currentNode.getProperty("name") + "> ");
score += 1;
}
The problem with this code is that although NODE_PATH is defined there may be cycles which I don't want.
Therefore, I would like to know:
Is there is a solution to avoid cycles and count exactly the number of nodes reached?
And ideally, is it possible (or better) to do the same thing using PathExpander, and if yes how can I go about coding that?
Thanks
This certainly isn't the best answer.
Instead of iterating on nodes() I iterate on the paths, and add the endNode() to a set and then simply get the size of the set as the number of unique nodes.
HashSet<String> nodes = new HashSet<>();
for (Path path : traversal.traverse(nodeList))
{
Node currNode = path.endNode();
String val = String.valueOf(currNode.getProperty("name"));
nodes.add(val);
System.out.println(path);
System.out.println("");
}
score = nodes.size();
Hopefully someone can suggest a more optimal solution.
I'm still surprised though that NODE_PATH didn't not prevent cycles from forming.
I cannot understand the effectiveness of an algorithm in the Dart SDK.
Here is the algorithm (List factory in dart:core, file list.dart)
factory List.from(Iterable other, { bool growable: true }) {
List<E> list = new List<E>();
for (E e in other) {
list.add(e);
}
if (growable) return list;
int length = list.length;
List<E> fixedList = new List<E>(length);
for (int i = 0; i < length; i ) {
fixedList[i] = list[i];
}
return fixedList;
}
If growable is false then both lists will be created.
List<E> list = new List<E>();
List<E> fixedList = new List<E>(length);
But the creation of list #1 in this case is redundant because it's a duplicate of Iterable other. It just wastes CPU time and memory.
In this case this algorithm will be more efficient because it wont create an unnecessary list # 1 (growable is false).
factory List.from(Iterable other, { bool growable: true }) {
if(growable) {
List<E> list = new List<E>();
for (E e in other) {
list.add(e);
}
return list;
}
List<E> fixedList = new List<E>(other.length);
var i = 0;
for (E e in other) {
fixedList[i++] = e;
}
return fixedList;
}
Or am I wrong and missed some subtleties of programming?
We usually avoid invoking the length getter on iterables since it can have linear performance and side-effects. For Example:
List list = [1, 2, 3];
Iterable iterable1 = list.map((x) {
print(x);
return x + 1;
});
Iterable iterable2 = iterable1.where((x) => x > 2);
var fixedList = new List.from(iterable2, growable: false);
If List.from invoked the length getter it would run over all elements twice (where does not cache its result). It would furthermore execute the side-effect (printing 1, 2, 3) twice. For more information on Iterables look here.
Eventually we want to change the List.from code so that we avoid the second allocation and the copying. To do this we need (internal) functionality that transforms a growable list into a fixed-length list. Tracking bug: http://dartbug.com/9459
It looks like it was just an incremental update to the existing function.
See this commit and this diff
The function started just with
List<E> list = new List<E>();
for (E e in other) {
list.add(e);
}
and had some more bits added as part of a fairly major refactoring of numerous libraries.
I would say that the best thing to do is to raise a bug report on dartbug.com, and either add a patch, or commit a CL - see instructions here: https://code.google.com/p/dart/wiki/Contributing (Note, you do need to jump through some hoops first, but once you're set up, it's all good).
It might also be worth dropping a note to one of the committers or reviewers from the original commit to let them know your plans.
Does a pugixml node object have a number-of-child-nodes method? I cannot find it in the documentation and had to use an iterator as follows:
int n = 0;
for (pugi::xml_node ch_node = xMainNode.child("name"); ch_node; ch_node = ch_node.next_sibling("name")) n++;
There is no built-in function to compute that directly; one other approach is to use std::distance:
size_t n = std::distance(xMainNode.children("name").begin(), xMainNode.children("name").end());
Of course, this is linear in the number of child nodes; note that computing the number of all child nodes, std::distance(xMainNode.begin(), xMainNode.end()), is also linear - there is no constant-time access to child node count.
You could use an expression based on an xpath search (no efficiency guarantees, though):
xMainNode.select_nodes( "name" ).size()
int children_count(pugi::xml_node node)
{
int n = 0;
for (pugi::xml_node child : node.children()) n++;
return n;
}
I'm trying to use Propel's NestedSet feature. However, I'm missing something about inserting such that the tree is balanced as it is created (i.e. fill it in horizontally).
Say I have these elements:
root
r1c1 r1c2
r2c1 r2c2
I want to insert r2c3 as the 1st child of r1c2 (i.e. fill row 2 before starting on row 3).
My first stab at this was to create this function:
function where(User $root,$depth=0)
{
$num = $root->getNumberOfDescendants();
if ( $num < 2 )
return $root;
foreach($root->getChildren() as $d)
{
if ( $d->getNumberOfChildren() < 2 )
{
return $d;
}
}
foreach($root->getChildren() as $d)
{
return where($d, $depth+1);
}
}
However, this will insert a child on r2c1, rather at r1c2 as I want.
Is there a way to insert an entry into the tree at the next available spot somehow?
TIA
Mike
OK, thanks to http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/, I found that this algorithm will do what I want:
function where($root)
{
$num = $root->getNumberOfDescendants();
if ( $num < 2 )
return $root;
$finder = DbFinder::from('User')->
where('LeftId','>=',$root->getLeftId())->
where('RightId','<=',$root->getRightId())->
whereCustom('user.RightId = user.LeftId + ?',1,'left')->
whereCustom('user.RightId = user.LeftId + ?',3,'right')->
combine(array('left','right'),'or')->
orderBy('ParentId');
return $finder->findOne();
}
It basically executes this SQL:
SELECT u.*
FROM user u
WHERE u.LEFT_ID >= $left AND u.RIGHT_ID <= $right AND
(u.RIGHT_ID = u.LEFT_ID+1 OR u.RIGHT_ID = u.LEFT_ID+3)
ORDER BY u.PARENT_ID
LIMIT 1
A leaf has RIGHT=LEFT+1, A node with 1 child has RIGHT=LEFT+3. By adding the ORDER BY u.PARENT_ID, we find the highest node in the tree available. If you use LEFT_ID or RIGHT_ID, it does not balance the tree.