数据类型及其到 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 类型

日期

neo4j.time.Date

带时区时间

neo4j.time.Time

本地时间

neo4j.time.Time††

带时区日期时间

neo4j.time.DateTime

本地日期时间

neo4j.time.DateTime††

持续时间

neo4j.time.Duration

tzinfo 不为 None 的情况。
†† tzinfoNone 的情况。

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


URI = "{neo4j-database-uri}"
AUTH = ("{neo4j-username}", "{neo4j-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 文档 — 时间数据类型

日期

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

from neo4j.time import Date

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

时间

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

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'

本地时间

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

from neo4j.time import Time

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

日期时间

表示一个捕获日期、时间及有时区标识符的时刻。

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'

本地日期时间

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

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'

持续时间

表示两个时间点之间的差值。作为参数传入的 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'

空间类型

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

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

Cypher 类型 Python 类型

neo4j.spatial.Point

点 (笛卡尔)

neo4j.spatial.CartesianPoint

点 (WGS-84)

neo4j.spatial.WGS84Point

完整文档请参见API 文档 — 空间类型

CartesianPoint

表示 2D/3D 笛卡尔空间中的一个点。
公开属性 xyzz 仅适用于 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

WGS84Point

表示全球大地测量系统 (WGS84) 中的一个点。
公开属性 longitudelatitudeheightheight 仅适用于 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

图类型

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

Cypher 类型 Python 类型

节点

neo4j.graph.Node

关系

neo4j.graph.Relationship

路径

neo4j.graph.Path

完整文档请参见API 文档 — 图类型

节点

表示图中的一个节点。
属性 element_id 提供实体的标识符。应谨慎使用此属性,因为无法保证 id 值与单个事务范围之外的元素之间的映射。换句话说,在不同事务中使用 element_idMATCH 元素是危险的。

from neo4j import GraphDatabase


URI = "{neo4j-database-uri}"
AUTH = ("{neo4j-username}", "{neo4j-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 文档 — 图类型 — 节点

关系

表示图中的一个关系。
属性 element_id 提供实体的标识符。应谨慎使用此属性,因为无法保证 id 值与单个事务范围之外的元素之间的映射。

from neo4j import GraphDatabase


URI = "{neo4j-database-uri}"
AUTH = ("{neo4j-username}", "{neo4j-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 文档 — 图类型 — 关系

路径

表示图中的一条路径。

from neo4j import GraphDatabase
from neo4j.time import Date


URI = "{neo4j-database-uri}"
AUTH = ("{neo4j-username}", "{neo4j-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 文档 — 图类型 — 路径

扩展类型

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

参数类型 映射的 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 文档中找到。有关服务器可能返回的错误列表,请参见状态码页面。

某些服务器错误被标记为可以安全重试,无需更改原始请求。此类错误的示例包括死锁、内存问题或连接问题。所有驱动程序的异常类型都实现了 .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 数据库连接所需的详细信息。

© . All rights reserved.