本文共 4730 字,大约阅读时间需要 15 分钟。
neo4j简单学习 博客分类: java opensource 背景 最近在一些论坛或者新闻里看到了neo4j,一种擅长处理图形的数据库。 据说非常适合做一些join关系型的查询,所以抽空也看了下相关文档,给自己做个技术储备。 过程 深入学习之前,先在网上找了一下别人的一个学习文档总结,踩在别人的肩膀上总是最快,最有效的学习。 http://blog.csdn.net/gtuu0123/article/details/6384375 http://www.iteye.com/topic/978371 顺着这些思路,逐步查看一些neo4j的相关wiki文档,摘录了一张图: neo4j的基本模型图: 针对图中的一些基本概念: node : 节点 relationships : 关系,也就是图中的边,注意是有向边 properties : 属性,针对node/relationship都可以设置property Traversal : 图遍历工具 Indexes : 索引 通过node和relationship就可以组成一个有向图,通过property就可以使其带上对应的数据,成为对应的图像数据库。 node(节点) 每个节点可以和多个节点之间建立多个关系(relationship) 单个节点可以设置多个(Key,Value)的properties属性的键值对 relationships(关系) 每个关系都会包含一个startNode和endNode 每个关系可以设置多个(Key,Value)的properties属性的键值对 可以为关系定义对应的关系类型(RelationshipType) * DynamicRelationshipType 动态关系类型 * XXXRelationshipType 静态关系类型(实现了RelationshipType接口) Traversal(遍历) traverser : http://wiki.neo4j.org/content/Traversal 一个例子: Java代码 收藏代码 Traverser trav = swedenNode.traverse(Order.DEPTH_FIRST, StopEvaluator.END_OF_GRAPH, new ReturnableEvaluator() { public boolean isReturnableNode( TraversalPosition pos ) { return !pos.isStartNode() && pos.lastRelationshipTraversed().isType( CUSTOMER_TO_ORDER ); } }, LIVES_IN, Direction.INCOMING, CUSTOMER_TO_ORDER, Direction.OUTGOING ); // iterate over traverser... Order : 对应的图的遍历算法 DEPTH_FIRST : 深度优先搜索,就是找到第一个节点,递归的一直往下找,直到找不到合适的节点后,才进行回溯 BREADTH_FIRST : 广度优先搜索 Direction :对应图中edge的方向 OUTGOING : 出边 INCOMING : 入边 BOTH : 顾明思议 StopEvaluator : 定义图搜索的停止条件,默认有两个 DEPTH_ONE : 深度超过1后停止 END_OF_GRAPH : 无合适结果和停止 ReturnableEvaluator : 结果处理器,可以设置对应的返回结果,默认有: ALL_BUT_START_NODE : 排除初始节点 ALL : 返回所有节点 TraversalPosition : 对应搜索过程中的node节点信息,包括: 上一个节点信息 上一个进入的Relationship信息 搜索深度 目前为止满足条件的节点数 Indexs(索引) neo4j中针对每个node/relationship/property都是进行独立存储,都是按照自然的顺序。为了支持一些场景,比如针对关系型数据库的根据主键name查询对应的person node,普通的Traversal很难满足这样的需求,而且人家也不是用来解决这个事的。所以neo4j就引出了一个index的概念。 早期的版本的index是采用了IndexService(http://wiki.neo4j.org/content/Indexing_with_IndexService) 一个例子: Java代码 收藏代码 GraphDatabaseService graphDb = new EmbeddedGraphDatabase( "path/to/neo4j-db" ); IndexService index = new LuceneIndexService( graphDb ); Node andy = graphDb.createNode(); Node larry = graphDb.createNode(); andy.setProperty( "name", "Andy Wachowski" ); andy.setProperty( "title", "Director" ); larry.setProperty( "name", "Larry Wachowski" ); larry.setProperty( "title", "Director" ); index.index( andy, "name", andy.getProperty( "name" ) ); index.index( andy, "title", andy.getProperty( "title" ) ); index.index( larry, "name", larry.getProperty( "name" ) ); index.index( larry, "title", larry.getProperty( "title" ) ); IndexService是做为外部的component进行扩展定义。 现在官方文档中是建议使用Integrated Index Framework 官方文档: http://docs.neo4j.org/chunked/stable/indexing.html 迁移方案: http://wiki.neo4j.org/content/Transitioning_To_Index_Framework 新版本例子: Java代码 收藏代码 IndexManager index = graphDb.index(); Index actors = index.forNodes( "actors" ); Index movies = index.forNodes( "movies" ); RelationshipIndex roles = index.forRelationships( "roles" ); 从新版本中,已经将index做为其内核的实现,并不是外部扩展包的机制,从而可见其重要性阿,想了解具体的内容可以详细看下对应的官方文档。 查询语法(Cyphe Query Language) neo4j自己基于图论的搜索算法,实现了一套查询语言解析,提供了一些常见的聚合函数(max,sum,min,count等)。 语法例子: Java代码 收藏代码 Join查询: start n=(1) match (n)-[:BLOCKS]->(x) return x Where条件: start n=(2, 1) where (n.age < 30 and n.name = "Tobias") or not(n.name = "Tobias") return n 聚合函数: start n=(2,3,4) return avg(n.property) Order: start n=(1,2,3) return n order by n.name DESC 分页: start n=(1,2,3,4,5) return n order by n.name skip 1 limit 2 调用例子: Java代码 收藏代码 db = new ImpermanentGraphDatabase(); engine = new ExecutionEngine( db ); CypherParser parser = new CypherParser(); ExecutionEngine engine = new ExecutionEngine(db); Query query = parser.parse( "start n=(0) where 1=1 return n" ); ExecutionResult result = engine.execute( query ); assertThat( result.columns(), hasItem( "n" ) ); Iterator n_column = result.columnAs( "n" ); assertThat( asIterable( n_column ), hasItem(db.getNodeById(0)) ); assertThat( result.toString(), containsString("Node[0]") ); 其他 现在用nosql,除了一些功能feature问题,很重要的会是关注其他的两点扩展性&可用性 扩展性 暂时未看到有相应的扩展性方案 可用性(HA机制) 目前neo4j支持简单的ha机制,是通过zookeeper进行管理。 它的工作机制还是挺简单的,就是由zookeeper负责neo4j server的心跳检测。 1. 发现master挂了后,会发起一个选举(没看过源码,估摸着选举的实现也会很简单,根据对应的serverid,取最小的id做为新的master)。 2. 将新的master广播给所有的slave,此时在选举过程中,不接受对应的write请求(全都是返回异常) 3. 新机器加入集群后,会做为slave于master进行通讯,同步两者的数据内容(如果当前slave的tid比master新,会产生一个数据冲突此时需要进行手工干预) 存在的问题: 1. zookeeper心跳检测的及时性,默认为3分钟延迟(因为会有包重试) 2. master选举期间,write请求不可处理,直接返回异常(虽然master的选举时间会相对比较端,但对客户端不够友好) 可以改进的点: 1. 提供客户端的api,提供一种failover重试的机制控制。 Console页面 neo4j支持嵌入式和独立部署的两种模式,部署了一下neo4j独立部署server,效果图如下: 图形管理后台,可以方面查看节点之间的relationships rest接口的api,提供了图形和纯数据的几种方式: 其他文档 http://wiki.neo4j.org/content/FAQ http://wiki.neo4j.org/content/Getting_Started_With_Neo4j_Server neo4j-manual-stable.pdf