数据类型和 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),并且不太可能正常工作。

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

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 = "<URI for Neo4j database>"
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

Duration

表示两个时间点之间的差异。作为参数传递的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 (Cartesian)

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) 中的一个点。
公开属性longitudelatitudeheight(后者仅适用于 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 = "<URI for Neo4j database>"
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_="neo4j",
    )
    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 = "<URI for Neo4j database>"
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 = "<URI for Neo4j database>"
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_="neo4j",
    )

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_="neo4j",
    )
    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']

异常

驱动程序可能会引发许多不同的异常。完整的列表可在API 文档中找到。有关服务器可能返回的错误列表,请参阅状态码页面。

表 1. 根异常类型
分类 描述

Neo4jError

Neo4j 服务器报告的错误(例如,错误的 Cypher 语法、连接错误、错误的凭据等)

DriverError

驱动程序报告的错误(例如,参数或事务的错误使用、结果的错误处理等)

某些服务器错误被标记为可以安全重试,无需更改原始请求。此类错误的示例包括死锁、内存问题或连接问题。所有驱动程序的异常类型都实现了.is_retryable()方法,该方法提供了有关进一步尝试是否可能成功的见解。这在显式事务中运行查询时特别有用,以了解失败的查询是否值得重新运行。

词汇表

LTS

长期支持版本是保证支持若干年的版本。Neo4j 4.4 是 LTS,Neo4j 5 也将有一个 LTS 版本。

Aura

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

Cypher

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

APOC

Awesome Procedures On Cypher (APOC) 是一个函数库(包含许多函数),这些函数无法用 Cypher 本身轻松表达。

Bolt

Bolt 是 Neo4j 实例与驱动程序之间交互使用的协议。默认情况下,它监听 7687 端口。

ACID

原子性、一致性、隔离性、持久性 (ACID) 是保证数据库事务可靠处理的特性。符合 ACID 的 DBMS 确保数据库中的数据即使在发生故障的情况下也能保持准确和一致。

最终一致性

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

因果一致性

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

NULL

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

事务

事务是工作的单元,要么完全提交,要么在发生故障时回滚。例如银行转账:它涉及多个步骤,但它们必须全部成功或被撤销,以避免从一个账户中扣款但未添加到另一个账户中。

背压

背压是阻碍数据流动的力量。它确保客户端不会被超出其处理能力的数据所淹没。

事务函数

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

驱动程序

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