Поле TIMESTAMPTZCompatible with Milvus 2.6.6+

Приложениям, которые отслеживают время в разных регионах, например, системам электронной коммерции, инструментам совместной работы или распределенному протоколированию, необходима точная обработка временных меток с учетом часовых поясов. Тип данных TIMESTAMPTZ в Milvus предоставляет такую возможность, сохраняя временные метки с привязкой к часовому поясу.

Что такое поле TIMESTAMPTZ?

Поле TIMESTAMPTZ - это определяемый схемой тип данных (DataType.TIMESTAMPTZ) в Milvus, который обрабатывает входные данные с учетом часовых поясов и хранит все временные точки в виде абсолютного времени UTC:

  • Принимаемый формат ввода: Строки ISO 8601 со смещением часового пояса (например, "2025-05-01T23:59:59+08:00" обозначает 11:59:59 PM 1 мая 2025 года (UTC+08:00)).

  • Внутреннее хранение: Все значения TIMESTAMPTZ нормализуются и хранятся в универсальном координированном времени (UTC).

  • Сравнение и фильтрация: Все операции фильтрации и упорядочивания выполняются в UTC, что обеспечивает последовательные и предсказуемые результаты в разных часовых поясах.

  • Для полей TIMESTAMPTZ можно установить значение nullable=True, допускающее пропущенные значения.

  • Вы можете указать значение временной метки по умолчанию с помощью атрибута default_value в формате ISO 8601.

Подробности см. в разделе Нулевые и по умолчанию.

Основные операции

Основной рабочий процесс использования поля TIMESTAMPTZ повторяет другие скалярные поля в Milvus: определение поля → вставка данных → запрос/фильтр.

Шаг 1: Определение поля TIMESTAMPTZ

Чтобы использовать поле TIMESTAMPTZ, явно определите его в схеме коллекции при создании коллекции. В следующем примере показано, как создать коллекцию с полем tsz типа DataType.TIMESTAMPTZ.

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

server_address = "http://localhost:19530"
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
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.")
// java
// nodejs
// go
# restful

Шаг 2: Вставка данных

Вставьте сущности, содержащие строки ISO 8601 со смещениями часовых поясов.

В приведенном ниже примере в коллекцию вставляется 8 193 строки данных образца. Каждая строка включает:

  • уникальный идентификатор

  • временную метку с учетом часового пояса (шанхайское время)

  • простой 4-мерный вектор

data_size = 8193

# 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.")
// java
// nodejs
// go
# restful

Шаг 3: Операции фильтрации

TIMESTAMPTZ поддерживает скалярные сравнения, интервальную арифметику и извлечение компонентов времени.

Прежде чем выполнять операции фильтрации полей TIMESTAMPTZ, убедитесь, что:

  • Вы создали индекс для каждого векторного поля.

  • Коллекция загружена в память.

Показать код примера

# 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.")
// java
// nodejs
// go
# restful

Запрос с фильтрацией по меткам времени

Используйте арифметические операторы, такие как ==, !=, <, >, <=, >=. Полный список арифметических операторов, доступных в Milvus, приведен в разделе Арифметические операторы.

В примере ниже фильтруются сущности с временными метками (tsz), которые не равны 2025-01-03T00:00:00+08:00:

# Query for entities where tsz is not equal to '2025-01-03T00:00:00+08:00'
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'}"]
// java
// nodejs
// go
# restful

В примере выше,

  • tsz это имя поля TIMESTAMPTZ, определенное в схеме.

  • ISO '2025-01-03T00:00:00+08:00' литерал временной метки в формате ISO 8601, включая смещение часового пояса.

  • != сравнивает значение поля с этим литералом. Другие поддерживаемые операторы: ==, <, <=, > и >=.

Интервальные операции

Вы можете выполнять арифметические операции над полями TIMESTAMPTZ, используя значения INTERVAL в формате длительности ISO 8601. Это позволяет добавлять или вычитать длительности, такие как дни, часы или минуты, из временной метки при фильтрации данных.

Например, следующий запрос фильтрует сущности, в которых временная метка (tsz) плюс ноль дней не равна 2025-01-03T00:00:00+08:00:

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'}"]
// java
// nodejs
// go
# restful

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
    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}}]]
// java
// nodejs
// go
# restful

Если коллекция содержит два или более векторных полей, вы можете выполнять гибридные операции поиска с фильтрацией по меткам времени. Подробнее см. в разделе Многовекторный гибридный поиск.

Расширенное использование

Для расширенного использования можно управлять временными зонами на разных уровнях (например, в базе данных, коллекции или запросе) или ускорять запросы к полям TIMESTAMPTZ с помощью индексов.

Управление часовыми поясами на разных уровнях

Вы можете управлять часовым поясом для полей TIMESTAMPTZ на уровне базы данных, коллекции или запроса/поиска.

Уровень

Параметр

Область применения

Приоритет

База данных

timezone

По умолчанию для всех коллекций в базе данных

Самый низкий

Коллекция

timezone

Отменяет настройку часового пояса по умолчанию базы данных для данной коллекции

Средняя

Запрос/поиск/гибридный поиск

timezone

Временные переопределения для одной конкретной операции

Самый высокий

Пошаговые инструкции и примеры кода см. на соответствующих страницах:

Ускорение запросов

По умолчанию запросы к полям TIMESTAMPTZ без индекса выполняют полное сканирование всех строк, что может быть медленным при работе с большими массивами данных. Чтобы ускорить запросы к временным меткам, создайте индекс STL_SORT для поля TIMESTAMPTZ.

Подробности см. в разделе STL_SORT.