




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
PAGEPAGE172\o"第
15
章
Cypher查询语言"Cypher查询语言\o"第
4
章
在Java应用中使用Neo4j"在Java应用中使用Neo4j\o"第
9
章
在Python应用中使用Neo4j"在Python应用中使用Neo4j\o"第
5
章
Neo4j远程客户端库"远程客户端访问库\o"第
8
章
多语言支持"多语言支持\o"第
17
章
Neo4j服务器"Neo4j服务器\o"第
18
章
RESTAPI"RESTAPI目录前言I.简介1.Neo4j的亮点2.图数据库概要3.Neo4j图数据库II.教程4.在Java应用中使用Neo4j5.Neo4j远程客户端库6.遍历查询框架7.数据模型范例8.多语言支持9.在Python应用中使用Neo4j10.扩展Neo4j服务器III.参考11.性能12.事务管理13.数据导入14.索引15.Cypher查询语言16.图形算法17.Neo4j服务器18.RESTAPI19.在Python中使用Neo4j嵌入模式IV.操作20.安装和部署21.配置和调优22.高可用性模式23.备份24.安全25.监视服务器V.工具集26.基于Web的Neo4j图数据库管理工具27.Neo4j命令行VI.社区28.社区支持29.促进Neo4j发展A.联机帮助页A.1.neo4jA.2.neo4j-shellA.3.neo4j-backupA.4.neo4j-coordinatorA.5.neo4j-coordinator-shellB.常见问题第1章Neo4j的亮点作为一款强健的,可伸缩的高性能数据库,Neo4j最适合完整的企业部署或者用于一个轻量级项目中完整服务器的一个子集存在。它包括如下几个显著特点:完整的ACID支持高可用性轻易扩展到上亿级别的节点和关系通过遍历工具高速检索数据适当的ACID操作是保证数据一致性的基础。Neo4j确保了在一个事务里面的多个操作同时发生,保证数据一致性。不管是采用嵌入模式还是多服务器集群部署,都支持这一特性。更多详细的介绍,请参考章节:transactions。可靠的图型存储可以非常轻松的集成到任何一个应用中。随着我们开发的应用在运营中不断发展,性能问题肯定会逐步凸显出来,而Neo4j不管应用如何变化,他只会受到计算机硬件性能的影响,不受业务本身的约束。部署一个neo4j服务器便可以承载上亿级的节点和关系。当然,当单节点无法承载我们的数据需求时,我们可以进行分布式集群部署,详细的细节,请参考章节:ha。将图数据库用于存储关系复杂的数据是他最大的优势。通过Neo4j提供的遍历工具,可以非常高效的进行数据检索,每秒可以达到上亿级的检索量。一个检索操作类似于RDBMS里面的连接(_join_)操作。第2章图数据库概要这个章节包括一个对图数据模型的介绍以及将它与其他我们常见的数据持久化模型的比较。2.1.什么是图数据库?图数据库用图来存储数据,是最接近高性能的一种用于存储数据的数据结构方式之一。让我们跟随下面的图表,用他们来解释图数据库相关概念。我们将跟随图表中箭头方向来读懂图想表达的真正含义。2.1.1.一个图由无数的节点和关系组成“一张图–数据记录在→节点→包括的→属性里面”最简单的图是单节点的,一个记录,记录了一些属性。一个节点可以从单属性开始,成长为成千上亿,虽然会有一点点麻烦。从某种意义上讲,将数据用关系连接起来分布到不同节点上才是有意义的。2.1.2.关系将图各个部分组织起来“节点—被组织→关系—可以有→属性”关系可以将节点组织成任意的结构,允许一张图被组织成一个列表,一棵树,一张地图,或者一个复杂的实体–这个实体本身也是由复杂的,关系高度关联的结构组成。2.1.3.用Traversal进行数据库查询“一个Traversal—导航→一张图;他—标示→路径—包含→节点”一次Traversal,你可以理解为是你通过一种算法,从一些开始节点开始查询与其关联的节点,比如你想找到“我朋友喜欢但我不喜欢的那首音乐是什么呢?”,又或者“如果断电了,拿下服务器的服务会首影响?”等等问题。2.1.4.为节点和关系建立索引“一个索引—映射到→属性—属于→节点或者关系”经常,你想通过某一给定的属性值找到节点或者关系。比起通过遍历我们的图来书,用索引将会更加高效。比如“找到用户名是tony的用户”。2.1.5.Neo4j是一个图数据库“一个图数据库—管理→一张图和与图相关的→索引”Neo4j是一个有商业支持的开源图数据库。他被设计来用于拿下数据不断高速成长的数据存储,用高效的图数据结构代替传统的表设计。用Neo4j工作,您的应用将得到图的所有优越表现,以及您期望的高可靠性。2.2.比较各种数据库模型图数据库通过在一张图上存储节点和关系来持久化我们的数据结构。比起其他持久化数据模型如何呢?因为图是一种常规数据结构,让我们与其他的进行一下比较试试看。2.2.1.从图数据库转换成RDBMS将所有的数据用竖立的堆栈表示,并且保持他们直接的关系,你可以看到下面一张图。一个RDBMS被优化用于聚合数据,而Neo4j擅长于高度关联的数据。图2.1.RDBMS图2.2.用图实现RDBMS模型2.2.2.从图数据库转换成Key-Value数据库Key-Value模型适合用于简单的数据或者列表。当数据之间不断交互关联时,你更需要一张图模型。Neo4j让你能惊醒制作简单的数据结构到复杂,互相连接的数据。图2.3.Key-Value存储模型K*代表一个键,V*代表一个值。请注意,某些键指向其他键以及普通值。图2.4.用图实现Key-Value模型2.2.3.从图数据库转换成列数据库列式(大表)数据库是Key-Value模型的升级,用“”来允许行数据增加。如果存储一张图,这个表将是分层的,关系也是非常明确的。2.2.4.从图数据库转换成文档型数据库文档型数据库用文档进行层次划分,而自由的数据规划也很容易被表示成一颗树。成长为一张图的话,文档之间的关联你需要更有代表性的数据结构来存储,而在Neo4j中,这些关系是非常容易处理的。图2.5.文档型数据库D=文档,S=子文档,V=值,D2/S2=关联到(其他)文档的索引。图2.6.从图数据库转换成文档型数据库第3章Neo4j图数据库这个章节将讲述Neo4j模型和行为的更多细节。3.1.节点构成一张图的基本元素是节点和关系。在Neo4j中,节点和关系都可以包含\o"3.3.
属性"属性。节点经常被用于表示一些_实体_,但依赖关系也一样可以表示实体。下面让我们认识一个最简单的节点,他只有一个属性,属性名是name,属性值是Marko:3.2.关系节点之间的关系是图数据库很重要的一部分。通过关系可以找到很多关联的数据,比如节点集合,关系集合以及他们的\o"3.3.
属性"属性集合。一个关系连接两个节点,必须有一个开始节点和结束节点。因为关系总是直接相连的,所以对于一个节点来说,与他关联的关系看起来有输入/输出两个方向,这个特性对于我们遍历图非常有帮助:关系在任一方向都会被遍历访问。这意味着我们并不需要在不同方向都新增关系。而关系总是会有一个方向,所以当这个方向对你的应用没有意义时你可以忽略方向。特别注意一个节点可以有一个关系是指向自己的:为了将来增强遍历图中所有的关系,我们需要为关系设置类型。注意关键字type在这可能会被误解,你其实可以把他简单的理解为一个标签而已。下面的例子是一个有两种关系的最简单的社会化网络图。表3.1.使用到的关系和关系类型功能实现getwhoapersonfollowsoutgoingfollowsrelationships,depthonegetthefollowersofapersonincomingfollowsrelationships,depthonegetwhoapersonblocksoutgoingblocksrelationships,depthonegetwhoapersonisblockedbyincomingblocksrelationships,depthone下面的放里是一个简单的文件系统,包括一些符号软链接:根据你看到的,你在遍历的时候会用到关系的方向和关系的类型。WhatHowgetthefullpathofafileincomingfilerelationshipsgetallpathsforafileincomingfileandsymboliclinkrelationshipsgetallfilesinadirectoryoutgoingfileandsymboliclinkrelationships,depthonegetallfilesinadirectory,excludingsymboliclinksoutgoingfilerelationships,depthonegetallfilesinadirectory,recursivelyoutgoingfileandsymboliclinkrelationships3.3.属性节点和关系都可以设置自己的属性。属性是由Key-Value键值对组成,键名是字符串。属性值是要么是原始值,要么是原始值类型的一个数组。比如+String+,+int+和i+int[]+都是合法的。注意null不是一个合法的属性值。Nulls能代替模仿一个不存在的Key。表3.2.属性值类型TypeDescriptionValuerangebooleantrue/falsebyte8-bitinteger-128to127,inclusiveshort16-bitinteger-32768to32767,inclusiveint32-bitinteger-2147483648to2147483647,inclusivelong64-bitinteger-9223372036854775808to9223372036854775807,inclusivefloat32-bitIEEE754floating-pointnumberdouble64-bitIEEE754floating-pointnumberchar16-bitunsignedintegersrepresentingUnicodecharactersu0000touffff(0to65535)StringsequenceofUnicodecharacters如果要了解float/double类型的更多细节,请参考:JavaLanguageSpecification。3.4.路径路径由至少一个节点,通过各种关系连接组成,经常是作为一个查询或者遍历的结果。最短的路径是0长度的像下面这样:长度为1的路径如下:3.5.遍历(Traversal)遍历一张图就是按照一定的规则,跟随他们的关系,访问关联的的节点集合。最多的情况是只有一部分子图被访问到,因为你知道你对那一部分节点或者关系感兴趣。Neo4j提供了遍历的API,可以让你指定遍历规则。最简单的设置就是设置遍历是宽度优先还是深度优先。想对遍历框架有一个深入的了解,请参考章节:tutorial-traversal。想了解更多的Java代码范例,请参考章节:tutorials-java-embedded-traversal。其他查询图的方式还有cypher-query-lang,Cypher和gremlin-plugin,Gremlin。部分II.教程教程这部分将指导我们如何建立你的环境并使用Neo4j进行开发。它将从最简单的HelloWorld到图数据库的高级应用逐一介绍。第4章在Java应用中使用Neo4j在Java中采用嵌入方式使用Neo4j是非常方便的。在这个章节中,你将找到所有你想了解的—从基本环境的搭建到用你的数据做一些实际有用的事情。在Java应用中使用Neo4j是非常容易的。正这个章节中你将找到你需要的一切 — 从开发环境的建立到用你的数据做一些有用的事情。4.1.将Neo4j引入到你的项目工程中在选择了适合你的平台的editions,edition后,只需要引入Neo4j的jars文件到你的工程的构造路径中,你就可以在你的工程中使用Neo4j数据库了。下面的章节将展示如何完成引入,要么通过直接改变构造路径,要么使用包依赖管理。4.1.1.增加Neo4j的库文件到构造路径中可以通过下面任意一种方式得到需要的jar文件:解压Neo4j下载的压缩包,我们需要使用的jars文件都包括在lib目录中。直接使用Maven中心仓库的jars文件。将jars引入到你的项目工程中:JDKtools增加到-classpath中Eclipse右键点击工程然后选择BuildPath→ConfigureBuildPath。在对话框中选择AddExternalJARs,浏览到Neo4j的'lib/'目录并选择所有的jar文件。另外一种方式是使用UserLibraries。IntelliJIDEA看Libraries,GlobalLibraries,andtheConfigureLibrarydialog了解详情。NetBeans在工程的Libraries点击鼠标右键,选择AddJAR/Folder,浏览到Neo4j的'lib/'目录选择里面的所有jar文件。你也可以从工程节点来管理库文件。详细情况请查看管理一个工程的classpath。4.1.2.将Neo4j作为一个依赖添加想总览一下主要的Neo4j构件,请查看editions。列在里面的构件都是包含实际Neo4j实现的顶级构件。你既可以使用顶级构件也可以直接引入单个的组件。在这的范例使用的是顶级构件的方式。MavenMavendependency.123456789101112<project>...<dependencies><dependency><groupId>org.neo4j</groupId><artifactId>neo4j</artifactId><version>1.8</version></dependency>...</dependencies>...</project>参数artifactId可以在editions找到。EclipseandMaven在Eclipse中开发,推荐安装插件m2eplugin让Maven管理classpath来代替上面的方案。这样的话,你既可以通过Maven命令行来编译你的工程,也可以通过Maven命令自动生成一个Eclipse工作环境以便进行开发。Ivy确保能解决来自MavenCentral的依赖问题,比如我们在你的'ivysettings.xml'文件中使用下面的配置选项:1234567891011<ivysettings><settingsdefaultResolver="main"/><resolvers><chainname="main"><filesystemname="local"><artifactpattern="${ivy.settings.dir}/repository/[artifact]-[revision].[ext]"/></filesystem><ibiblioname="maven_central"root="/maven2/"m2compatible="true"/></chain></resolvers></ivysettings>有了这个,你就可以通过增加下面这些内容到你的'ivy.xml'中来引入Neo4j:1234567..<dependencies>..<dependencyorg="org.neo4j"name="neo4j"rev="1.8"/>..</dependencies>..参数name可以在editions找到。Gradle下面的范例演示了用Gradle生成一个脚本来引入Neo4j库文件。12345678defneo4jVersion="1.8"applyplugin:'java'repositories{mavenCentral()}dependencies{compile"org.neo4j:neo4j:${neo4jVersion}"}参数coordinates(在范例中的org.neo4j:neo4j)可以在editions找到。4.1.3.启动和停止为了创建一个新的数据库或者打开一个已经存在的,你需要实例化一个+EmbeddedGraphDatabase+对象。12graphDb=newGraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);registerShutdownHook(graphDb);注意EmbeddedGraphDatabase实例可以在多个线程中共享。然而你不能创建多个实例来指向同一个数据库。为了停止数据库,你需要调用方法shutdown():1graphDb.shutdown();为了确保Neo4j被正确关闭,你可以为它增加一个关闭钩子方法:1234567891011121314privatestaticvoidregisterShutdownHook(finalGraphDatabaseServicegraphDb){//RegistersashutdownhookfortheNeo4jinstancesothatit//shutsdownnicelywhentheVMexits(evenifyou"Ctrl-C"the//runningexamplebeforeit'scompleted)Runtime.getRuntime().addShutdownHook(newThread(){@Overridepublicvoidrun(){graphDb.shutdown();}});}如果你只想通过只读方式浏览数据库,请使用EmbeddedReadOnlyGraphDatabase。想通过配置设置来启动Neo4j,一个Neo4j属性文件可以像下面这样加载:1234GraphDatabaseServicegraphDb=newGraphDatabaseFactory().newEmbeddedDatabaseBuilder("target/database/location").loadPropertiesFromFile(pathToConfig+"perties").newGraphDatabase();或者你可以编程创建你自己的Map<String,String>来代替。想了解更多配置设置的细节,请参考:embedded-configuration。4.2.你好,世界正这里可以学习如何创建和访问节点和关系。关于建立工程环境的信息,请参考:\o"4.1.
将Neo4j引入到你的项目工程中"第4.1节“将Neo4j引入到你的项目工程中”。从\o"2.1.
什么是图数据库?"第2.1节“什么是图数据库?”中,我们还记得,一个Neo4j图数据库由以下几部分组成:相互关联的节点有一定的关系存在在节点和关系上面有一些属性。所有的关系都有一个类型。比如,如果一个图数据库实例表示一个社网络,那么一个关系类型可能叫KNOWS。如果一个类型叫KNOWS的关系连接了两个节点,那么这可能表示这两个人呼吸认识。一个图数据库中大量的语义都被编码成关系的类型来使用。虽然关系是直接相连的,但他们也可以不用考虑他们遍历的方向而互相遍历对方。提示范例源代码下载地址:EmbeddedNeo4j.java4.2.1.准备图数据库关系类型可以通过enum创建。正这个范例中我们之需要一个单独的关系类型。下面是我们的定义:1234privatestaticenumRelTypesimplementsRelationshipType{KNOWS}我们页准备一些需要用到的参数:1234GraphDatabaseServicegraphDb;NodefirstNode;NodesecondNode;Relationshiprelationship;下一步将启动数据库服务器了。逐一如果给定的保持数据库的目录如果不存在,那么它会自动创建。12graphDb=newGraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);registerShutdownHook(graphDb);注意:启动一个图数据库是一个非常重(耗费资源)的操作,所以不要每次你需要与数据库进行交互操作时都去启动一个新的实例。这个实例可以被多个线程共享。事务是线程安全的。就像你上面所看到的一样,我们注册了一个关闭数据库的钩子用来确保在JVM退出时数据库已经被关闭。现在是时候与数据库进行交互了。4.2.2.在一个事务中完成多次写数据库操作所有的写操作(创建,删除以及更新)都是在一个事务中完成的。这是一个有意的设计,因为我们相信事务是使用一个企业级数据库中非常重要的一部分。现在,在Neo4j中的事务处理是非常容易的:12345678910Transactiontx=graphDb.beginTx();try{//Updatingoperationsgoheretx.success();}finally{tx.finish();}要了解更多关于事务的细节,请参考:transactions和JavaAPI中的事务接口。4.2.3.创建一个小型图数据库现在,让我们来创建一些节点。API是非常直观的。你也随意查看在/neo4j/1.8/apidocs/的JavaDocs文档。它们也被包括正发行版中。这儿展示了如何创建一个小型图数据库,数据库中包括两个节点并用一个关系相连,节点和关系还包括一些属性:1234567firstNode=graphDb.createNode();firstNode.setProperty("message","Hello,");secondNode=graphDb.createNode();secondNode.setProperty("message","World!");relationship=firstNode.createRelationshipTo(secondNode,RelTypes.KNOWS);relationship.setProperty("message","braveNeo4j");现在我们有一个图数据库看起来像下面这样:图4.1.HelloWorld图数据库4.2.4.打印结果在我们创建我们的图数据库后,让我们从中读取数据并打印结果。123System.out.print(firstNode.getProperty("message"));System.out.print(relationship.getProperty("message"));System.out.print(secondNode.getProperty("message"));输出结果:Hello,braveNeo4jWorld!4.2.5.移除数据在这种情况下我们将在提交之前移除数据:1234//let'sremovethedatafirstNode.getSingleRelationship(RelTypes.KNOWS,Direction.OUTGOING).delete();firstNode.delete();secondNode.delete();注意删除一个仍然有关系的节点,当事务提交是会失败。这是为了确保关系始终有一个开始节点和结束节点。4.2.6.关闭图数据库最后,当应用完成后关闭数据库:1graphDb.shutdown();4.3.带索引的用户数据库你有一个用户数据库,希望通过名称查找到用户。首先,下面这是我们想创建的数据库结构:图4.2.用户节点空间预览其中,参考节点连接了一个用户参考节点,而真实的所有用户都连接在用户参考节点上面。提示范例中的源代码下载地址:EmbeddedNeo4jWithIndexing.java首先,我们定义要用到的关系类型:12345privatestaticenumRelTypesimplementsRelationshipType{USERS_REFERENCE,USER}然后,我们创建了两个辅助方法来处理用户名称以及往数据库新增用户:123456789101112privatestaticStringidToUserName(finalintid){return"user"+id+"@";}privatestaticNodecreateAndIndexUser(finalStringusername){Nodenode=graphDb.createNode();node.setProperty(USERNAME_KEY,username);nodeIndex.add(node,USERNAME_KEY,username);returnnode;}下一步我们将启动数据库:123graphDb=newGraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);nodeIndex=graphDb.index().forNodes("nodes");registerShutdownHook();是时候新增用户了:1234567891011121314Transactiontx=graphDb.beginTx();try{//CreateuserssubreferencenodeNodeusersReferenceNode=graphDb.createNode();graphDb.getReferenceNode().createRelationshipTo(usersReferenceNode,RelTypes.USERS_REFERENCE);//CreatesomeusersandindextheirnameswiththeIndexServicefor(intid=0;id<100;id++){NodeuserNode=createAndIndexUser(idToUserName(id));usersReferenceNode.createRelationshipTo(userNode,RelTypes.USER);}通过Id查找用户:12345intidToFind=45;NodefoundUser=nodeIndex.get(USERNAME_KEY,idToUserName(idToFind)).getSingle();System.out.println("Theusernameofuser"+idToFind+"is"+foundUser.getProperty(USERNAME_KEY));4.4.基本的单元测试Neo4j的单元测试的基本模式通过下面的范例来阐释。要访问Neo4j测试功能,你应该把neo4j-kernel'tests.jar'新增到你的类路径中。你可以从MavenCentral:org.neo4j:neo4j-kernel下载到需要的jars。使用Maven作为一个依赖管理,你通常会正pom.xml中增加依赖配置:Maven依赖.1234567891011121314<project>...<dependencies><dependency><groupId>org.neo4j</groupId><artifactId>neo4j-kernel</artifactId><version>${neo4j-version}</version><type>test-jar</type><scope>test</scope></dependency>...</dependencies>...</project>_${neo4j-version}是Neo4j的版本号。_到此,我们已经准备好进行单元测试编码了。提示范例源代码下载地址:Neo4jBasicTest.java每一次开始单元测试之前,请创建一个干净的数据库:12345@BeforepublicvoidprepareTestDatabase(){graphDb=newTestGraphDatabaseFactory().newImpermanentDatabaseBuilder().newGraphDatabase();}在测试完成之后,请关闭数据库:12345@AfterpublicvoiddestroyTestDatabase(){graphDb.shutdown();}在测试期间,创建节点并检查它们是否存在,并在一个事务中结束写操作。123456789101112131415161718192021222324252627Transactiontx=graphDb.beginTx();Noden=null;try{n=graphDb.createNode();n.setProperty("name","Nancy");tx.success();}catch(Exceptione){tx.failure();}finally{tx.finish();}//Thenodeshouldhaveanidgreaterthan0,whichistheidofthe//referencenode.assertThat(n.getId(),is(greaterThan(0l)));//Retrieveanodebyusingtheidofthecreatednode.Theid'sand//propertyshouldmatch.NodefoundNode=graphDb.getNodeById(n.getId());assertThat(foundNode.getId(),is(n.getId()));assertThat((String)foundNode.getProperty("name"),is("Nancy"));如果你想查看创建数据库的参数配置,你可以这样:12345Map<String,String>config=newHashMap<String,String>();config.put("neostore.nodestore.db.mapped_memory","10M");config.put("string_block_size","60");config.put("array_block_size","300");GraphDatabaseServicedb=newImpermanentGraphDatabase(config);4.5.遍历查询了解更多关于遍历查询的信息,请参考:tutorial-traversal。了解更多关于遍历查询范例的信息,请参考:\o"第
7
章
数据模型范例"第7章数据模型范例。4.5.1.黑客帝国对于上面的黑客帝国范例的遍历查询,这次使用新的遍历API:提示范例源代码下载地址:NewMatrix.java朋友以及朋友的朋友.123456789privatestaticTraversergetFriends(finalNodeperson){TraversalDescriptiontd=Traversal.description().breadthFirst().relationships(RelTypes.KNOWS,Direction.OUTGOING).evaluator(Evaluators.excludeStartPosition());returntd.traverse(person);}让我们只想一次真实的遍历查询并打印结果:1234567891011intnumberOfFriends=0;Stringoutput=neoNode.getProperty("name")+"'sfriends:\n";TraverserfriendsTraverser=getFriends(neoNode);for(PathfriendPath:friendsTraverser){output+="Atdepth"+friendPath.length()+"=>"+friendPath.endNode().getProperty("name")+"\n";numberOfFriends++;}output+="Numberoffriendsfound:"+numberOfFriends+"\n";输出结果:123456ThomasAnderson'sfriends:Atdepth1=>TrinityAtdepth1=>MorpheusAtdepth2=>CypherAtdepth3=>AgentSmith找到朋友的数量:4谁编写了黑客帝国?.12345678910privatestaticTraverserfindHackers(finalNodestartNode){TraversalDescriptiontd=Traversal.description().breadthFirst().relationships(RelTypes.CODED_BY,Direction.OUTGOING).relationships(RelTypes.KNOWS,Direction.OUTGOING).evaluator(Evaluators.includeWhereLastRelationshipTypeIs(RelTypes.CODED_BY));returntd.traverse(startNode);}打印输出结果:1234567891011Stringoutput="Hackers:\n";intnumberOfHackers=0;Traversertraverser=findHackers(getNeoNode());for(PathhackerPath:traverser){output+="Atdepth"+hackerPath.length()+"=>"+hackerPath.endNode().getProperty("name")+"\n";numberOfHackers++;}output+="Numberofhackersfound:"+numberOfHackers+"\n";现在我们知道是谁编写了黑客帝国:123Hackers:Atdepth4=>TheArchitect找到hackers的数量:1游走一个有序路径这个范例展示了如何通过一个路径上下文控制一条路径的表现。提示范例源代码下载地址:OrderedPath.java创建一个图数据库.12345678NodeA=db.createNode();NodeB=db.createNode();NodeC=db.createNode();NodeD=db.createNode();A.createRelationshipTo(B,REL1);B.createRelationshipTo(C,REL2);C.createRelationshipTo(D,REL3);A.createRelationshipTo(C,REL2);现在,关系(REL1→REL2→REL3)的顺序保存在一个ArrayList对象中。当遍历的时候,Evaluator能针对它进行检查,确保只有拥有预定义关系顺序的路径才会被包括并返回:定义如何游走这个路径.123456789101112131415161718192021222324finalArrayList<RelationshipType>orderedPathContext=newArrayList<RelationshipType>();orderedPathContext.add(REL1);orderedPathContext.add(withName("REL2"));orderedPathContext.add(withName("REL3"));TraversalDescriptiontd=Traversal.description().evaluator(newEvaluator(){@OverridepublicEvaluationevaluate(finalPathpath){if(path.length()==0){returnEvaluation.EXCLUDE_AND_CONTINUE;}RelationshipTypeexpectedType=orderedPathContext.get(path.length()-1);booleanisExpectedType=path.lastRelationship().isType(expectedType);booleanincluded=path.length()==orderedPathContext.size()&&isExpectedType;booleancontinued=path.length()<orderedPathContext.size()&&isExpectedType;returnEvaluation.of(included,continued);}});执行一次遍历查询并返回结果.123456Traversertraverser=td.traverse(A);PathPrinterpathPrinter=newPathPrinter("name");for(Pathpath:traverser){output+=Traversal.pathToString(path,pathPrinter);}输出结果:1(A)--[REL1]-->(B)--[REL2]-->(C)--[REL3]-->(D)在这种情况下我们使用一个自定义类来格式化路径输出。下面是它的具体实现:12345678910111213141516171819202122232425262728293031staticclassPathPrinterimplementsTraversal.PathDescriptor<Path>{privatefinalStringnodePropertyKey;publicPathPrinter(StringnodePropertyKey){this.nodePropertyKey=nodePropertyKey;}@OverridepublicStringnodeRepresentation(Pathpath,Nodenode){return"("+node.getProperty(nodePropertyKey,"")+")";}@OverridepublicStringrelationshipRepresentation(Pathpath,Nodefrom,Relationshiprelationship){Stringprefix="--",suffix="--";if(from.equals(relationship.getEndNode())){prefix="<--";}else{suffix="-->";}returnprefix+"["+relationship.getType().name()+"]"+suffix;}}为了了解更多关于Path的有选择的输出的细节,请参考:Traversal类。注意下面的范例使用了一个已经废弃的遍历API。它与新的遍历查询API共享底层实现,所以它们的性能是一样的。比较起来它提供的功能非常有限。4.5.2.老的遍历查询API这是我们想遍历查询的第一个图数据库:图4.3.黑客帝国节点空间预览提示范例源代码下载地址:Matrix.java朋友以及朋友的朋友.1234567privatestaticTraversergetFriends(finalNodeperson){returnperson.traverse(Order.BREADTH_FIRST,StopEvaluator.END_OF_GRAPH,ReturnableEvaluator.ALL_BUT_START_NODE,RelTypes.KNOWS,Direction.OUTGOING);}让我们执行一次真实的遍历查询并打印结果:123456789101112intnumberOfFriends=0;Stringoutput=neoNode.getProperty("name")+"'sfriends:\n";TraverserfriendsTraverser=getFriends(neoNode);for(NodefriendNode:friendsTraverser){output+="Atdepth"+friendsTraverser.currentPosition().depth()+"=>"+friendNode.getProperty("name")+"\n";numberOfFriends++;}output+="Numberoffriendsfound:"+numberOfFriends+"\n";下面是输出结果:123456ThomasAnderson的朋友们:Atdepth1=>TrinityAtdepth1=>MorpheusAtdepth2=>CypherAtdepth3=>AgentSmith一共找到朋友数量:4是谁编写了黑客帝国呢?12345678910111213141516privatestaticTraverserfindHackers(finalNodestartNode){returnstartNode.traverse(Order.BREADTH_FIRST,StopEvaluator.END_OF_GRAPH,newReturnableEvaluator(){@OverridepublicbooleanisReturnableNode(finalTraversalPositioncurrentPos){return!currentPos.isStartNode()&¤tPos.lastRelationshipTraversed().isType(RelTypes.CODED_BY);}},RelTypes.CODED_BY,Direction.OUTGOING,RelTypes.KNOWS,Direction.OUTGOING);}输出结果:123456789101112Stringoutput="Hackers:\n";intnumberOfHackers=0;Traversertraverser=findHackers(getNeoNode());for(NodehackerNode:traverser){output+="Atdepth"+traverser.currentPosition().depth()+"=>"+hackerNode.getProperty("name")+"\n";numberOfHackers++;}output+="Numberofhackersfound:"+numberOfHackers+"\n";现在我们知道是谁编写了黑客帝国:123Hackers:Atdepth4=>TheArchitect找到hackers的数量:14.5.3.在遍历查询中的唯一路径这个范例演示了节点唯一性的使用。下面是一个想象的有多个负责人的领域图,这些负责人有它们增加的宠物,而这些宠物又生产了它的后代。图4.4.后代范例图为了返回Pet0的所有后代,要求与Pet0必须有owns和Principal1关系(实际上只有Pet1和Pet3),遍历查询的Uniqueness应该设置成NODE_PATH来代替默认的NODE_GLOBAL以至于节点可以被遍历不止一次,而且那些有不同节点但能有一些相同的路径(比如开始节点和结束节点)也能被返回。1234567891011121314151617finalNodetarget=data.get().get("Principal1");TraversalDescriptiontd=Traversal.description().uniqueness(Uniqueness.NODE_PATH).evaluator(newEvaluator(){@OverridepublicEvaluationevaluate(Pathpath){if(path.endNode().equals(target)){returnEvaluation.INCLUDE_AND_PRUNE;}returnEvaluation.EXCLUDE_AND_CONTINUE;}});Traverserresults=td.traverse(start);这将返回下面的路径:12(3)--[descendant,0]-->(1)<--[owns,3]--(5)(3)--[descendant,2]-->(4)<--[owns,5]--(5)在path.toString()的默认实现中,(1)--[knows,2]-->(4)表示一个ID=1的节点通过一个ID=2,关系类型为knows的关系连接到了一个ID=4的节点上。让我们从一个旧的中创建一个新的TraversalDescription,并且设置uniqueness为NODE_GLOBAL来查看它们之间的区别。提示TraversalDescription对象是不变的,因此我们必须使用一个新的实例来返回新的uniqueness设置。12TraversalDescriptionnodeGlobalTd=td.uniqueness(Uniqueness.NODE_GLOBAL);results=nodeGlobalTd.traverse(start);现在只有一条路径返回:1(3)--[descendant,0]-->(1)<--[owns,3]--(5)4.5.4.社交网络注意:下面的范例使用了处于实验阶段的遍历查询API。社交网络(在互联网上也被称为社交图)是天然的用图来表示的模型。下面的范例演示了一个非常简单的社交模型,它连接了朋友并关注了好友动态。提示范例源代码下载地址:socnet简单的社交模型图4.5.社交网络数据模型一个社交网络的数据模型是简漂亮的:有名称的Persons和有时间戳文本的StatusUpdates。这些实体然后通过特殊的关系连接在一起。Personfriend:连接两个不同Person实例的关系(不能连接自己)status:连接到最近的StatusUpdateStatusUpdatenext:指向在主线上的下一个StatusUpdate,是在当前这个状态更新之前发生的状态图实例一个Person的StatusUpdate列表是一个链表。表头(最近动态)可以通过下一个status找到。每一个随后的StatusUpdate都通过关系next相连。这是一个AndreasKollegger微博记录图早上走路上班的范例:为了读取状态更新情况,我们可以创建一个遍历查询,比如:123TraversalDescriptiontraversal=Traversal.description().depthFirst().relationships(NEXT);这给了我们一个遍历查询,它将从一个StatusUpdate开始,并一直跟随状态的主线直到它们运行结束。遍历查询是懒加载模式所以当我们处理成千上万状态的时候性能一样很好 — 除非我们真实使用它们,否在它们不会被加载。活动流一旦我们有了朋友,而且它们有了状态消息,我们可能想读取我们的朋友的消息动态,按时间倒序排列 — 最新的动态在前面。为了实现这个,我们可以通过下面几个步骤:抓取所有的好友动态放入一个列表 — 最新的排前面。对列表进行排序。返回列表中的第一个记录。如果第一个迭代器为空,则把它从列表移除。否则,在这个迭代器中获取下一个记录。跳转到步骤2直到在列表中没有任何记录。这个队列看起来像这样。代码实现像这样:1234567891011121314PositionedIterator<StatusUpdate>first=statuses.get(0);StatusUpdatereturnVal=first.current();if(!first.hasNext()){statuses.remove(0);}else{first.next();sort();}returnreturnVal;4.6.领域实体这个地方演示了当使用Neo4j时控制领域实体的一个方法。使用的原则是将实体封装到节点上(这个方法也可以用在关系上)。提示范例源代码下载地址:Person.java马上,保存节点并且让它在包里可以被访问:1234567891011privatefinalNodeunderlyingNode;Person(NodepersonNode){this.underlyingNode=personNode;}protectedNodegetUnderlyingNode(){returnunderlyingNode;}分配属性给节点:1234publicStringgetName(){return(String)underlyingNode.getProperty(NAME);}确保重载这些方法:123456789101112131415161718@OverridepublicinthashCode(){returnunderlyingNode.hashCode();}@Overridepublicbooleanequals(Objecto){returnoinstanceofPerson&&underlyingNode.equals(((Person)o).getUnderlyingNode());}@OverridepublicStringtoString(){return"Person["+getName()+"]";}4.7.图算法范例提示范例源代码下载地址:PathFindingExamplesTest.java计算正连个节点之间的最短路径(最少数目的关系):12345678910111213141516NodestartNode=graphDb.createNode();NodemiddleNode1=graphDb.createNode();NodemiddleNode2=graphDb.createNode();NodemiddleNode3=graphDb.createNode();NodeendNode=graphDb.createNode();createRelationshipsBetween(startNode,middleNode1,endNode);createRelationshipsBetween(startNode,middleNode2,middleNode3,endNode);//WillfindtheshortestpathbetweenstartNodeandendNodevia//"MY_TYPE"relationships(inOUTGOINGdirection),likef.ex:////(startNode)-->(middleNode1)-->(endNode)//PathFinder<Path>finder=GraphAlgoFactory.shortestPath(Traversal.expanderForTypes(ExampleTypes.MY_TYPE,Direction.OUTGOING),15);Iterable<Path>paths=finder.findAllPaths(startNode,endNode);使用迪科斯彻(Dijkstra)算法解决有向图中任意两个顶点之间的最短路径问题。1234567PathFinder<WeightedPath>finder=GraphAlgoFactory.dijkstra(Traversal.expanderForTypes(ExampleTypes.MY_TYPE,Direction.BOTH),"cost");WeightedPathpath=finder.findSinglePath(nodeA,nodeB);//Gettheweightforthefoundpathpath.weight();使用A*算法是解决静态路网中求解最短路最有效的方法。这儿是我们的范例图:123456789101112131415161718192021NodenodeA=createNode("name","A","x",0d,"y",0d);NodenodeB=createNode("name","B","x",7d,"y",0d);NodenodeC=createNode("name","C","x",2d,"y",1d);RelationshiprelAB=createRelationship(nodeA,nodeC,"length",2d);RelationshiprelBC=createRelationship(nodeC,nodeB,"length",3d);RelationshiprelAC=createRelationship(nodeA,nodeB,"length",10d);EstimateEvaluator<Double>estimateEvaluator=newEstimateEvaluator<Double>(){publicDoublegetCost(finalNodenode,finalNodegoal){doubledx=(Double)node.getProperty("x")-(Double)goal.getProperty("x");doubledy=(Double)node.getProperty("y")-(Double)goal.getProperty("y");doubleresult=Math.sqrt(Math.pow(dx,2)+Math.pow(dy,2));returnresult;}};PathFinder<WeightedPath>astar=GraphAlgoFactory.aStar(Traversal.expanderForAllTypes(),CommonEvaluators.doubleCostEvaluator("length"),estimateEvaluator);WeightedPathpath=astar.findSinglePath(nodeA,nodeB);4.8.读取一个管理配置属性EmbeddedGraphDatabase类包括了一个/neo4j/1.8/apidocs/org/neo4j/kernel/EmbeddedGraphDatabase.html#getManagementBean%28java.lang.Class%29[方便的方法]来获取Neo4j管理用的beans。一般JMX服务也能使用,但比起你自己编码不如使用这概述的方法。提示范例源代码下载地址:JmxTest.java这个范例演示了如何得到一个图数据库的开始时间:12345678privatestaticDategetStartTimeFromManagementBean(GraphDatabaseServicegraphDbService){GraphDatabaseAPIgraphDb=(GraphDatabaseAPI)graphDbService;Kernelkernel=graphDb.getSingleManagementBean(Kernel.class);DatestartTime=kernel.getKernelStartTime();returnstartTime;}不同的Neo4j版本,你将使用不同的管理beans设置。了解所有Neo4j版本的信息,请参考:org.neo4j.jmx。了解Neo4j高级版和企业版的信息,请参考:org.neo4j.management。4.9.OSGi配置4.9.1.SimpleOSGiActivator脚本在OSGi关联的上下文比如大量的应用服务器(e.g.Glassfish)和基于Eclipse的系统中,Neo4j能被明确地建立起来而不是通过Java服务加载机制来发现。4.9.1.SimpleOSGiActivator脚本如同在下面的范例中看到的一样,为了代替依赖Neo4j内核的类加载,Neo4jBundle被作为库bundles,而像IndexProviders和CacheProviders这样的服务被明确地实例化,配置和注册了秩序。只需要确保必要的jars,所以所有必须的类都被导出并且包括这Activator。1234567891011121314151617181920212223242526272829303132333435363738394041424publicclassNeo4jActivatorimplementsBundleActivator{privatestaticGraphDatabaseServicedb;privateServiceRegistrationserviceRegistration;privateServiceR
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 塔城职业技术学院《数字化建筑设计概论》2023-2024学年第二学期期末试卷
- 吉林体育学院《钢琴即兴伴奏(3)》2023-2024学年第一学期期末试卷
- 山东省青岛市崂山区青岛第二中学2025年高考模拟语文试题试卷含解析
- 浙江警察学院《预防医学新》2023-2024学年第二学期期末试卷
- 承德医学院《文学创作与实践》2023-2024学年第二学期期末试卷
- 安徽省六安二中、霍邱一中、金寨一中2025年招生全国统一考试复习检测试题(一)生物试题含解析
- 新疆农业大学《航天测控技术》2023-2024学年第二学期期末试卷
- 山西经贸职业学院《大学体育三》2023-2024学年第二学期期末试卷
- 广州华立科技职业学院《文化项目管理》2023-2024学年第一学期期末试卷
- 苏州市职业大学《公共空间室内设计》2023-2024学年第二学期期末试卷
- 电力建设工程施工安全管理导则
- JTG-QB-003-2003公路桥涵标准图钢筋混凝土盖板涵
- 少儿绘画之《春江水暖鸭先知》
- 2022中医医院章程(完整版)
- 2020 ACLS-PC-SA课前自我测试试题及答案
- QGDW 1168-2013 输变电设备状态检修试验规程(高清版)
- 10000中国普通人名大全
- 第二代身份证号码验证器
- GB_T 229-2020 金属材料夏比摆锤冲击试验方法
- 施工组织设计双代号时标网络图
- 财政部金融企业不良资产批量转让管理办法(财金[2012]6号)
评论
0/150
提交评论