这篇blog主要和大家分享一下neo4j中是如何对节点进行遍历,和其中集成的图论的一些常用算法。

遍历

http://docs.neo4j.org.cn/tutorials-java-embedded-traversal.html   这是neo4j官方的中文教程。

  1. private static Traverser getFriends(Node node )
  2. {
  3. TraversalDescription td = Traversal.description()
  4. .breadthFirst()
  5. .relationships( RelTypes.KNOWS, Direction.OUTGOING )
  6. .evaluator( Evaluators.excludeStartPosition() );
  7. return td.traverse( node );
  8. }
private static Traverser getFriends(Node node )
{
TraversalDescription td = Traversal.description()
.breadthFirst()
.relationships( RelTypes.KNOWS, Direction.OUTGOING )
.evaluator( Evaluators.excludeStartPosition() );
return td.traverse( node );
}

TraversalDescription提供了用户遍历节点的方法,并且用户需要自己添加遍历的条件。

首先用户可以定义是使用深度优先还收广度优先 breadthFirst() 和 depthFirst();relationships定义了遍历取得节点的关系类型,是入度Direction.INCOMING还是出度Direction.OUTGOING还是both;evaluator用来定义筛选的条件,比如去掉开始节点,结束节点,遍历深度(toDepth(3))等,具体可以参照官方的API文档。
  1. int num = 0;
  2. String result = neoNode.getProperty( "name" ) + "'s friends:\n";
  3. Traverser friendsTraverser = getFriends( neoNode );
  4. for ( Path friendPath : friendsTraverser )
  5. {
  6. output += "At depth " + friendPath.length() + " => "
  7. + friendPath.endNode()
  8. .getProperty( "name" ) + "\n";
  9. numberOfFriends++;
  10. }
  11. 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";

打印出结果

  1. Thomas Anderson's friends:
  2. At depth 1 => Trinity
  3. At depth 1 => Morpheus
  4. At depth 2 => Cypher
  5. At depth 3 => Agent Smith
  6. 找到朋友的数量: 4
Thomas Anderson's friends:
At depth 1 => Trinity
At depth 1 => Morpheus
At depth 2 => Cypher
At depth 3 => Agent Smith
找到朋友的数量: 4

下面介绍如何按照一个预先定义好的顺序遍历图。

创建一个数据库
  1. Node A = db.createNode();
  2. Node B = db.createNode();
  3. Node C = db.createNode();
  4. Node D = db.createNode();
  5. A.createRelationshipTo( B, REL1 );
  6. B.createRelationshipTo( C, REL2 );
  7. C.createRelationshipTo( D, REL3 );
  8. 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能够对它进行检验,确保只有该关系顺序的路径才会被包括。

  1. ArrayList<RelationshipType> orderedPathContext = new ArrayList<RelationshipType>();
  2. orderedPathContext.add( REL1 );
  3. orderedPathContext.add( withName( "REL2" ) );
  4. orderedPathContext.add( withName( "REL3" ) );
  5. TraversalDescription td = Traversal.description()
  6. .evaluator( new Evaluator()
  7. {
  8. @Override
  9. public Evaluation evaluate( final Path path )
  10. {
  11. if ( path.length() == 0 )
  12. {
  13. return Evaluation.EXCLUDE_AND_CONTINUE;
  14. }
  15. RelationshipType expectedType = orderedPathContext.get( path.length() - 1 );
  16. boolean isExpectedType = path.lastRelationship()
  17. .isType( expectedType );
  18. boolean included = path.length() == orderedPathContext.size()
  19. && isExpectedType;
  20. boolean continued = path.length() < orderedPathContext.size()
  21. && isExpectedType;
  22. return Evaluation.of( included, continued );
  23. }
  24. } );
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 );
}
} );

打印出结果

  1. Traverser traverser = td.traverse( A );
  2. PathPrinter pathPrinter = new PathPrinter( "name" );
  3. for ( Path path : traverser )
  4. {
  5. output += Traversal.pathToString( path, pathPrinter );
  6. }
Traverser traverser = td.traverse( A );
PathPrinter pathPrinter = new PathPrinter( "name" );
for ( Path path : traverser )
{
output += Traversal.pathToString( path, pathPrinter );
}

用户也可以通过自定义格式输出路径。

  1. static class PathPrinter implements Traversal.PathDescriptor<Path>
  2. {
  3. private final String nodePropertyKey;
  4. public PathPrinter( String nodePropertyKey )
  5. {
  6. this.nodePropertyKey = nodePropertyKey;
  7. }
  8. @Override
  9. public String nodeRepresentation( Path path, Node node )
  10. {
  11. return "(" + node.getProperty( nodePropertyKey, "" ) + ")";
  12. }
  13. @Override
  14. public String relationshipRepresentation( Path path, Node from,
  15. Relationship relationship )
  16. {
  17. String prefix = "--", suffix = "--";
  18. if ( from.equals( relationship.getEndNode() ) )
  19. {
  20. prefix = "<--";
  21. }
  22. else
  23. {
  24. suffix = "-->";
  25. }
  26. return prefix + "[" + relationship.getType().name() + "]" + suffix;
  27. }
  28. }
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 = "&lt;--";
}
else
{
suffix = "--&gt;";
}
return prefix + "[" + relationship.getType().name() + "]" + suffix;
}

}

 图算法

neo4j中集成了一些常用的图算法,包括最短路径,Dijkstra,A*算法。
最短路径
  1. public Iterable<Path> findShortestPath(Node node1, Node node2) {
  2. PathFinder<Path> finder = GraphAlgoFactory.shortestPath(
  3. Traversal.expanderForTypes(RelTypes.KNOWS, Direction.BOTH), 10);
  4. Iterable<Path> paths = finder.findAllPaths(node1, node2);
  5. return paths;
  6. }
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;
}
  1. for(Path shortestPath: findShortestPath(aa, ab)) {
  2. System.out.println(shortestPath.toString());
  3. }
for(Path shortestPath: findShortestPath(aa, ab)) {
System.out.println(shortestPath.toString());
}

Traversal.expanderForTypes用来定义遍历的深度和节点关系的出入度。

Dijkstra解决有向图中任意两个顶点之间的最短路径问题。
  1. PathFinder<WeightedPath> finder = GraphAlgoFactory.dijkstra(
  2. Traversal.expanderForTypes( ExampleTypes.MY_TYPE, Direction.BOTH ), "cost" );
  3. WeightedPath path = finder.findSinglePath( nodeA, nodeB );
  4. path.weight();
PathFinder<WeightedPath> finder = GraphAlgoFactory.dijkstra(
Traversal.expanderForTypes( ExampleTypes.MY_TYPE, Direction.BOTH ), "cost" ); WeightedPath path = finder.findSinglePath( nodeA, nodeB );

path.weight();

 使用 A*算法是解决静态路网中求解最短路最有效的方法。

  1. Node nodeA = createNode( "name", "A", "x", 0d, "y", 0d );
  2. Node nodeB = createNode( "name", "B", "x", 7d, "y", 0d );
  3. Node nodeC = createNode( "name", "C", "x", 2d, "y", 1d );
  4. Relationship relAB = createRelationship( nodeA, nodeC, "length", 2d );
  5. Relationship relBC = createRelationship( nodeC, nodeB, "length", 3d );
  6. Relationship relAC = createRelationship( nodeA, nodeB, "length", 10d );
  7. EstimateEvaluator<Double> estimateEvaluator = new EstimateEvaluator<Double>()
  8. {
  9. public Double getCost( final Node node, final Node goal )
  10. {
  11. double dx = (Double) node.getProperty( "x" ) - (Double) goal.getProperty( "x" );
  12. double dy = (Double) node.getProperty( "y" ) - (Double) goal.getProperty( "y" );
  13. double result = Math.sqrt( Math.pow( dx, 2 ) + Math.pow( dy, 2 ) );
  14. return result;
  15. }
  16. };
  17. PathFinder<WeightedPath> astar = GraphAlgoFactory.aStar(
  18. Traversal.expanderForAllTypes(),
  19. CommonEvaluators.doubleCostEvaluator( "length" ), estimateEvaluator );
  20. 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 );

 

neo4j遍历和图算法的更多相关文章

  1. 关于图计算&图学习的基础知识概览:前置知识点学习(Paddle Graph Learning (PGL))

    关于图计算&图学习的基础知识概览:前置知识点学习(Paddle Graph Learning (PGL)) 欢迎fork本项目原始链接:关于图计算&图学习的基础知识概览:前置知识点学习 ...

  2. 20172305 2018-2019-1 《Java软件结构与数据结构》第九周学习总结

    20172305 2018-2019-1 <Java软件结构与数据结构>第九周学习总结 教材学习内容总结 本周内容主要为书第十五章内容: 图(结点和结点之间的连接构成) 顶点:结点 边:结 ...

  3. CF-544:部分题目总结

    -------------------昨天打的重现赛,感觉是我打的发挥的最好的一场比赛了,六题都一次AC.那么就来总结一下吧 题目链接:http://codeforces.com/contest/11 ...

  4. Neo4j简介

    Neo4j简介 发表于2013年3月16日 11:52 p.m.    位于分类图数据库与图并行计算 现实中很多数据都是用图来表达的,比如社交网络中人与人的关系.地图数据.或是基因信息等等.RDBMS ...

  5. 为什么选择图形数据库,为什么选择Neo4j?

    最近在抓取一些社交网站的数据,抓下来的数据用MySql存储.问我为什么用MySql,那自然是入门简单,并且我当时只熟悉MySql.可是,随着数据量越来越大,有一个问题始终困扰着我,那就是社交关系的存储 ...

  6. 主流图数据库Neo4J、ArangoDB、OrientDB综合对比:架构分析

    主流图数据库Neo4J.ArangoDB.OrientDB综合对比:架构分析 YOTOY 关注 0.4 2017.06.15 15:11* 字数 3733 阅读 16430评论 2喜欢 18 1: 本 ...

  7. Neo4j

    Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中.它是一个嵌入式的.基于磁盘的.具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做 ...

  8. 图数据库neo4j和关系数据库的区别

    相信您和我一样,在使用关系型数据库时常常会遇到一系列非常复杂的设计问题.例如一部电影中的各个演员常常有主角配角之分,还要有导演,特效等人员的参与.通常情况下这些人员常常都被抽象为Person类型,对应 ...

  9. Neo4j图数据库管理系统开发笔记之一:Neo4j Java 工具包

    1 应用开发概述 基于数据传输效率以及接口自定义等特殊性需求,我们暂时放弃使用Neo4j服务器版本,而是在Neo4j嵌入式版本的基础上进行一些封装性的开发.封装的重点,是解决Neo4j嵌入式版本Emb ...

随机推荐

  1. 「题解」NOIP模拟测试题解乱写I(29-31)

    NOIP模拟29(B) T1爬山 简单题,赛时找到了$O(1)$查询的规律于是切了. 从倍增LCA那里借鉴了一点东西:先将a.b抬到同一高度,然后再一起往上爬.所用的步数$×2$就是了. 抬升到同一高 ...

  2. 数论,质因数,gcd——cf1033D 好题!

    直接筛质数肯定是不行的 用map<ll,ll>来保存质因子的指数 考虑只有3-5个因子的数的组成情况 必定是a=pq or a=p*p or a=p*p*p or a=p*p*p*p 先用 ...

  3. NOIP 2017 提高组 day1t2 时间复杂度

    P3952 时间复杂度 标签 NOIp提高组 2017 时空限制 1000ms / 128MB 小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂 ...

  4. Java-slf4j:sfl4j

    ylbtech-Java-slf4j:sfl4j 1.返回顶部 1. SLF4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种 ...

  5. Android之LinearLayout线性布局

    1.相关术语解释 orientation 子控件的排列方式,horizontal(水平)和vertical(垂直默认)两种方式! gravity 子控件的对齐方式,多个组合 layout_gravit ...

  6. JavaScript事件(随笔)

    1. Javascript事件介绍 JavaScript中的事件和现实生活中的事件类似,现实生活中发生的一些事情,例如:交通事件,当这些事情发生时,我们需要提供处理方案: 在JavaScript中事件 ...

  7. 群晖引导是uefi还是传统模式的识别

     看左下角光标闪不闪,不闪的是uefi,在闪的就是传统

  8. Install- Linux必学的60个命令

    1.作用 install命令的作用是安装或升级软件或备份数据,它的使用权限是所有用户. 2.格式 (1)install [选项]... 来源 目的地 (2)install [选项]... 来源... ...

  9. 高德地图定位不到 报错 location Error, ErrCode:7, errInfo:KEY错误 请到http://lbs.amap.com/api/android-location-sdk/abouterrorcode/查看错误码说明.

    出现该问题的可能是高德地图的配置不准确: 仔细配对一下 看sha1 是否是通过应用签名生成的  要区分发布版的sha1 跟调试版的sha1  是不相同的 (小编我第一次反这种错误的时候 是因为我把高得 ...

  10. [转]Expression Blend实例中文教程(8) - 动画设计快速入门StoryBoard

    上一篇,介绍了Silverlight动画设计基础知识,Silverlight动画是基于时间线的,对于动画的实现,其实也就是对对象属性的修改过程. 而Silverlight动画分类两种类型,From/T ...