
qdrant 当前版本(v1.7.x 及更早)不支持直接使用 datetime 对象进行范围过滤,需将时间转换为 unix 时间戳(整型秒或毫秒)后,通过 range 过滤器进行数值比较。
qdrant 当前版本(v1.7.x 及更早)不支持直接使用 datetime 对象进行范围过滤,需将时间转换为 unix 时间戳(整型秒或毫秒)后,通过 range 过滤器进行数值比较。
在 Qdrant 中,所有字段过滤均基于底层存储的数据类型,而时间戳字段(如 “timestamp”)在向量点(point)元数据中必须以数值形式(int 或 Float)存储,才能被 range 过滤器正确解析。直接传入 python 的 datetime 对象会导致类型校验失败,抛出类似 input should be a valid number 的 Pydantic 错误。
✅ 正确做法是:统一使用 Unix 时间戳(毫秒级整数)表示时间,并确保写入与查询时类型一致。
1. 写入数据时:将 datetime 转为毫秒时间戳
from datetime import datetime from qdrant_client import QdrantClient from qdrant_client.models import PointStruct, Payload # 示例:构造带时间戳的点 dt = datetime(2024, 2, 22, 10, 4, 28, 658690) timestamp_ms = int(dt.timestamp() * 1000) # 转为毫秒级整数(推荐,精度更高) point = PointStruct( id=1, vector=[0.1, 0.2, 0.3], payload={ "text": "log entry", "timestamp": timestamp_ms # ✅ 存为 int } ) qdrant_client = QdrantClient("http://localhost:6333") qdrant_client.upsert(Collection_name="logs", points=[point])
2. 查询时:同样使用毫秒时间戳构建 range 过滤器
from datetime import datetime # 构造查询起始时间 start_dt = datetime(2024, 2, 22, 10, 0, 0) start_ts_ms = int(start_dt.timestamp() * 1000) # 构建过滤查询(gte: 大于等于该时间) query_filter = { "bool": { "filter": [ { "range": { "timestamp": {"gte": start_ts_ms} } } ] } } # 执行向量搜索(带过滤) search_result = qdrant_client.search( collection_name="logs", query_vector=[0.1, 0.2, 0.3], query_filter=query_filter, limit=10 )
⚠️ 关键注意事项
- 单位一致性:务必统一使用「毫秒」(推荐)或「秒」,但不能混用;Qdrant 本身无时间单位概念,仅做数值比较。
- 字段类型预设:确保 collection schema 中 timestamp 字段未被错误声明为 String;若使用 create_collection,无需显式声明基础类型(Qdrant 自动推断),但 payload 中值必须为 int/float。
- 时区处理:datetime.timestamp() 默认基于本地时区转换;如需 UTC 时间,请使用 datetime.utcnow().timestamp() 或更安全的 datetime.now(timezone.utc).timestamp()(Python 3.9+)。
- 未来兼容性:Qdrant v1.8.0 将原生支持 datetime 类型字段及 ISO 格式字符串过滤(如 “2024-02-22T10:04:28.658Z”),但当前稳定版仍需手动转换。
✅ 总结
只要坚持「写入用毫秒整数、查询用毫秒整数」这一原则,即可在现有 Qdrant 版本中稳健实现高精度时间范围过滤。该方案性能优异、零依赖、完全兼容 SDK 各版本,是生产环境中的标准实践。