Neo4j 3.0 提供一个新的功能“存储过程”,该功能并不是Neo4j-Server的扩展,而是可以直接运行的。
在写这篇文章的时候,只能通过预备好的语句去执行
| 1 | CALL package.procedure(params) | 
 
 
 
但是接下来他会被完全集成到Cypher语句当中。这样我梦就可以通过CALL这个语句或者将它转换成方法表达式(这只是个人喜好)。
现在,“存储过程”只能使用Java(或者其他JVM语言)。你可能获说,“WTF  。。。java”, 其实java也没有那么一无是处。
一开始,在建立,编码,编译一个存储过程并不会花费太多的精力,只需要下载Neo4j 3.0, 3.0.0-M04 milestone或者最新的版本,同时JDK,Gradle或者Maven也需要安装。
我们可以直接使用Jake Hansson写好的一个模板neo4j-examples,这样可以更快的开始我们的第一个练习。
我们举一个简单的例子(GitHub Repository),你需要说明一下org.neo4j:neo4j:3.0.0[-M04]可以得到的取值范围,来获得必需的注释,然后Neo4j API才能讨论数据库。
| 2 |   <groupId>org.neo4j</groupId> | 
 
| 3 |   <artifactId>neo4j</artifactId> | 
 
| 4 |   <version>${neo4j.version}</version> | 
 
| 5 |   <scope>provided</scope> | 
 
 
 
 
 
Gradle 如下
| 5 | compile group: "org.neo4j", name:"neo4j", version:project.neo4j_version | 
 
| 6 | testCompile group: "org.neo4j", name:"neo4j-kernel", version:project.neo4j_version, classifier:"tests" | 
 
| 7 | testCompile group: "org.neo4j", name:"neo4j-io", version:project.neo4j_version, classifier:"tests" | 
 
| 8 | testCompile group: "junit", name:"junit", version:4.12 | 
 
 
 
 
 
如果你想写一些其他的程序,你只需要重新建立一个文件夹和新的类。
需要注意的是包和方法的名字变成了存储过程的名字(并不是类的名字)。
在我们的例子中,我们将写一个简单的存储过程来计算某个标签的最大和最小度数。
通过[@Context](/user/Context)标注可以讲Neo4j的 GraphDatabaseService 实例注入到你的类中。因为存储过程是无状态的,所以声明非注入非静态的字段是不允许的。
在我们的例子中,存储过程将命名为stats.degree,以CALL stats.degree('User')的形式进行调用。
| 03 | publicclassGraphStatistics { | 
 
| 05 |     [@Context](/user/Context)privateGraphDatabaseService db; | 
 
| 08 |     publicstaticclassDegree { | 
 
| 10 |         // note, that "int" values are not supported | 
 
| 11 |         publiclongcount, max, min = Long.MAX_VALUE; | 
 
| 13 |         // method to consume a degree and compute min, max, count | 
 
| 14 |         privatevoidadd(longdegree) { | 
 
| 15 |           if(degree < min) min = degree; | 
 
| 16 |           if(degree > max) max = degree; | 
 
| 21 |     [@Procedure](/user/Procedure) | 
 
| 22 |     publicStream<Degree> degree(String label) { | 
 
| 23 |         // create holder class for results | 
 
| 24 |         Degree degree = newDegree(label); | 
 
| 25 |         // iterate over all nodes with label | 
 
| 26 |         try(ResourceIterator it = db.findNodes(Label.label(label))) { | 
 
| 27 |             while(it.hasNext()) { | 
 
| 28 |                // submit degree to holder for consumption (i.e. max, min, count) | 
 
| 29 |                d.add(it.next().getDegree()); | 
 
| 32 |         // we only return a "Stream" of a single element in this case. | 
 
| 33 |         returnStream.of(degree); | 
 
 
 
 
 
如果你要快速的测试这个存储过程,又不想启动一个进程内服务端再连接上(比如,存储过程模板中演示的通过新的二进制的通信协议),你可以使用Neo4j测试工具集提供的Java API。
 
现在,我们可以写一个单元测试来测试下我们刚写的酷炫的存储过程。
| 03 | classGraphStatisticsTest { | 
 
| 04 |     [@Test](/user/Test)publicvoidtestDegree() { | 
 
| 05 |         // given Alice knowing Bob and Charlie and Dan knowing no-one | 
 
| 06 |         db.execute("CREATE (alice:User)-[:KNOWS]->(bob:User),(alice)-[:KNOWS]->(charlie:User),(dan:User)").close(); | 
 
| 08 |         // when retrieving the degree of the User label | 
 
| 09 |         Result res = db.execute("CALL stats.degree('User')"); | 
 
| 11 |         // then we expect one result-row with min-degree 0 and max-degree 2 | 
 
| 12 |         assertTrue(res.hasNext()); | 
 
| 13 |         Map<String,Object> row = res.next(); | 
 
| 14 |         assertEquals("User", row.get("label")); | 
 
| 16 |         assertEquals(0, row.get("min")); | 
 
| 17 |         // Alice knows 2 people | 
 
| 18 |         assertEquals(2, row.get("max")); | 
 
| 19 |         // We have 4 nodes in our graph | 
 
| 20 |         assertEquals(4, row.get("count")); | 
 
| 21 |         // only one result record was produced | 
 
| 22 |         assertFalse(res.hasNext()); | 
 
 
 
 
 
当然,你可以使用存储过程来生成更多的存储过程,比如其他原生支持JVM的语言,比如 JavaScript via Nashorn, Clojure,Groovy, Scala, Frege (Haskell), (J)Ruby or (J/P)ython。
我用JavaScript写了一个生成和运行存储过程的程序。
你还可以用存储过程做很多其他很酷的事情,比如下面列的资源。
如果你有写一些自己的存储过程的想法,请联系我们。
其他资源
 
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 
CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们