跳到主要内容
版本:Cloud 开发指南

TIMESTAMPTZ 类型

应用需要在跨区域处理中追踪时间(例如电商系统、协作工具或分布式日志系统),通常必须精确处理带有时区信息的时间戳。TIMESTAMPTZ 数据类型在 Zilliz Cloud 中通过存储带有时区的时间戳来提供这一能力。

什么是 TIMESTAMPTZ 字段?

TIMESTAMPTZ 字段是一种在 Zilliz Cloud 中以 DataType.TIMESTAMPTZ 定义的数据类型,它能够处理带时区的输入,并将所有时间点以 UTC 绝对时间的形式存储:

  • 接受的输入格式TIMESTAMPTZ 字段支持符合 ISO 8601 规范的时间戳字符串,包括:

    • "2024-12-31 22:00:00"

    • "2024-12-31T22:00:00"

    • "2024-12-31T22:00:00+08:00"

    • "2024-12-31T22:00:00Z"

  • 时间戳解析规则:时间戳的解析方式取决于输入字符串是否显式指定了时区信息:

    • 如果输入中包含时区偏移量(例如 +08:00 或 Z),则该时间戳会被视为一个绝对时间点。

    • 如果输入中未包含时区偏移量,则会使用 collection 配置的 timezone 进行解析。例如,当 collection 的时区设置为 Asia/Shanghai 时:

      • "2024-12-31 22:00:00" 会被解析为 2024-12-31T22:00:00+08:00

      • "2024-12-31T22:00:00" 会被解析为 2024-12-31T22:00:00Z,对应的本地时间为 2025-01-01T06:00:00+08:00

  • 内部存储:所有 TIMESTAMPTZ 值都会被标准化并以协调世界时(UTC)存储。

  • 比较与过滤:所有针对 TIMESTAMPTZ 字段的比较、过滤和排序操作,均基于标准化后的 UTC 值执行,从而确保在不同时区下具有一致且可预测的行为。

📘说明
  • 你可以为 TIMESTAMPTZ 字段设置 nullable=True 以允许缺失值。

  • 你可以通过 default_value 属性以 ISO 8601 格式指定默认时间戳。

有关更多信息,请参考 Nullable 和默认值

基本操作

TIMESTAMPTZ 字段的基本使用流程与其他标量字段一致:定义字段 → 插入数据 → 查询/过滤检索。

步骤 1:定义 TIMESTAMPTZ 字段

要使用 TIMESTAMPTZ 字段,你需要在创建 Collection 时,在 schema 中显式定义该字段。以下示例展示了如何创建一个包含类型为 DataType.TIMESTAMPTZtsz 字段的 Collection。

import time
from pymilvus import MilvusClient, DataType
import datetime
import pytz

server_address = "YOUR_CLUSTER_ENDPOINT"
collection_name = "timestamptz_test123"

client = MilvusClient(uri=server_address)

if client.has_collection(collection_name):
client.drop_collection(collection_name)

schema = client.create_schema()
# Add a primary key field
schema.add_field("id", DataType.INT64, is_primary=True)
# Add a TIMESTAMPTZ field that allows null values
# highlight-next-line
schema.add_field("tsz", DataType.TIMESTAMPTZ, nullable=True)
# Add a vector field
schema.add_field("vec", DataType.FLOAT_VECTOR, dim=4)

client.create_collection(collection_name, schema=schema, consistency_level="Session")
print(f"Collection '{collection_name}' with a TimestampTz field created successfully.")

步骤 2:插入数据

插入包含带时区偏移量的 ISO 8601 字符串的实体。

下面的示例向 Collection 中插入 8,193 行示例数据。每一行包含:

  • 一个唯一的 ID

  • 一个带时区信息的时间戳(上海时间)

  • 一个简单的 4 维向量

data_size = 10

# Get the Asia/Shanghai time zone using the pytz library
# You can use any valid IANA time zone identifier such as:
# "Asia/Tokyo", "America/New_York", "Europe/London", "UTC", etc.
# To view all available values:
# import pytz; print(pytz.all_timezones)
# Reference:
# IANA database – https://www.iana.org/time-zones
# Wikipedia – https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
shanghai_tz = pytz.timezone("Asia/Shanghai")

data = [
{
"id": i + 1,
"tsz": shanghai_tz.localize(
datetime.datetime(2025, 1, 1, 0, 0, 0) + datetime.timedelta(days=i)
).isoformat(),
"vec": [float(i) / 10 for i in range(4)],
}
for i in range(data_size)
]

client.insert(collection_name, data)
print("Data inserted successfully.")

步骤 3:过滤操作

TIMESTAMPTZ 支持标量比较、时间区间运算,以及时间组件的提取。

在对 TIMESTAMPTZ 字段执行过滤操作之前,请确保:

  • 已为每个向量字段创建索引。

  • Collection 已加载到内存中。

Show example code
# Create index on vector field
index_params = client.prepare_index_params()
index_params.add_index(
field_name="vec",
index_type="AUTOINDEX",
index_name="vec_index",
metric_type="COSINE"
)
client.create_index(collection_name, index_params)
print("Index created successfully.")

# Load the collection
client.load_collection(collection_name)
print(f"Collection '{collection_name}' loaded successfully.")

基于时间戳过滤的查询

使用算术运算符(如 ==、!=、<、>、<=、>=)。

有关 Zilliz Cloud 中可用的完整算术运算符列表,请参考 基本操作符

📘说明

不支持链式范围表达式(例如 lower_bound < tsz < upper_bound)。

请改用逻辑与条件,例如:tsz > lower_bound AND tsz < upper_bound

下面的示例会过滤出时间戳字段 tsz 不等于 2025-01-03T00:00:00+08:00 的实体:

# Query for entities where tsz is not equal to '2025-01-03T00:00:00+08:00'
# highlight-next-line
expr = "tsz != ISO '2025-01-03T00:00:00+08:00'"

results = client.query(
collection_name=collection_name,
filter=expr,
output_fields=["id", "tsz"],
limit=10
)

print("Query result: ", results)

# Expected output:
# Query result: data: ["{'id': 1, 'tsz': '2024-12-31T16:00:00Z'}", "{'id': 2, 'tsz': '2025-01-01T16:00:00Z'}", "{'id': 4, 'tsz': '2025-01-03T16:00:00Z'}", "{'id': 5, 'tsz': '2025-01-04T16:00:00Z'}", "{'id': 6, 'tsz': '2025-01-05T16:00:00Z'}", "{'id': 7, 'tsz': '2025-01-06T16:00:00Z'}", "{'id': 8, 'tsz': '2025-01-07T16:00:00Z'}", "{'id': 9, 'tsz': '2025-01-08T16:00:00Z'}", "{'id': 10, 'tsz': '2025-01-09T16:00:00Z'}", "{'id': 11, 'tsz': '2025-01-10T16:00:00Z'}"]

在上面的示例中:

  • tsz 是在 schema 中定义的 TIMESTAMPTZ 字段名。

  • ISO '2025-01-03T00:00:00+08:00' 是遵循 ISO 8601 格式的时间戳字面量,包含其时区偏移量。

  • != 用于将字段值与该字面量进行比较。其他支持的运算符包括 ==、<、<=、> 和 >=。

时间区间(Interval)运算

你可以使用 ISO 8601 持续时间格式的 INTERVAL 值对 TIMESTAMPTZ 字段进行时间运算。这使你能够在过滤数据时,对时间戳进行加减运算,例如增加或减少天、小时或分钟。

例如,下面的查询会筛选出时间戳字段(tsz)加上 0 天后不等于 2025-01-03T00:00:00+08:00 的实体:

# highlight-next-line
expr = "tsz + INTERVAL 'P0D' != ISO '2025-01-03T00:00:00+08:00'"

results = client.query(
collection_name,
filter=expr,
output_fields=["id", "tsz"],
limit=10
)

print("Query result: ", results)

# Expected output:
# Query result: data: ["{'id': 1, 'tsz': '2024-12-31T16:00:00Z'}", "{'id': 2, 'tsz': '2025-01-01T16:00:00Z'}", "{'id': 4, 'tsz': '2025-01-03T16:00:00Z'}", "{'id': 5, 'tsz': '2025-01-04T16:00:00Z'}", "{'id': 6, 'tsz': '2025-01-05T16:00:00Z'}", "{'id': 7, 'tsz': '2025-01-06T16:00:00Z'}", "{'id': 8, 'tsz': '2025-01-07T16:00:00Z'}", "{'id': 9, 'tsz': '2025-01-08T16:00:00Z'}", "{'id': 10, 'tsz': '2025-01-09T16:00:00Z'}", "{'id': 11, 'tsz': '2025-01-10T16:00:00Z'}"]
📘说明

INTERVAL 值遵循 ISO 8601 的持续时间语法。例如:

  • P1D → 1 天

  • PT3H → 3 小时

  • P2DT6H → 2 天 6 小时

你可以在过滤表达式中直接使用 INTERVAL 运算,例如:

  • tsz + INTERVAL 'P3D' → 加 3 天

  • tsz - INTERVAL 'PT2H' → 减 2 小时

基于时间戳过滤的向量搜索

你可以将 TIMESTAMPTZ 过滤与向量相似度搜索结合使用,从而同时根据时间与相似度缩小搜索结果范围。

# Define a time-based filter expression
filter = "tsz > ISO '2025-01-05T00:00:00+08:00'"

res = client.search(
collection_name=collection_name, # Collection name
data=[[0.1, 0.2, 0.3, 0.4]], # Query vector (must match collection's vector dim)
limit=5, # Max. number of results to return
# highlight-next-line
filter=filter, # Filter expression using TIMESTAMPTZ
output_fields=["id", "tsz"], # Fields to include in the search results
)

print("Search result: ", res)

# Expected output:
# Search result: data: [[{'id': 10, 'distance': 0.9759000539779663, 'entity': {'tsz': '2025-01-09T16:00:00Z', 'id': 10}}, {'id': 9, 'distance': 0.9759000539779663, 'entity': {'tsz': '2025-01-08T16:00:00Z', 'id': 9}}, {'id': 8, 'distance': 0.9759000539779663, 'entity': {'tsz': '2025-01-07T16:00:00Z', 'id': 8}}, {'id': 7, 'distance': 0.9759000539779663, 'entity': {'tsz': '2025-01-06T16:00:00Z', 'id': 7}}, {'id': 6, 'distance': 0.9759000539779663, 'entity': {'tsz': '2025-01-05T16:00:00Z', 'id': 6}}]]
📘说明

如果你的 Collection 包含两个或以上的向量字段,你可以在执行混合搜索时结合时间戳过滤。详情请参考多向量混合搜索

高级用法

在高级场景中,你可以在不同层级(例如数据库、Collection 或查询)管理时区,或通过索引加速对 TIMESTAMPTZ 字段的查询。

在不同层级管理时区

你可以在Collection 级或查询/搜索级为 TIMESTAMPTZ 字段控制时区。

层级

参数

范围

优先级

Collection

timezone

覆盖 Database 级默认时区,仅作用于该 Collection

中等

Query/search/hybrid search

timezone

针对某次操作的临时覆盖

最高

要查看分步骤说明与示例代码,请参阅以下页面:

加速查询

默认情况下,如果 TIMESTAMPTZ 字段未建立索引,查询将对所有行执行全表扫描,这在大型数据集中会非常缓慢。

要加速时间戳相关的查询,请在 TIMESTAMPTZ 字段上创建 AUTOINDEX 索引。

更多详情请参考 创建 Scalar Index