熟悉Neo4j的朋友们都知道,Neo4j有一个非常好的工具集叫做APOC。叫这个名字是有来头的,APOC是电影《黑客帝国》中Nebuchadnezzar号飞船上的技术员和司机,可惜后来被Cypher杀死(叫这个名字真是居心叵测啊。。。)。不过如果你把APOC理解成Awesome Procedures On Cypher(令人敬畏的Cypher程序)我也不反对,呵呵
放一张APOC的相片吧,快二十年前的电影了,各位老家伙们还有没有印象?

引入APOC的原因大致是这样的,由于从Neo4j 3.0版本开始引入了一些新的功能特性,包括用户自定义过程(procedures,有点类似于SQL的存储过程)和函数(Function)。当你使用Cypher不那么容易实现某些特定的功能的时候,你就可以使用过程来定制你的需求。由于这些程序是用Java实现的,所以可以很容易地部署到Neo4j实例中,然后直接通过Cypher调用。
大约一年前的Neo4j的3.0版本里程碑阶段(关于版本介绍可以参考我的上一篇公众号文章),第一套图形重构程序开始出现,后续演变成APOC库,在Neo4j 3.0正式发行的版本中,大约有100个程序,到Neo4j 3.1版本时差不多有250个程序和功能,现在达到约300个。
这些程序,可以有效的帮助大家用于数据集成、图算法或数据转换等领域的许多不同任务。
如果您想了解更多有关现有APOC功能集的信息,请访问:
https://neo4j.com/developer/procedures-gallery/
不过,在访问上面的链接地址之前,还是要了解什么是用户自定义过程和函数,以及如何在Cypher中使用,如果你已经知道了,那就往下阅读吧。
APOC
首先申明一点,不同的APOC版本对应到的是不同的Neo4j版本,所以在使用APOC的过程和函数之前,先核对一下下面表格哦对应关系,别弄错了。
apoc version | neo4j version |
3.2.0.2 | 3.2.0-alpha07 (3.2.x) |
3.1.3.6 | 3.1.3 (3.1.x) |
3.1.2.5 | 3.1.2 |
3.1.0.4 | 3.1.0-3.1.1 |
3.0.8.6 | 3.0.5-3.0.9 (3.0.x) |
3.0.4.3 | 3.0.4 |
1.1.0 | 3.0.0 - 3.0.3 |
1.0.0 | 3.0.0 - 3.0.3 |
APOC涵盖了很多领域,以下只是APOC中一些程序的示例。
程序包 | 过程编号 | 过程名 | |
data api access | 11 | apoc.load.json(json-url) | |
database integration | 23 | apoc.load.jdbc(jdbc-url,table-or-statement) | |
graph algorithms | 18 | apoc.algo.dijkstra(from,to,cost-prop) | |
apoc.algo.pageRankStats({iterations:10,write:true}) | |||
(virtual) data creation | 16 | CALL apoc.create.relationship(startNode,'TYPE',{key:value,…}, endNode) | |
transaction control | 8 | apoc.periodic.iterate('source-query','work-statement',{batchSize:100, parallel:true}) | |
cypher operations | 9 | apoc.cypher.runFile(file or url) | |
graph data export | 9 | apoc.export.cypher.query(query,file,config) | |
graph generation | 5 | apoc.generate.ws(noNodes, degree, beta, 'label', 'TYPE') Watts-Strogatz | |
meta information | 4 | apoc.meta.stats() | |
time to live, node-expiry | 1 | CALL apoc.date.expire(node,100,'s'); | |
monitoring & operations | 6 | apoc.monitor.tx() | |
manual and schema indexes | 17 | apoc.index.between(node1,'TYPE',node2,'prop:value*') | |
cypher triggers on transaction end | 3 | apoc.trigger.add(name, statement, selector) | |
search and expand | 5 | apoc.path.expand(startNode, relationshipFilter, labelFilter, minDepth, maxDepth ) | |
以下是示例的函数:
包 | 功能数量 | 流行功能 | |
date & time conversion | 3 | apoc.date.parse("time",["unit"],["format"]) | |
number conversion | 3 | apoc.number.parse("number",["format"]) | |
general type conversion | 8 | apoc.convert.toMap(value) | |
type information and checking | 4 | apoc.meta.type(value) | |
collection and map functions | 25 | apoc.map.fromList(["k1",v1,"k2",v2,"k3",v3]) | |
JSON conversion | 4 | apoc.convert.toJson(value) | |
string functions | 7 | apoc.text.join(["s1","s2","s3"],"delim") | |
hash functions | 2 | apoc.util.md5(value) | |
大家可以阅读APOC 博客文章系列或观看有关APOC的演示文稿,了解APOC的更多信息。
APOC本身也有一个全面和文档网站,内容现在还在不断增长当中。
最近添加的Neo4j浏览器指南使您的工作环境中也可以提供该文档的部分内容。
只需在您的Neo4j浏览器运行下面的语句即可实现交互式学习。
:play http://guides.neo4j.com/apoc
Neo4j的空间过程(Spatial Procedures)
Neo4j的空间过程已经存在于Neo4j安装包里面很长一段时间了。
过去,通过它的Java或REST API来调用。现在,对于Neo4j 3.0来说,Craig Taverner已经增加了API的程序,将空间过程能与Cypher紧密集成在一起。
空间过程概述
Neo4j Spatial被打包成可以解压到$NEO4J_HOME/plugins目录中的ZIP文件。重新启动服务器后,您应该可以从Cypher 中进行以下过程的调用。
以下是按类型分组的一些最常用的程序。
类型 | 空间过程 | |
general | procedures() | |
layers | layer(layer),layers(), layerTypes() | |
add layers | addLayer(layer, type, config), addLayerWithEncoder(), addPointLayer(layer), addWKTLayer(name, property) | |
remove layers | removeLayer(layer) | |
add nodes | addNode(layer,node), addNodes(layer,nodes), updateFromWKT(layer,geometry,geoNodeId) | |
add geometries | addWKT(layer, geometry), addWKTs(layer,geometries) | |
find search | bbox(layer, min, max), closest(layer, coordinate, distance), intersects(layer, geometry), withinDistance(layer, coordinate, distance) | |
utilities | asGeometry, asExternalGeometry, decodeGeometry, getFeatureAttributes | |
import | importShapefile(uri), importShapefileToLayer(layer, uri) | |
开发自己的过程和函数
开发你的第一个函数
您可以在Neo4j手册中找到有关过程的编写和测试的详细信息。
甚至有一个GitHub样例库,具有详细的文档和注释,您可以直接克隆并作为起点来使用。
用户定义的函数更简单,所以我们来看一下下面:
@UserFunction annotated, named Java Methods
default name is class package + "." + method-name
take `@Name’ed parameters (with optional default values)
return a single value
are read only
can use @Context injected GraphDatabaseService etc
run within Transaction of the Cypher Statement
简单的用户定义uuid功能
@UserFunction("create.uuid")@Description("creates an UUID (universally unique id)")public String uuid() {return UUID.randomUUID().toString();
} 使用这样的函数
CREATE (p:Person {id: create.uuid(),name:{name}})
测试功能
Neo4j测试库neo4j-harness
使您可以启动Neo4j服务器,为数据设置提供灯具,并注册您的函数和过程。
然后通过Bolt协议调用并测试功能测试neo4j-java-driver
。
@Rule
public Neo4jRule neo4j = new Neo4jRule()
.withFunction( UUIDs.class );
...
try( Driver driver = GraphDatabase.driver( neo4j.boltURI() , config ) {Session session = driver.session();
String uuid = session.run("RETURN create.uuid() AS uuid").single().get( 0 ).asString();
assertThat( uuid,....);
}
写一个过程
用户定义过程和函数是相似的:
@Procedure annotated, Java methods
with an additional mode attribute (Read, Write, Dbms)
return a Stream of value objects (DTO) with public fields
value object fields are turned into result columns to be `YIELD`ed
从Java API中将dijkstra算法暴露给Cypher
@Procedure(mode = Write)
@Description("apoc.algo.dijkstra(startNode,endNode, 'KNOWS', 'distance') YIELD path," +
" weight - run dijkstra withrelationship property name as cost function")
public Stream<WeightedPathResult>dijkstra(
@Name("startNode") Node startNode,
@Name("endNode") Node endNode,
@Name("type") String type,
@Name("costProperty") String costProperty){
PathFinder<WeightedPath> algo = GraphAlgoFactory.dijkstra(
PathExpanders.forType(RelationshipType.withName(type)),
costProperty);
Iterable<WeightedPath> allPaths = algo.findAllPaths(startNode, endNode);
return Iterables.asCollection(allPaths).stream()
.map(WeightedPathResult::new);
}
public static class WeightedPathResult{
public final Path path;
public final double weight;
public WeightedPathResult(WeightedPath wp) { this.path = wp; this.weight= wp.weight(); }
}
使用构建工具(如maven,gradle,ant)将代码打包成一个jar文件并将其复制到$NEO4J_HOME/plugins
确保将所需的依赖项添加到您的jar或plugins目录中。





