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

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

核心类型

Cypher 类型 Python 类型

NULL

None

LIST

list

MAP

dict

布尔值 (BOOLEAN)

bool

INTEGER(整数)

int

FLOAT

float

STRING

str

ByteArray

bytearray

有关完整文档,请参阅 API 文档 — 核心数据类型

时间类型

时间数据类型由 neo4j.time 模块实现。它提供了一组兼容 ISO-8601 和 Cypher 的类型,类似于 Python 原生 datetime 模块中的类型。要在驱动程序类型和原生类型之间进行转换,请使用 .from_native().to_native() 方法(不适用于 Duration)。这种转换是有损的,因为驱动程序的类型支持纳秒级精度,而 Python 的原生类型则不支持。

驱动程序的时间类型旨在与 pytz 一起使用。不支持其他 datetime.tzinfo 实现(例如 datetime.timezonezoneinfodateutil.tz),且它们可能无法正常工作。

有关时区缩写列表,请参阅 tz 数据库时区列表

Cypher 类型 Python 类型

DATE

neo4j.time.Date

ZONED TIME

neo4j.time.Time

LOCAL TIME

neo4j.time.Time††

ZONED DATETIME

neo4j.time.DateTime

LOCAL DATETIME

neo4j.time.DateTime††

DURATION(持续时间)

neo4j.time.Duration

† 其中 tzinfo 不为 None
†† 其中 tzinfoNone

如何在查询中使用时间类型
from datetime import datetime
import pytz
from neo4j import GraphDatabase
from neo4j.time import DateTime


URI = "<database-uri>"
AUTH = ("<username>", "<password>")


friends_since = DateTime(year=1999, month=11, day=23,
                         hour=7, minute=47, nanosecond=4123)
friends_since = pytz.timezone("US/Eastern").localize(friends_since)

# Python's native datetimes work as well.
# They don't support the full feature-set of Neo4j's type though.
# py_friends_since = datetime(year=1999, month=11, day=23, hour=7, minute=47)
# py_friends_since = pytz.timezone("US/Eastern").localize(py_friends_since)

# Create a friendship with the given DateTime, and return the DateTime
with GraphDatabase.driver(URI, auth=AUTH) as driver:
    records, summary, keys = driver.execute_query("""
        MERGE (a:Person {name: $name})
        MERGE (b:Person {name: $friend})
        MERGE (a)-[friendship:KNOWS {since: $friends_since}]->(b)
        RETURN friendship.since
        """, name="Alice", friend="Bob",
        friends_since=friends_since  # or friends_since=py_friends_since
    )
    out_datetime = records[0]["friendship.since"]
    print(out_datetime)  # 1999-11-23T07:47:00.000004123-05:00

    # Converting DateTime to native datetime (lossy)
    py_out_datetime = out_datetime.to_native()  # type: datetime
    print(py_out_datetime)  # 1999-11-23 07:47:00.000004-05:00

有关完整文档,请参阅 API 文档 — 时间数据类型

Date

表示一个时刻,仅捕获日期,不捕获时间或时区。

from neo4j.time import Date

d = Date(year=2021, month=11, day=2)
print(d)  # '2021-11-02'

有关完整文档,请参阅 API 文档 — 时间数据类型 — Date

Time

表示一个时刻,捕获时间以及以秒为单位的时区偏移量,但不捕获日期。

from neo4j.time import Time
import pytz

t = Time(hour=7, minute=47, nanosecond=4123, tzinfo=pytz.FixedOffset(-240))
print(t)  # '07:47:00.000004123-04:00'

有关完整文档,请参阅 API 文档 — 时间数据类型 — Time

LocalTime

表示一个时刻,捕获一天中的时间,但不捕获日期或时区。

from neo4j.time import Time

t = Time(hour=7, minute=47, nanosecond=4123)
print(t)  # '07:47:00.000004123'

有关完整文档,请参阅 API 文档 — 时间数据类型 — Time

DateTime

表示一个时刻,捕获日期、时间和时区标识符。

from neo4j.time import DateTime
import pytz

dt = DateTime(year=2021, month=11, day=2, hour=7, minute=47, nanosecond=4123)
dt = pytz.timezone("US/Eastern").localize(dt)  # time zone localization (optional)
print(dt)  # '2021-11-02T07:47:00.000004123-04:00'

有关完整文档,请参阅 API 文档 — 时间数据类型 — DateTime

LocalDateTime

表示一个时刻,捕获日期和时间,但不捕获时区。

from neo4j.time import DateTime

dt = DateTime(year=2021, month=11, day=2, hour=7, minute=47, nanosecond=4123)
print(dt)  # '2021-11-02T07:47:00.000004123'

有关完整文档,请参阅 API 文档 — 时间数据类型 — DateTime

耗时

表示两个时间点之间的差值。作为参数传递的 datetime.timedelta 对象将始终被隐式转换为 neo4j.time.Duration。无法从 neo4j.time.Duration 转换为 datetime.timedelta(因为 datetime.timedelta 不支持月份)。

from neo4j.time import Duration

duration = Duration(years=1, days=2, seconds=3, nanoseconds=4)
print(duration)  # 'P1Y2DT3.000000004S'

有关完整文档,请参阅 API 文档 — 时间数据类型 — Duration

空间类型

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

对象属性 srid(空间参考标识符)是一个数字,用于标识空间类型所属的坐标系。您可以将其视为每个空间类型的唯一标识符。

Cypher 类型 Python 类型

POINT

neo4j.spatial.Point

POINT(笛卡尔)

neo4j.spatial.CartesianPoint

POINT (WGS-84)

neo4j.spatial.WGS84Point

有关完整文档,请参阅 API 文档 — 空间类型

CartesianPoint

表示 2D/3D 笛卡尔空间中的点。
公开属性 xyz(后者仅适用于 3D 点)。

from neo4j.spatial import CartesianPoint

# A 2D CartesianPoint
point = CartesianPoint((1.23, 4.56))
print(point.x, point.y, point.srid)
# 1.23 4.56 7203

# A 3D CartesianPoint
point = CartesianPoint((1.23, 4.56, 7.89))
print(point.x, point.y, point.z, point.srid)
# 1.23 4.56 7.8 9157

有关完整文档,请参阅 API 文档 — 空间类型 — CartesianPoint

WGS84Point

表示世界大地测量系统 (WGS84) 中的点。
公开属性 longitude(经度)、latitude(纬度)、height(高度,仅适用于 3D 点),它们是 xyz 的别名。

from neo4j.spatial import WGS84Point

# A 2D WGS84Point
point = WGS84Point((1.23, 4.56))
print(point.longitude, point.latitude, point.srid)
# or print(point.x, point.y, point.srid)
# 1.23 4.56 4326

# A 3D WGS84Point
point = WGS84Point((1.23, 4.56, 7.89))
print(point.longitude, point.latitude, point.height, point.srid)
# or print(point.x, point.y, point.z, point.srid)
# 1.23 4.56 7.89 4979

有关完整文档,请参阅 API 文档 — 空间类型 — WSG84Point

图类型

图类型仅作为结果传递,不能用作参数。章节 操作查询结果 — 转换为图 包含一个使用图类型的示例。

Cypher 类型 Python 类型

NODE

neo4j.graph.Node

RELATIONSHIP

neo4j.graph.Relationship

PATH

neo4j.graph.Path

有关完整文档,请参阅 API 文档 — 图类型

Node

表示图中的一个节点。
属性 element_id 为实体提供了一个标识符。使用时需谨慎,因为不保证 ID 值与单次事务范围之外的元素之间的映射关系。换句话说,使用 element_id 在不同事务之间 MATCH 元素是有风险的。

from neo4j import GraphDatabase


URI = "<database-uri>"
AUTH = ("<username>", "<password>")

with GraphDatabase.driver(URI, auth=AUTH) as driver:
    records, _, _ = driver.execute_query(
        "MERGE (p:Person {name: $name}) RETURN p AS person",
        name="Alice",
        database_="<database-name>",
    )
    for record in records:
        node = record["person"]
        print(f"Node ID: {node.element_id}\n"
              f"Labels: {node.labels}\n"
              f"Properties: {node.items()}\n"
        )

# Node ID: 4:73e9a61b-b501-476d-ad6f-8d7edf459251:0
# Labels: frozenset({'Person'})
# Properties: dict_items([('name', 'Alice')])

有关完整文档,请参阅 API 文档 — 图类型 — Node

Relationship

表示图中的一个关系。
属性 element_id 为实体提供了一个标识符。使用时需谨慎,因为不保证 ID 值与单次事务范围之外的元素之间的映射关系。

from neo4j import GraphDatabase


URI = "<database-uri>"
AUTH = ("<username>", "<password>")

with GraphDatabase.driver(URI, auth=AUTH) as driver:
    records, _, _ = driver.execute_query("""
        MERGE (p:Person {name: $name})
        MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend:Person {name: $friend_name})
        RETURN r AS friendship
        """, name="Alice", status="BFF", friend_name="Bob",
    )
    for record in records:
        relationship = record["friendship"]
        print(f"Relationship ID: {relationship.element_id}\n"
              f"Start node: {relationship.start_node}\n"
              f"End node: {relationship.end_node}\n"
              f"Type: {relationship.type}\n"
              f"Friends since: {relationship.get('since')}\n"
              f"All properties: {relationship.items()}\n"
        )

# Relationship ID: 5:73e9a61b-b501-476d-ad6f-8d7edf459251:1
# Start node: <Node element_id='4:73e9a61b-b501-476d-ad6f-8d7edf459251:0' labels=frozenset({'Person'}) properties={'name': 'Alice'}>
# End node: <Node element_id='4:73e9a61b-b501-476d-ad6f-8d7edf459251:2' labels=frozenset({'Person'}) properties={'name': 'Bob'}>
# Type: KNOWS
# Friends since: 2022-11-07
# All properties: dict_items([('since', neo4j.time.Date(2022, 11, 7)), ('status', 'BFF')])

有关完整文档,请参阅 API 文档 — 图类型 — Relationship

Path

表示图中的一条路径。

from neo4j import GraphDatabase
from neo4j.time import Date


URI = "<database-uri>"
AUTH = ("<username>", "<password>")

def add_friend(driver, name, status, date, friend_name):
    driver.execute_query("""
        MERGE (p:Person {name: $name})
        MERGE (p)-[r:KNOWS {status: $status, since: $date}]->(friend:Person {name: $friend_name})
        """, name=name, status=status, date=date, friend_name=friend_name,
        database_="<database-name>",
    )

with GraphDatabase.driver(URI, auth=AUTH) as driver:
    # Create some :Person nodes linked by :KNOWS relationships
    add_friend(driver, name="Alice", status="BFF", date=Date.today(), friend_name="Bob")
    add_friend(driver, name="Bob", status="Fiends", date=Date.today(), friend_name="Sofia")
    add_friend(driver, name="Sofia", status="Acquaintances", date=Date.today(), friend_name="Sofia")

    # Follow :KNOWS relationships outgoing from Alice three times, return as path
    records, _, _ = driver.execute_query("""
        MATCH path=(:Person {name: $name})-[:KNOWS*3]->(:Person)
        RETURN path AS friendship_chain
        """, name="Alice",
        database_="<database-name>",
    )
    path = records[0]["friendship_chain"]

    print("-- Path breakdown --")
    for friendship in path:
        print("{name} is friends with {friend} ({status})".format(
            name=friendship.start_node.get("name"),
            friend=friendship.end_node.get("name"),
            status=friendship.get("status"),
        ))

有关完整文档,请参阅 API 文档 — 图类型 — Path

扩展类型

驱动程序支持更多作为查询参数的类型,这些类型会自动映射到 核心类型 之一。由于这种转换,且服务器不了解扩展类型,因此驱动程序永远不会在结果中返回这些类型,而总是返回其对应的映射类型。

参数类型 映射的 Python 类型

tuple

list

bytearray

bytes

numpy ndarray

list (嵌套)

pandas DataFrame

dict

pandas Series

list

pandas Array

list

通常,如果您不确定给定参数会发生什么类型转换,您可以按照以下示例进行测试

import neo4j

with neo4j.GraphDatabase.driver(URI, auth=AUTH) as driver:
    type_in = ("foo", "bar")
    records, _, _ = driver.execute_query("RETURN $x AS type_out", x=type_in)
    type_out = records[0].get("type_out")
    print(type(type_out))  # <class 'list'>
    print(type_out)        # ['foo', 'bar']

向量类型

类型 Vector 映射到 Cypher 类型 VECTORVector 对象存储为连续的内存块 (bytes),包含以大端序编码的同质值。

您可以从多种数据类型创建 Vector

一些有效的 Vector 调用示例
Vector([1, 2, 3], "i8")  (1)
Vector(b"\x00\x01\x00\x02", "i16")  (2)
Vector(b"\x01\x00\x02\x00", "i16", byteorder="little")  (3)
Vector(numpy.array([1, 2, 3]))  (4)
Vector(pyarrow.array([1, 2, 3]))  (5)
1 浮点数/整数的可迭代对象,以及单个条目的类型 (VectorDType)。
支持的类型包括
  • f32: 32 位浮点数(单精度)

  • f64: 64 位浮点数(双精度)

  • i8: 8 位整数

  • i16: 16 位整数

  • i32: 32 位整数

  • i64: 64 位整数

2 原始字节,以及用于解析字节的类型 (VectorDType)。
3 提供原始字节时,byteorder 是可选的,默认为 "big"
4 numpy.ndarray。不接受其他参数,VectorDType 从输入中推断得出。
5 pyarrow.Array。不接受其他参数,VectorDType 从输入中推断得出。
创建并存储向量
from neo4j.vector import Vector

# Create a vector (parsing bytes as big-endian by default)
v = Vector(b"\x00\x01\x02\x03", "i16")
# or (less performant, but friendlier)
v = Vector([1, 513], "i16")

# Store the vector as a node property
driver.execute_query("MERGE (d:Doc {embedding: $vector})", vector=v)
在数据库中存储 VECTOR 对象需要服务器版本 >= 2025.10,企业版。
检索并处理向量
from neo4j.vector import Vector

# Retrieve a vector
v = driver.execute_query(
    "MATCH (d:Doc) RETURN d.embedding AS v LIMIT 1",
    database_="neo4j",
).records[0]["v"]

# Work with the vector
print(f"Got vector of type {v.dtype} with {len(v)} elements: {v}")
print("raw bytes:", v.raw())
print("python list:", v.to_native())
print("as numpy array:", v.to_numpy())
由于 Python 没有原生的 float32 类型,转换为原生 Python 列表的 float32 向量会变成 float64 列表,导致潜在的表示精度误差。为了保留 float32 表示,请将结果向量转换为 numpy 数组 (Vector.to_numpy) 或 pyarrow 数组 (Vector.to_pyarrow)。

UnsupportedType

类型 UnsupportedType 用于 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

事务

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

背压

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

书签

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

事务函数

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

驱动程序 (Driver)

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