第 5 章 Neo4j 远程客户端库

优质
小牛编辑
126浏览
2023-12-01

包括Java范例在内的这些内容向我们展示了一个在Java中使用Neo4j REST API的更``低级``的方法。

要获取更多信息,请浏览下面的介绍。

5.1. 由社区贡献的Neo4j REST客户端

表 5.1. 由社区贡献的Neo4j REST客户端。

名称

语言 / 框架

地址

Java-Rest-Binding

Java

https://github.com/neo4j/java-rest-binding/

Neo4jClient

.NET

http://hg.readify.net/neo4jclient/

Neo4jRestNet

.NET

https://github.com/SepiaGroup/Neo4jRestNet

py2neo

Python

http://py2neo.org/

Bulbflow

Python

http://bulbflow.com/

neo4jrestclient

Python

https://github.com/versae/neo4j-rest-client

neo4django

Django

https://github.com/scholrly/neo4django

Neo4jPHP

PHP

https://github.com/jadell/Neo4jPHP

neography

Ruby

https://github.com/maxdemarzi/neography

Neoid

Ruby

https://github.com/elado/neoid

node.js

JavaScript

https://github.com/thingdom/node-neo4j

Neocons

Clojure

https://github.com/michaelklishin/neocons

5.2. 在Java中如何使用REST API

5.2.1. 通过 REST API 创建一个图数据库

REST API使用HTTP协议和JSON数据格式,以至于它能用于多种语言和平台。当准备开始使用的时候,看一些可以被重用的模式也是非常有帮助的。在这个简短的概述中,我们将为你展示如何使用 REST API 创建和维护一个简单的图数据库并且如何从中查询数据。

对于这些范例,我们选择了 Jersey客户端组件,这个组件之前我们已经通过Maven 下载了。 For these examples, we’ve chosen the Jerseyclient components, which are easily downloadedvia Maven.

5.2.2. 启动图数据库服务器

在我们对服务器做任何操作之前,我们需要启动它。了解服务器安装的详细信息,请参考:server-installation。

1

2

3

4

5

6

7

WebResource resource = Client.create()

.resource( SERVER_ROOT_URI );

ClientResponse response = resource.get( ClientResponse.class);

System.out.println( String.format( "GET on [%s], status code [%d]",

SERVER_ROOT_URI, response.getStatus() ) );

response.close();

如果返回状态码是 +200 OK+,那我们知道服务器已经运行良好而我们也能继续了。如果连接到服务器失败,请参考:server。

注意:如果你得到任何大于 +200 OK+(特别是 +4xx+和 +5xx+)的返回码,那么请检查你的配置并且查看在目录'data/log'的日志文件。

5.2.3. 创建一个节点

REST API使用+POST+方式创建节点。在Java中使用Jersey客户端封装是很简单的:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

finalString nodeEntryPointUri = SERVER_ROOT_URI + "node";

// http://localhost:7474/db/data/node

WebResource resource = Client.create()

.resource( nodeEntryPointUri );

// POST {} to the node entry point URI

ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )

.type( MediaType.APPLICATION_JSON )

.entity( "{}")

.post( ClientResponse.class);

finalURI location = response.getLocation();

System.out.println( String.format(

"POST to [%s], status code [%d], location header [%s]",

nodeEntryPointUri, response.getStatus(), location.toString() ) );

response.close();

returnlocation;

如果请求成功完成,它会在后台发送一个包括SON格式的数据的HTTP请求到图数据库服务器。这服务器将会在数据库中创建一个新的节点并且返回一个状态码 +201 Created+和一个包含新节点地址的 +Location+头信息。

在我们的范例中,我们将调用两次这个功能以便在我们的数据库中创建两个节点。

5.2.4. 增加属性

一旦我们在我们的数据库中有了节点,我们能用他们存储有用的数据。在这种情况下,我们将在我们的数据库中存储关于音乐的信息。让我们先看看我们创建节点和增加属性的代码。这儿我们已经增加了一个节点用来表示”Joe Strummer“和一个乐队“The Clash”。

1

2

3

4

URI firstNode = createNode();

addProperty( firstNode, "name", "Joe Strummer");

URI secondNode = createNode();

addProperty( secondNode, "band", "The Clash");

在 +addProperty+方法内部我们确定了表示节点属性的资源以及这个属性的名称。我们然后 +PUT+那个属性的值到服务器。

1

2

3

4

5

6

7

8

9

10

11

12

13

String propertyUri = nodeUri.toString() + "/properties/"+ propertyName;

// http://localhost:7474/db/data/node/{node_id}/properties/{property_name}

WebResource resource = Client.create()

.resource( propertyUri );

ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )

.type( MediaType.APPLICATION_JSON )

.entity( "\""+ propertyValue + "\"")

.put( ClientResponse.class);

System.out.println( String.format( "PUT to [%s], status code [%d]",

propertyUri, response.getStatus() ) );

response.close();

如果一切运行正常,我们将得到一个 204 No Content的返回码表示服务器已经处理了我们的情况但并不会回显属性的值。

5.2.5. 增加关系

现在我们有了表示Joe Strummer 和 The Clash的节点,我们将给他们建立关系。 REST API支持通过一个 +POST+请求来为节点间建立关系。在Java中与此相对应,我们 +POST+一些JSON数据到表示Joe Strummer的节点的地址上面,来确定一个该节点和表示The Clash的节点之前的关系。

1

2

URI relationshipUri = addRelationship( firstNode, secondNode, "singer",

"{ \"from\" : \"1976\", \"until\" : \"1986\" }");

在 +addRelationship+方法内部,我们确定了节点Joe Strummer的关系的URI,然后 +POST+了一个JSON数据到服务器。这个JSON数据包括目标节点,关系类型以及其他任何属性。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

privatestaticURI addRelationship( URI startNode, URI endNode,

String relationshipType, String jsonAttributes )

throwsURISyntaxException

{

URI fromUri = newURI( startNode.toString() + "/relationships");

String relationshipJson = generateJsonRelationship( endNode,

relationshipType, jsonAttributes );

WebResource resource = Client.create()

.resource( fromUri );

// POST JSON to the relationships URI

ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )

.type( MediaType.APPLICATION_JSON )

.entity( relationshipJson )

.post( ClientResponse.class);

finalURI location = response.getLocation();

System.out.println( String.format(

"POST to [%s], status code [%d], location header [%s]",

fromUri, response.getStatus(), location.toString() ) );

response.close();

returnlocation;

}

如果i一切运行正常,我们将收到一个状态码 +201 Created+并且一个我们刚创建的关系的URI在HTTP头里面的 +Location+。

5.2.6. 给关系增加属性

像节点一样,关系也可以有属性。因为我们是both Joe Strummer 和 the Clash的超级大粉丝,我们将增加一个评价属性到关系上面以至于其他人能看到这个乐队的5星级歌手。

1

addMetadataToProperty( relationshipUri, "stars", "5");

在 +addMetadataToProperty+方法内部,我们确定关系的属性的URI,并且 +PUT+我们的新值到服务器(因为它是 +PUT+所以它总是会覆盖已经存在的值,所以一定要小心)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

privatestaticvoidaddMetadataToProperty( URI relationshipUri,

String name, String value ) throwsURISyntaxException

{

URI propertyUri = newURI( relationshipUri.toString() + "/properties");

String entity = toJsonNameValuePairCollection( name, value );

WebResource resource = Client.create()

.resource( propertyUri );

ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )

.type( MediaType.APPLICATION_JSON )

.entity( entity )

.put( ClientResponse.class);

System.out.println( String.format(

"PUT [%s] to [%s], status code [%d]", entity, propertyUri,

response.getStatus() ) );

response.close();

}

假设一切运行正常,我们将得到一个 +200 OK+返回码(我们也可以调用 +ClientResponse.getStatus()+来获取)而且我们现在可以确定我们已经可以从一个小型图数据库中查询数据了。

5.2.7. 从图数据库中查询数据

作为图数据库的嵌入模式,Neo4j服务器使用图遍历来在途中查询数据。当前Neo4j服务器期望一个JSON数据通过 +POST+发送过来进行遍历查询(虽然这也可以改变成 +GET+的方式)。

要启动这个进程,我们用一个简单的类来封装JSON数据并通过 +POST+发送到服务器,在这种情况下我们硬编码遍历查询来查找所有带有输出方向关系 +"singer"+的所有节点。

1

2

3

4

5

6

7

// TraversalDescription turns into JSON to send to the Server

TraversalDescription t = newTraversalDescription();

t.setOrder( TraversalDescription.DEPTH_FIRST );

t.setUniqueness( TraversalDescription.NODE );

t.setMaxDepth( 10);

t.setReturnFilter( TraversalDescription.ALL );

t.setRelationships( newRelationship( "singer", Relationship.OUT ) );

一旦我们定义了我们的遍历查询所需的参数,我们只需要传递它。我们先确定起始节点的遍历查询的URI,然后 +POST+遍历查询的JSON数据来完成这个需求。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

URI traverserUri = newURI( startNode.toString() + "/traverse/node");

WebResource resource = Client.create()

.resource( traverserUri );

String jsonTraverserPayload = t.toJson();

ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )

.type( MediaType.APPLICATION_JSON )

.entity( jsonTraverserPayload )

.post( ClientResponse.class);

System.out.println( String.format(

"POST [%s] to [%s], status code [%d], returned data: "

+ System.getProperty( "line.separator") + "%s",

jsonTraverserPayload, traverserUri, response.getStatus(),

response.getEntity( String.class) ) );

response.close();

一旦请求被完成,我们将得到歌手的数据集以及他们所属的乐队:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

[ {

"outgoing_relationships": "http://localhost:7474/db/data/node/82/relationships/out",

"data": {

"band": "The Clash",

"name": "Joe Strummer"

},

"traverse": "http://localhost:7474/db/data/node/82/traverse/{returnType}",

"all_typed_relationships": "http://localhost:7474/db/data/node/82/relationships/all/{-list|&|types}",

"property": "http://localhost:7474/db/data/node/82/properties/{key}",

"all_relationships": "http://localhost:7474/db/data/node/82/relationships/all",

"self": "http://localhost:7474/db/data/node/82",

"properties": "http://localhost:7474/db/data/node/82/properties",

"outgoing_typed_relationships": "http://localhost:7474/db/data/node/82/relationships/out/{-list|&|types}",

"incoming_relationships": "http://localhost:7474/db/data/node/82/relationships/in",

"incoming_typed_relationships": "http://localhost:7474/db/data/node/82/relationships/in/{-list|&|types}",

"create_relationship": "http://localhost:7474/db/data/node/82/relationships"

}, {

"outgoing_relationships": "http://localhost:7474/db/data/node/83/relationships/out",

"data": {

},

"traverse": "http://localhost:7474/db/data/node/83/traverse/{returnType}",

"all_typed_relationships": "http://localhost:7474/db/data/node/83/relationships/all/{-list|&|types}",

"property": "http://localhost:7474/db/data/node/83/properties/{key}",

"all_relationships": "http://localhost:7474/db/data/node/83/relationships/all",

"self": "http://localhost:7474/db/data/node/83",

"properties": "http://localhost:7474/db/data/node/83/properties",

"outgoing_typed_relationships": "http://localhost:7474/db/data/node/83/relationships/out/{-list|&|types}",

"incoming_relationships": "http://localhost:7474/db/data/node/83/relationships/in",

"incoming_typed_relationships": "http://localhost:7474/db/data/node/83/relationships/in/{-list|&|types}",

"create_relationship": "http://localhost:7474/db/data/node/83/relationships"

} ]

5.2.8. 喔,是这样吗?==

那是我们用REST API 做我们的事情的方式。 That’s a flavor of what we can do with the REST API. 自然而然的我们提交到服务器的任何HTTP语义都很容易被封装,包括通过 +DELETE+来移除节点和关系。不过,如果你已经完全掌握了,那么在Jersey客户端从 +.delete()+切换成 +.delete()+是非常容易的。

5.2.9. 下一步计划是什么呢?

HTTP API提供一个客户端库更好的基本实现,它也是优秀的基于HTTP的REST接口。比起提供友好的语言级的开发架构实现,尽管他们能非常简单的绑定来使用嵌入模式的图数据库,我们还是i计划在将来让常用语言都提供基于RESTAPI的客户端绑定实现。要了解当前各种语言的Neo4j REST客户端实现以及嵌入封装,请参考: http://www.delicious.com/neo4j/drivers

5.2.10. 附录:代码

- CreateSimpleGraph.java

- Relationship.java

- TraversalDescription.java