neo4j遍历和图算法
这篇blog主要和大家分享一下neo4j中是如何对节点进行遍历,和其中集成的图论的一些常用算法。
遍历
http://docs.neo4j.org.cn/tutorials-java-embedded-traversal.html 这是neo4j官方的中文教程。
- private static Traverser getFriends(Node node )
- {
- TraversalDescription td = Traversal.description()
- .breadthFirst()
- .relationships( RelTypes.KNOWS, Direction.OUTGOING )
- .evaluator( Evaluators.excludeStartPosition() );
- return td.traverse( node );
- }
private static Traverser getFriends(Node node ) { TraversalDescription td = Traversal.description() .breadthFirst() .relationships( RelTypes.KNOWS, Direction.OUTGOING ) .evaluator( Evaluators.excludeStartPosition() ); return td.traverse( node ); }TraversalDescription提供了用户遍历节点的方法,并且用户需要自己添加遍历的条件。
- int num = 0;
- String result = neoNode.getProperty( "name" ) + "'s friends:\n";
- Traverser friendsTraverser = getFriends( neoNode );
- for ( Path friendPath : friendsTraverser )
- {
- output += "At depth " + friendPath.length() + " => "
- + friendPath.endNode()
- .getProperty( "name" ) + "\n";
- numberOfFriends++;
- }
- output += "Number of friends found: " + numberOfFriends + "\n";
int num = 0; String result = neoNode.getProperty( "name" ) + "'s friends:\n"; Traverser friendsTraverser = getFriends( neoNode ); for ( Path friendPath : friendsTraverser ) { output += "At depth " + friendPath.length() + " => " + friendPath.endNode() .getProperty( "name" ) + "\n"; numberOfFriends++; } output += "Number of friends found: " + numberOfFriends + "\n";打印出结果
- Thomas Anderson's friends:
- At depth 1 => Trinity
- At depth 1 => Morpheus
- At depth 2 => Cypher
- At depth 3 => Agent Smith
- 找到朋友的数量: 4
Thomas Anderson's friends: At depth 1 => Trinity At depth 1 => Morpheus At depth 2 => Cypher At depth 3 => Agent Smith 找到朋友的数量: 4下面介绍如何按照一个预先定义好的顺序遍历图。
- Node A = db.createNode();
- Node B = db.createNode();
- Node C = db.createNode();
- Node D = db.createNode();
- A.createRelationshipTo( B, REL1 );
- B.createRelationshipTo( C, REL2 );
- C.createRelationshipTo( D, REL3 );
- A.createRelationshipTo( C, REL2 );
Node A = db.createNode(); Node B = db.createNode(); Node C = db.createNode(); Node D = db.createNode(); A.createRelationshipTo( B, REL1 ); B.createRelationshipTo( C, REL2 ); C.createRelationshipTo( D, REL3 ); A.createRelationshipTo( C, REL2 );现在关系(REL1-->REL2-->REL), 当遍历的时候,Evaluator能够对它进行检验,确保只有该关系顺序的路径才会被包括。
- ArrayList<RelationshipType> orderedPathContext = new ArrayList<RelationshipType>();
- orderedPathContext.add( REL1 );
- orderedPathContext.add( withName( "REL2" ) );
- orderedPathContext.add( withName( "REL3" ) );
- TraversalDescription td = Traversal.description()
- .evaluator( new Evaluator()
- {
- @Override
- public Evaluation evaluate( final Path path )
- {
- if ( path.length() == 0 )
- {
- return Evaluation.EXCLUDE_AND_CONTINUE;
- }
- RelationshipType expectedType = orderedPathContext.get( path.length() - 1 );
- boolean isExpectedType = path.lastRelationship()
- .isType( expectedType );
- boolean included = path.length() == orderedPathContext.size()
- && isExpectedType;
- boolean continued = path.length() < orderedPathContext.size()
- && isExpectedType;
- return Evaluation.of( included, continued );
- }
- } );
ArrayList<RelationshipType> orderedPathContext = new ArrayList<RelationshipType>(); orderedPathContext.add( REL1 ); orderedPathContext.add( withName( "REL2" ) ); orderedPathContext.add( withName( "REL3" ) ); TraversalDescription td = Traversal.description() .evaluator( new Evaluator() { @Override public Evaluation evaluate( final Path path ) { if ( path.length() == 0 ) { return Evaluation.EXCLUDE_AND_CONTINUE; } RelationshipType expectedType = orderedPathContext.get( path.length() - 1 ); boolean isExpectedType = path.lastRelationship() .isType( expectedType ); boolean included = path.length() == orderedPathContext.size() && isExpectedType; boolean continued = path.length() < orderedPathContext.size() && isExpectedType; return Evaluation.of( included, continued ); } } );打印出结果
- Traverser traverser = td.traverse( A );
- PathPrinter pathPrinter = new PathPrinter( "name" );
- for ( Path path : traverser )
- {
- output += Traversal.pathToString( path, pathPrinter );
- }
Traverser traverser = td.traverse( A ); PathPrinter pathPrinter = new PathPrinter( "name" ); for ( Path path : traverser ) { output += Traversal.pathToString( path, pathPrinter ); }用户也可以通过自定义格式输出路径。
- static class PathPrinter implements Traversal.PathDescriptor<Path>
- {
- private final String nodePropertyKey;
- public PathPrinter( String nodePropertyKey )
- {
- this.nodePropertyKey = nodePropertyKey;
- }
- @Override
- public String nodeRepresentation( Path path, Node node )
- {
- return "(" + node.getProperty( nodePropertyKey, "" ) + ")";
- }
- @Override
- public String relationshipRepresentation( Path path, Node from,
- Relationship relationship )
- {
- String prefix = "--", suffix = "--";
- if ( from.equals( relationship.getEndNode() ) )
- {
- prefix = "<--";
- }
- else
- {
- suffix = "-->";
- }
- return prefix + "[" + relationship.getType().name() + "]" + suffix;
- }
- }
static class PathPrinter implements Traversal.PathDescriptor<Path> { private final String nodePropertyKey;public PathPrinter( String nodePropertyKey ) { this.nodePropertyKey = nodePropertyKey; } @Override public String nodeRepresentation( Path path, Node node ) { return "(" + node.getProperty( nodePropertyKey, "" ) + ")"; } @Override public String relationshipRepresentation( Path path, Node from, Relationship relationship ) { String prefix = "--", suffix = "--"; if ( from.equals( relationship.getEndNode() ) ) { prefix = "<--"; } else { suffix = "-->"; } return prefix + "[" + relationship.getType().name() + "]" + suffix; }
}
图算法
- public Iterable<Path> findShortestPath(Node node1, Node node2) {
- PathFinder<Path> finder = GraphAlgoFactory.shortestPath(
- Traversal.expanderForTypes(RelTypes.KNOWS, Direction.BOTH), 10);
- Iterable<Path> paths = finder.findAllPaths(node1, node2);
- return paths;
- }
public Iterable<Path> findShortestPath(Node node1, Node node2) { PathFinder<Path> finder = GraphAlgoFactory.shortestPath( Traversal.expanderForTypes(RelTypes.KNOWS, Direction.BOTH), 10); Iterable<Path> paths = finder.findAllPaths(node1, node2); return paths; }
- for(Path shortestPath: findShortestPath(aa, ab)) {
- System.out.println(shortestPath.toString());
- }
for(Path shortestPath: findShortestPath(aa, ab)) { System.out.println(shortestPath.toString()); }Traversal.expanderForTypes用来定义遍历的深度和节点关系的出入度。
- PathFinder<WeightedPath> finder = GraphAlgoFactory.dijkstra(
- Traversal.expanderForTypes( ExampleTypes.MY_TYPE, Direction.BOTH ), "cost" );
- WeightedPath path = finder.findSinglePath( nodeA, nodeB );
- path.weight();
PathFinder<WeightedPath> finder = GraphAlgoFactory.dijkstra( Traversal.expanderForTypes( ExampleTypes.MY_TYPE, Direction.BOTH ), "cost" );WeightedPath path = finder.findSinglePath( nodeA, nodeB );
path.weight();
使用 A*算法是解决静态路网中求解最短路最有效的方法。
- Node nodeA = createNode( "name", "A", "x", 0d, "y", 0d );
- Node nodeB = createNode( "name", "B", "x", 7d, "y", 0d );
- Node nodeC = createNode( "name", "C", "x", 2d, "y", 1d );
- Relationship relAB = createRelationship( nodeA, nodeC, "length", 2d );
- Relationship relBC = createRelationship( nodeC, nodeB, "length", 3d );
- Relationship relAC = createRelationship( nodeA, nodeB, "length", 10d );
- EstimateEvaluator<Double> estimateEvaluator = new EstimateEvaluator<Double>()
- {
- public Double getCost( final Node node, final Node goal )
- {
- double dx = (Double) node.getProperty( "x" ) - (Double) goal.getProperty( "x" );
- double dy = (Double) node.getProperty( "y" ) - (Double) goal.getProperty( "y" );
- double result = Math.sqrt( Math.pow( dx, 2 ) + Math.pow( dy, 2 ) );
- return result;
- }
- };
- PathFinder<WeightedPath> astar = GraphAlgoFactory.aStar(
- Traversal.expanderForAllTypes(),
- CommonEvaluators.doubleCostEvaluator( "length" ), estimateEvaluator );
- WeightedPath path = astar.findSinglePath( nodeA, nodeB );
Node nodeA = createNode( "name", "A", "x", 0d, "y", 0d ); Node nodeB = createNode( "name", "B", "x", 7d, "y", 0d ); Node nodeC = createNode( "name", "C", "x", 2d, "y", 1d ); Relationship relAB = createRelationship( nodeA, nodeC, "length", 2d ); Relationship relBC = createRelationship( nodeC, nodeB, "length", 3d ); Relationship relAC = createRelationship( nodeA, nodeB, "length", 10d );EstimateEvaluator<Double> estimateEvaluator = new EstimateEvaluator<Double>()
{
public Double getCost( final Node node, final Node goal )
{
double dx = (Double) node.getProperty( "x" ) - (Double) goal.getProperty( "x" );
double dy = (Double) node.getProperty( "y" ) - (Double) goal.getProperty( "y" );
double result = Math.sqrt( Math.pow( dx, 2 ) + Math.pow( dy, 2 ) );
return result;
}
};
PathFinder<WeightedPath> astar = GraphAlgoFactory.aStar(
Traversal.expanderForAllTypes(),
CommonEvaluators.doubleCostEvaluator( "length" ), estimateEvaluator );
WeightedPath path = astar.findSinglePath( nodeA, nodeB );