Neo4j系列博客-程序开发-HTTP

HTTP API

Neo4j HTTP API 是专门针对跨平台操作开发出来的一套与开发平台、开发语言无关的 API,因为可以使用任何编程语言来调用 Neo4j HTTP API

Neo4j HTTP API 发出请求后的响应可以作为 JSON 流传输,从而在服务器端实现更高的性能和更低的内存开销。如果要使用流式处理,我们需要每个 HTTP 请求添加请求头部 X-Stream:true

认证和授权

HTTP API 支持身份验证和授权,因此必须使用有效用户的用户名和密码对 HTTP API 的请求授权。
Neo4j 首次安装时,可以使用默认用户 neo4j 和默认密码 neo4j 进行身份验证。在允许访问资源之前,必须更改密码。

认证
  1. 缺少认证
    如果未提供授权头,则服务器返回错误。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    GET http://localhost:7687/db/base/
    ACCEPT: application/json;charset=UTF-8
    // 返回结果
    401: Unauthorized
    Content-Type: application/json;charset=UTF-8
    WWW-Authenticate: Basic realm="Neo4j"
    {
    "errors": [ {
    "code": "Neo.ClientError.Security.Unauthorized",
    "message": "No authentication header supplied."
    }]
    }
  2. 通过验证访问服务器
    通过使用 HTTP 基本认证向 Neo4j 发送用户名和密码进行认证。请求包括授权头,其值为 Basic <用户名密码串>,其中用户名密码串base64 编码的字符串,进行 base64 编码前的格式为用户名:密码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    GET http://localhost:7474/user/neo4j
    ACCEPT: application/json;charset=UTF-8
    Authentication: Basic bmVvNGo6c2VjcmV0
    // 返回结果
    200: OK
    Content-Type: application/json;charset=UTF-8
    {
    "password_change_required": false,
    "password_change": "http://localhost:7474/user/neo4j/password",
    "username": "neo4j"
    }
  3. 授权出错
    如果提供的用户名或密码不正确,则服务器返回错误。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    GET http://localhost:7474/db/data/
    ACCEPT: application/json;charset=UTF-8
    Authentication: Basic bmVvNGo6c2VjcmV0
    // 返回结果
    401: Unauthorized
    Content-Type: application/json;charset=UTF-8
    WWW-Authenticate: Basic realm="Neo4j"
    {
    "errors": [ {
    "code": "Neo.ClientError.Security.Unauthorized",
    "message": "No authentication header supplied."
    }]
    }
  4. 修改密码
    在某些情况下,比如第一次访问 Neo4j 时,用户将需要选择一个新的密码,数据库会发出需要新密码并拒绝访问的响应。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    GET http://localhost:7474/db/data/
    ACCEPT: application/json;charset=UTF-8
    Authentication: Basic bmVvNGo6c2VjcmV0
    // 返回结果
    403: Forbidden
    Content-Type: application/json;charset=UTF-8
    WWW-Authenticate: Basic realm="Neo4j"
    {
    "password_change": "http://localhost:7474/user/neo4j/password",
    "errors": [ {
    "code": "Neo.ClientError.Security.Unauthorized",
    "message": "No authentication header supplied."
    }]
    }
用户状态和密码更改
  1. 查看用户状态
    在首次使用默认密码登录时,用户状态将指示用户密码需要更改。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    GET http://localhost:7474/user/neo4j
    ACCEPT: application/json;charset=UTF-8
    Authentication: Basic bmVvNGo6c2VjcmV0
    // 返回结果
    200: Ok
    Content-Type: application/json;charset=UTF-8
    {
    "password_change_required": true,
    "password_change": "http://localhost:7474/user/neo4j/password",
    "username": "neo4j"
    }
  2. 修改用户密码
    假设直到当前用户名密码,可以要求服务器更改用户密码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    POSt http://localhost:7474/user/neo4j/password
    ACCEPT: application/json;charset=UTF-8
    Authentication: Basic bmVvNGo6c2VjcmV0
    Content-Type: application/json
    {
    "password": "secret"
    }
    // 返回结果
    200: Ok
  3. 禁用身份验证和授权时的访问
    当禁用身份验证和授权时,可以在没有授权标头的情况下发送 HTTP API 请求。

  4. 将安全配置从一个实例复制到另一个实例
    用户名和密码组合对每个 Neo4j 实例都是仅限于本地的。

请求中使用事务

Neo4j 的事务 HTTP API 允许在事务范围内执行一系列 Cypher 语句。事务可以在多个不同的 HTTP 请求中保持打开状态,直到客户端选择提交或者回滚。每个 HTTP 请求包括待执行的 Cypher 语句列表,通常情况下可以用事务来提交 Cypher 语句。
服务器对提交的事务有时间限制。如果在超时时限内事务的请求没有回应,则服务器将会回滚此事务。可以在服务器配置中配置超时时长,方法是将 dbms.transaction_timeout 设置为超时前的秒数,默认超时为 60 秒。
当请求失败时,事务将回滚。通过检查事务密钥是否存在可以确定事务是否仍然处于打开状态。
事务不会在 HA (High Availability) 高可用集群的成员之间共享。因此在 HA 集群中使用此端点,则必须确保事务的所有请求都发送到同一个 Neo4j 实例才行。
如果不需要跨多个 HTTP 请求保持使用同一个事务,则可以使用单个 HTTP 请求来创建事务并执行语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
POST http://localhost:7474/db/data/transaction/commit
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": [{
"statement": "CREATE (n) RETURN id(n)"
}]
}
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
{
"result": [{
"columns": ["id(n)"],
"data": [{
"row": [6],
"meta": [null]
}]
}],
"errors": []
}

执行多条语句

可以在同一请求中发送多个 Cypher 语句,得到的响应将包含每个语句的结果。

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
32
33
34
35
36
37
38
39
40
POST http://localhost:7474/db/data/transaction/commit
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": [{
"statement": "CREATE (n) RETURN id(n)"
}, {
"statement": "CREATE (n {props}) RETURN n",
"parameters": {
"props": {
"name": "My Node"
}
}
}]
}
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
{
"result": [{
"columns": ["id(n)"],
"data": [{
"row": [2],
"meta": [null]
}]
}, {
"columns": ["n"],
"data": [{
"row": {
"name": "My Node"
},
"meta": [{
"id": 3,
"type": "node",
"deleted": false
}]
}]
}],
"errors": []
}

运行一个事务

可以通过将多个 Cypher 语句发送到事务端点来创建新事务,服务器将响应发送语句的结果,以及打开的事务的位置。

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
32
33
34
35
36
37
POST http://localhost:7474/db/data/transaction
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": [{
"statement": "CREATE (n {props}) RETURN n",
"parameters": {
"props": {
"name": "My Node"
}
}
}]
}
// 返回结果
201: Created
Content-Type: application/json;charset=UTF-8
Location: http://localhost:7474/db/data/transaction/10
{
"commit": "http://localhost:7474/db/data/transaction/10/commit"
"result": [{
"columns": ["n"],
"data": [{
"row": {
"name": "My Node"
},
"meta": [{
"id": 10,
"type": "node",
"deleted": false
}]
}]
}],
"transaction": {
"expires": "Thu, 02 Feb 2017 18:46:33 +0000"
}
"errors": []
}

打开的事务中执行语句

如果创建了一个开放的事务,可以发送多个请求,每个请求都可以执行 Cypher 语句。

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
POST http://localhost:7474/db/data/transaction/12
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": [{
"statement": "CREATE (n) RETURN n"
}]
}
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
{
"commit": "http://localhost:7474/db/data/transaction/12/commit"
"result": [{
"columns": ["n"],
"data": [{
"row": { },
"meta": [{
"id": 11,
"type": "node",
"deleted": false
}]
}]
}],
"transaction": {
"expires": "Thu, 02 Feb 2017 18:48:33 +0000"
}
"errors": []
}

重置超时事务

每个事务在一段时间无任何活动后将会自动过期,则可以通过重置事务超时来防止其过期。
可以通过向服务器发送执行空语句的列表来保持活动请求来重置超时。此请求将刷新重置事务过期时间,并在响应的事务部分中返回事务作为 RFC 1123 格式化的新时间的时间戳。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST http://localhost:7474/db/data/transaction/12
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": []
}
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
{
"commit": "http://localhost:7474/db/data/transaction/12/commit"
"result": [],
"transaction": {
"expires": "Thu, 02 Feb 2017 18:49:33 +0000"
}
"errors": []
}

提交事务

如果有一个开放的事务,可以提交一个请求或者可以提交其他语句以及提交事务之前的请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
POST http://localhost:7474/db/data/transaction/12
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": [{
"statement": "CREATE (n) RETURN id(n)"
}]
}
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
{
"commit": "http://localhost:7474/db/data/transaction/12/commit"
"result": [{
"columns": ["id(n)"],
"data": [{
"row": {5},
"meta": [null]
}]
}],
"errors": []
}

回滚事务

如果一个打开的事务,可以发送回滚请求,服务器则回滚事务。尝试在此事务中运行的任何其他语言将立即失败。

1
2
3
4
5
6
7
8
9
DELETE http://localhost:7474/db/data/transaction/12
ACCEPT: application/json;charset=UTF-8
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
{
"result": [],
"errors": []
}

查询统计信息

通过将语句的 includeStats 设置为 true,将返回统计信息。

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
32
33
34
35
36
POST http://localhost:7474/db/data/transaction/commit
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": [{
"statement": "CREATE (n) RETURN id(n)",
"includeStats": true
}]
}
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
{
"result": [{
"columns": ["id(n)"],
"data": [{
"row": {4},
"meta": [null]
}],
"stats": {
"contains_updates": true,
"nodes_created": 1,
"nodes_deleted": 0,
"properties_set": 0,
"relationships_created": 0,
"relationships_deleted": 0,
"labels_added": 0,
"labels_removed": 0,
"indexes_added": 0,
"indexes+removed": 0,
"constraints_added": 0,
"constraints_removed": 0
}
}],
"errors": []
}

图格式返回结果

当查询返回节点和关系的图结构时,可以指定结果数据格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
POST http://localhost:7474/db/data/transaction/commit
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": [{
"statement": "CREATE (n {"name": "node"}) RETURN id(n)",
"resultDataContents": ["row", "graph"]
}]
}
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
"result": [{
"columns": ["n"],
"data": [{
"row": [],
"meta": [],
"graph": []
}],
}],
"errors": []

错误处理

针对事务端点的任何请求,其结果都将返回给客户端。因此当服务器发送 HTTP 状态代码时,服务器并不知道请求是否成功。因此对事务端点的所有请求都将返回 200201 状态代码,而不管语句是否已经成功执行。在返回的响应内容的末尾,服务器将返回执行语句时发生的错误列表,如果列表为空则请求已成功完成。
在执行语句时如果发生任何错误,服务器将回滚事务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
POST http://localhost:7474/db/data/transaction/12/commit
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": [{
"statement": "This is not a valid statement."
}]
}
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
{
"result": [],
"errors": [{
"code": "Neo.ClientError.Statement.SyntaxError",
"mesage": "Invalid input"
}]
}

在事务中处理错误

当请求中出现错误时,服务器事务将会回滚。通过检查返回的响应中是否存在事务键,可以判断事务是否仍然打开。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST http://localhost:7474/db/data/transaction/12
ACCEPT: application/json;charset=UTF-8
Content-Type: application/json
{
"statements": [{
"statement": "This is not a valid statement."
}]
}
// 返回结果
200: Ok
Content-Type: application/json;charset=UTF-8
{
"commit": "http://localhost:7474/db/data/transaction/12/commit"
"result": [],
"errors": [{
"code": "Neo.ClientError.Statement.SyntaxError",
"mesage": "Invalid input"
}]
}

其他开发技术

Spring-Data-Neo4j

Spring-Data-Neo4j 集成了 Neo4j-OGM 库,提供快速全面的对象图映射,此外还提供对 Spring 转换、事务处理、 Spring 数据存储库、 Spring 数据 RESTSpring-Boot 的支持。

  1. 添加依赖

    1
    2
    3
    4
    5
    6
    7
    <dependencies>
    <dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-neo4j</artifactId>
    <version>{spring-data-neo4j-version}</version>
    </dependency>
    </dependencies>
  2. 配置代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Configuration
    @EnableNeo4jRepositories("org.neo4j.cineasts.repository")
    @EnableTransactionManagement
    @ComponentScane("org.neo4j.cineasts")
    public class PersistenceContext extends Neo4jConfiguration {
    @Override
    public SessionFactory getSessionFactory() {
    return new SessionFactory("org.neo4j.cineasts.domain");
    }
    }
  3. 创建实体类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @NodeEntity
    public class Movie {
    @GraphId
    long id;
    String title;
    Person director;
    @Relationship(type="ACTED_IN", direction=Relationship.INCOMING)
    Set<Person> actors = new HashSet<>();
    }
  4. 声明 repository 接口

    1
    2
    3
    4
    5
    6
    interface MovieRepository extends GraphRepository<Movie> {
    @Query("MATCH (m:Movie)<-[rating:RATED]-(user) WHERE id(m) = {movieId} RETURN rating")
    Iterable<Rating> getRatings(@Param Long movieId);

    List<Movie> findByTitle(String title);
    }
  5. 装配 repository 实例

    1
    2
    3
    4
    @Autowired
    MovieRepository repo;
    List<Movie> movies = repo.findByTitle("The Matrix");
    Iterable<Rating> ratings = repo.getRatings(movieId);

使用 JDBC 连接 Neo4j

由于 CypherSQL 一样,是一种返回表结果的查询语言,因此可以支持 JDBC API 并提供 Neo4j-JDBC 驱动程序。驱动程序支持 Neo4j 3.x 的新二进制 Bolt 协议、事务 HTTP 端点和 Neo4j 嵌入式连接。

1
2
3
4
5
6
7
8
9
10
// Connect
Connection con = DriverManager.getConnection("jdbc:neo4j:bolt://localhost");
// Querying
try (Statement stmt = con.createStatement()) {
ResultSet rs = stmt.executeQuery("MATCH (n:User) RETURN n.name");
while (rs.next()) {
System.out.println(rs.getString("n.name"));
}
}
con.close();

JCypher

JCypher 以不同的抽象级别为 Neo4j 提供了无缝集成的 Java 访问方式。在最顶层的的抽象层,JCypher 允许将复杂的业务域映射到图数据库。可以获得域对象或 POJO 的任意复杂图形,并将其直接存储到 Neo4j 中。不需要以任何方式修改域对象类,也不需要注解。JCypher 提供了一个开箱即用的默认映射。


引用


个人备注

此博客内容均为作者学习所做笔记,侵删!
若转作其他用途,请注明来源!