数据类型及其与 Cypher 类型的映射

本节中的表格显示了 Cypher 数据类型与 Java 类型之间的映射关系。

无论类型如何,查询结果中的所有值都嵌入在 Value 对象中。要提取并将其转换为相应的 Java 类型,请使用 .as<type>()(例如 .asString()asInt() 等)。例如,如果来自数据库的 name 属性是一个字符串,record.get("name").asString() 将把该属性值作为 String 对象返回。

另一方面,在提交查询参数时,您无需使用驱动程序类型。驱动程序会自动序列化作为参数传递的 Java 原生类型对象。

有关驱动程序将数据序列化成的完整值类型列表,请参阅 API 文档

核心类型

Cypher 类型 驱动程序类型

NULL

NullValue

LIST

ListValue

MAP

MapValue

布尔值 (BOOLEAN)

BooleanValue

INTEGER(整数)

IntegerValue

FLOAT

FloatValue

STRING

StringValue

ByteArray

BytesValue

时间类型

驱动程序提供了一套符合 ISO-8601 和 Cypher 标准的时间数据类型。亚秒级值以纳秒精度测量。

驱动程序的类型依赖于 Java 的 time 类型。除 DurationValue 外,所有时间类型底层实际上都是 java.time 对象。这意味着

  • 如果您想使用时间类型查询数据库,只需实例化一个 java.time 对象并将其用作查询参数(即您不需要关心驱动程序的类型)。

  • 如果您从数据库检索时间对象(包括通过 Cypher 时间函数),您将获得下表中显示的相应驱动程序类型。驱动程序实现了将驱动程序时间类型转换为 Java 类型的方法(例如 .asZonedDateTime().asOffsetTime() 等)。

Cypher 类型 驱动程序类型

DATE

DateValue

ZONED TIME

TimeValue

LOCAL TIME

LocalTimeValue

ZONED DATETIME

DateTimeValue

LOCAL DATETIME

LocalDateTimeValue

DURATION(持续时间)

DurationValue

如何在查询中使用时间类型
package demo;

import java.util.Map;
import java.time.ZonedDateTime;
import java.time.ZoneId;

import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.QueryConfig;

public class App {

    public static void main(String... args) {
        final String dbUri = "<database-uri>";
        final String dbUser = "<username>";
        final String dbPassword = "<password>";

        try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) {
            driver.verifyConnectivity();

            // Define a date, with timezone, and use it to set a relationship property
            var friendsSince = ZonedDateTime.of(2016, 12, 16, 13, 59, 59, 9999999, ZoneId.of("Europe/Stockholm"));
            var result = driver.executableQuery("""
                MERGE (a:Person {name: $name})
                MERGE (b:Person {name: $friend})
                MERGE (a)-[friendship:KNOWS {since: $friendsSince}]->(b)
                RETURN friendship.since AS date
                """)
                .withParameters(Map.of("name", "Alice", "friend", "Bob", "friendsSince", friendsSince))
                .withConfig(QueryConfig.builder().withDatabase("<database-name>").build())
                .execute();

            var date = result.records().get(0).get("date");
            System.out.println(date.getClass().getName());  // org.neo4j.driver.internal.value.DateTimeValue
            System.out.println(date);  // 2016-12-16T13:59:59.009999999+01:00[Europe/Stockholm]

            var nativeDate = date.asZonedDateTime();
            System.out.println(nativeDate.getClass().getName());  // java.time.ZonedDateTime
        }
    }
}

DurationValue

表示两个时间点之间的差值(以月、日、秒、纳秒表示)。

// import org.neo4j.driver.Values;

var duration = Values.isoDuration(1, 2, 3, 4);  // months, days, seconds, nanoseconds
System.out.println(duration);  // P1M2DT3.000000004S

有关完整文档,请参阅 API 文档 → DurationValue

空间类型

Cypher 支持空间值(点),Neo4j 可以将这些点值存储为节点和关系的属性。

属性 SRIDSpatial Reference Identifier,空间参考标识符的缩写)是一个数字,用于标识解析空间类型时所使用的坐标系。您可以将其视为每个空间类型的唯一标识符。

Cypher 类型 驱动程序类型 SRID

POINT (2D 笛卡尔坐标系)

PointValue

7203

POINT (2D WGS-84)

PointValue

4326

POINT (3D 笛卡尔坐标系)

PointValue

9157

POINT (3D WGS-84)

PointValue

4979

您可以通过 Values.point(srid, x, y[, z])(第三个坐标是可选的)创建点值。从数据库查询返回的点是 PointValue 类型,可以通过 .asPoint() 方法转换为 Point 对象。

从数据库接收 Point
package demo;

import java.util.Map;

import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.QueryConfig;
import org.neo4j.driver.Values;

public class App {

    public static void main(String... args) {
        final String dbUri = "<database-uri>";
        final String dbUser = "<username>";
        final String dbPassword = "<password>";

        try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) {
            driver.verifyConnectivity();

            var result = driver.executableQuery("RETURN point({x: 2.3, y: 4.5, z: 2}) AS point")
                .withConfig(QueryConfig.builder().withDatabase("<database-name>").build())
                .execute();
            var point = result.records().get(0).get("point");
            System.out.println(point);  // Point{srid=9157, x=2.3, y=4.5, z=2.0}
            System.out.println(point.asPoint().x());  // 2.3
        }
    }
}
创建一个 Point 值并将其用作属性值
package demo;

import java.util.Map;

import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.QueryConfig;
import org.neo4j.driver.Values;

public class App {

    public static void main(String... args) {
        final String dbUri = "<database-uri>";
        final String dbUser = "<username>";
        final String dbPassword = "<password>";

        try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) {
            driver.verifyConnectivity();

            var location = Values.point(4326, 67.28775180193841, 17.734163823312397);  // 4326 = 2D geodetic point
            var result = driver.executableQuery("CREATE (p:PlaceOfInterest {location: $location}) RETURN p")
                .withParameters(Map.of("location", location))
                .withConfig(QueryConfig.builder().withDatabase("<database-name>").build())
                .execute();
            var place = result.records().get(0).get("p").get("location");
            System.out.println(place);  // Point{srid=4326, x=67.28775180193841, y=17.734163823312397}
            System.out.println(place.asPoint().y());  // 17.734163823312397
        }
    }
}

图类型

图类型仅作为结果传递,不可用作参数.

Cypher 类型 驱动程序类型

NODE

NodeValue

RELATIONSHIP

RelationshipValue

PATH

PathValue

NodeValue

表示图中的一个节点。

表 1. 节点对象上的重要方法
方法 返回

.labels()

节点标签,作为列表返回。

.asMap()

节点属性,作为映射(Map)返回。

.get("<propertyName>")

给定属性的值。

.elementId()

节点的字符串标识符。使用时需谨慎,因为不保证 id 值与单个事务范围之外的元素之间的映射关系。换句话说,使用 elementId 在不同事务之间 MATCH 元素是有风险的。

检索节点并显示其详细信息
package demo;

import java.util.Map;

import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.QueryConfig;

public class App {

    public static void main(String... args) {
        final String dbUri = "<database-uri>";
        final String dbUser = "<username>";
        final String dbPassword = "<password>";

        try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) {
            driver.verifyConnectivity();

            // Get a node from the database
            var result = driver.executableQuery("MERGE (p:Person:Actor {name: $name, age: 59}) RETURN p")
                .withParameters(Map.of("name", "Alice"))
                .withConfig(QueryConfig.builder().withDatabase("<database-name>").build())
                .execute();

            // Extract node from result
            var nodeVal = result.records().get(0).get("p");
            var node = nodeVal.asNode();  // .asNode() -> type org.neo4j.driver.types.Node

            System.out.printf("Labels: %s %n", node.labels());
            System.out.printf("Properties: %s %n", node.asMap());
            System.out.printf("Name property: %s %n", node.get("name"));
            System.out.printf("Element ID: %s %n", node.elementId());
            /*
            Labels: [Person, Actor]
            Properties: {name=Alice, age=59}
            Name property: "Alice"
            Element ID: 4:549a0567-2015-4bb6-a40c-8536bf7227b0:5
            */
        }
    }
}

有关完整文档,请参阅 API 文档 → NodeValue

RelationshipValue

表示图中的一个关系。

表 2. 关系对象上的重要方法
方法 返回

.type()

关系类型。

.asMap()

关系属性,作为映射(Map)返回。

.get("<propertyName>")

给定属性的值。

.startNodeElementId()

起始节点的 elementId

.endNodeElementId()

结束节点的 elementId

.elementId()

关系的字符串标识符。使用时需谨慎,因为不保证 id 值与单个事务范围之外的元素之间的映射关系。换句话说,使用 elementId 在不同事务之间 MATCH 元素是有风险的。

检索关系并显示其详细信息
package demo;

import java.util.Map;

import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.QueryConfig;

public class App {

    public static void main(String... args) {
        final String dbUri = "<database-uri>";
        final String dbUser = "<username>";
        final String dbPassword = "<password>";

        try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) {
            driver.verifyConnectivity();

            // Get a relationship from the database
            var result = driver.executableQuery("""
                MERGE (p:Person {name: $name})
                MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend:Person {name: $friendName})
                RETURN r AS friendship
                """)
                .withParameters(Map.of("name", "Alice", "status", "BFF", "friendName", "Bob"))
                .withConfig(QueryConfig.builder().withDatabase("<database-name>").build())
                .execute();

            // Extract relationship from result
            var relationshipVal = result.records().get(0).get("friendship");
            var relationship = relationshipVal.asRelationship();  // .asRelationship() -> type org.neo4j.driver.types.Relationship

            System.out.printf("Type: %s %n", relationship.type());
            System.out.printf("Properties: %s %n", relationship.asMap());
            System.out.printf("Status property: %s %n", relationship.get("status"));
            System.out.printf("Start node: %s %n", relationship.startNodeElementId());
            System.out.printf("End node: %s %n", relationship.endNodeElementId());
            System.out.printf("Element ID: %s %n", relationship.elementId());
            /*
            Type: KNOWS
            Properties: {since=2024-01-12, status=BFF}
            Status property: "BFF"
            Start node: 4:549a0567-2015-4bb6-a40c-8536bf7227b0:0
            End node: 4:549a0567-2015-4bb6-a40c-8536bf7227b0:6
            Element ID: 5:549a0567-2015-4bb6-a40c-8536bf7227b0:1
            */
        }
    }
}

有关完整文档,请参阅 API 文档 → RelationshipValue

PathValue

表示图中的一条路径。

驱动程序将路径分解为(可迭代的)(segments),每个段由一个起始节点、一个关系和一个结束节点组成。可以通过 .start().relationship().end() 方法按顺序检索段实体。

检索路径并遍历它,列出节点和关系
package demo;

import java.util.Map;

import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.types.Path;
import org.neo4j.driver.QueryConfig;

public class App {

    public static void main(String... args) {
        final String dbUri = "<database-uri>";
        final String dbUser = "<username>";
        final String dbPassword = "<password>";

        try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword))) {
            driver.verifyConnectivity();

            // Create some :Person nodes linked by :KNOWS relationships
            addFriend(driver, "Alice", "BFF", "Bob");
            addFriend(driver, "Bob", "Fiends", "Sofia");
            addFriend(driver, "Sofia", "Acquaintances", "Sofia");

            // Follow :KNOWS relationships outgoing from Alice three times, return as path
            var result = driver.executableQuery("""
                MATCH path=(:Person {name: $name})-[:KNOWS*3]->(:Person)
                RETURN path AS friendshipChain
                """)
                .withParameters(Map.of("name", "Alice"))
                .withConfig(QueryConfig.builder().withDatabase("<database-name>").build())
                .execute();

            // Extract path from result
            var pathVal = result.records().get(0).get("friendshipChain");
            var path = pathVal.asPath();  // .asPath() -> type org.neo4j.driver.types.Path

            System.out.println("-- Path breakdown --");
            for (Path.Segment segment : path) {
                System.out.printf(
                    "%s is friends with %s (%s).%n",
                    segment.start().get("name").asString(),
                    segment.end().get("name").asString(),
                    segment.relationship().get("status").asString());
            }
            /*
            -- Path breakdown --
            Alice is friends with Bob (BFF).
            Bob is friends with Sofia (Fiends).
            Sofia is friends with Sofia (Acquaintances).
            */
        }
    }

    public static void addFriend(Driver driver, String name, String status, String friendName) {
        driver.executableQuery("""
            MERGE (p:Person {name: $name})
            MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend:Person {name: $friendName})
            """)
            .withParameters(Map.of("name", name, "status", status, "friendName", friendName))
            .withConfig(QueryConfig.builder().withDatabase("<database-name>").build())
            .execute();
    }
}

有关完整文档,请参阅 API 文档 → PathValue

向量类型

VectorValue 类型映射到 Cypher 类型 VECTOR。Vector 对象存储为包含同质值的连续内存块。

您可以通过 Values.vector() 方法之一,使用 byteshortintlongfloatdouble 列表创建向量。

创建并存储向量
// import org.neo4j.driver.Values;

var vector = Values.vector(new float[8]);
driver.executableQuery("CREATE (:Value {vector: $vector})")
    .withParameters(Map.of("vector", vector))
    .execute();
在数据库中存储 VECTOR 对象需要服务器版本 >= 2025.10,企业版。
检索并处理向量
var result = driver.executableQuery("MATCH (v:Value) RETURN v.vector AS vector")
    .execute();
var vector = result.records().get(0).get("vector");

System.out.printf("Retrieved vector: %s", vector);
// Retrieved vector: vector([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 8, FLOAT32 NOT NULL)

UnsupportedType

UnsupportedTypeValue 类型用于 Cypher 查询返回但驱动程序无法识别的数据类型。当客户端版本相对于服务器版本过旧时会发生这种情况。

术语表

LTS (长期支持版)

长期支持 (Long Term Support) 版本是保证在若干年内得到支持的版本。Neo4j 4.4 和 5.26 是 LTS 版本。

Aura

Aura 是 Neo4j 的全托管云服务。它提供免费和付费计划。

Cypher

Cypher 是 Neo4j 的图查询语言,允许您从数据库中检索数据。它就像 SQL,但专用于图数据库。

APOC

Awesome Procedures On Cypher (APOC) 是一个包含(许多)函数的库,这些函数在 Cypher 本身中难以轻松实现。

Bolt

Bolt 是用于 Neo4j 实例和驱动程序之间交互的协议。默认监听 7687 端口。

ACID

原子性 (Atomicity)、一致性 (Consistency)、隔离性 (Isolation)、持久性 (Durability) (ACID) 是保证数据库事务可靠处理的属性。符合 ACID 的 DBMS 确保即使发生故障,数据库中的数据也能保持准确和一致。

最终一致性

如果一个数据库能保证所有集群成员在某个时间点都存储了数据的最新版本,则该数据库具有最终一致性。

因果一致性

如果读写查询被集群中的每个成员以相同的顺序看到,则数据库具有因果一致性。这比最终一致性更强。

NULL

空标记不是一种类型,而是缺失值的占位符。更多信息,请参阅 Cypher → 使用 null

事务

事务是一个工作单元,要么被提交,要么在失败时被回滚。例如银行转账:它涉及多个步骤,但它们必须全部成功或全部撤销,以避免钱从一个账户扣除却未存入另一个账户的情况。

背压

背压是对数据流的抵抗力。它确保客户端不会被过快发送的数据压垮,从而超出其处理能力。

书签

书签是代表数据库某种状态的标记。通过将一个或多个书签与查询一起传递,服务器将确保在所表示的状态建立之前,该查询不会被执行。

事务函数

事务函数是由 executeReadexecuteWrite 调用执行的回调。如果发生服务器故障,驱动程序会自动重新执行该回调。

驱动程序 (Driver)

Driver 对象保存了与 Neo4j 数据库建立连接所需的详细信息。