暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

APOC,Neo4j的开发者宝藏

Neo4j与图数据库 2017-04-11
767

     熟悉Neo4j的朋友们都知道,Neo4j有一个非常好的工具集叫做APOC。叫这个名字是有来头的,APOC是电影《黑客帝国》Nebuchadnezzar号飞船上的技术员和司机,可惜后来被Cypher杀死(叫这个名字真是居心叵测啊。。。)。不过如果你把APOC理解成Awesome Procedures On Cypher(令人敬畏的Cypher程序)我也不反对,呵呵

放一张APOC的相片吧,快二十年前的电影了,各位老家伙们还有没有印象?

引入APOC的原因大致是这样的,由于从Neo4j 3.0版本开始引入了一些新的功能特性,包括用户自定义过程(procedures,有点类似于SQL的存储过程)和函数(Function)。当你使用Cypher不那么容易实现某些特定的功能的时候,你就可以使用过程来定制你的需求。由于这些程序是用Java实现的,所以可以很容易地部署到Neo4j实例中,然后直接通过Cypher调用。

大约一年前的Neo4j3.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安装包里面很长一段时间了。

过去,通过它的JavaREST 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(); }

}

使用构建工具(如mavengradleant)将代码打包成一个jar文件并将其复制到$NEO4J_HOME/plugins
确保将所需的依赖项添加到您的jarplugins目录中。


文章转载自Neo4j与图数据库,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论