跳到主要内容
版本:v3.0.x

Geometry 字段

在构建地理信息系统(GIS)、制图工具或基于位置的服务等应用程序时,您经常需要存储和查询几何数据。Milvus 中的 GEOMETRY 数据类型提供了一种本地方式来存储和查询灵活的几何数据,从而解决了这一难题。

例如,当应用需要将向量相似度与空间约束结合时,可以使用 GEOMETRY 字段:

  • 位置服务(LBS):查找位于指定城市街区内的相似 POI。

  • 多模态搜索:检索距离指定坐标 1 km 范围内的相似照片。

  • 地图与物流:查询区域内的资产,或查找与指定路径相交的路线。

说明

要使用 GEOMETRY 字段,请将 SDK 升级到最新版本。

什么是 Geometry 字段?

GEOMETRY 是 Milvus Schema 中用于存储几何数据的字段类型,对应 SDK 标识符 DataType.GEOMETRY。写入和查询时可以使用人类可读的 Well-known text(WKT) 表示;Milvus 在内部将其转换为更适合存储和计算的 Well-known binary(WKB),应用程序通常不需要直接处理 WKB。

GEOMETRY 数据类型支持以下几何对象:

  • POINT (x y);例如,POINT (13.403683 52.520711),其中 x = 经度,y = 纬度

  • LINESTRINGLINESTRING (x1 y1, x2 y2, …);例如,LINESTRING (13.40 52.52, 13.41 52.51)

  • POLYGONPOLYGON ((x1 y1, x2 y2, x3 y3, x1 y1));例如,POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))

  • MULTIPOINTMULTIPOINT ((x1 y1), (x2 y2), …);例如,MULTIPOINT ((10 40), (40 30), (20 20), (30 10))

  • MULTILINESTRINGMULTILINESTRING ((x1 y1, …), (xk yk, …));例如,MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10))

  • MULTIPOLYGONMULTIPOLYGON (((outer ring ...)), ((outer ring ...)));例如,MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))

  • GEOMETRYCOLLECTIONGEOMETRYCOLLECTION(POINT(x y), LINESTRING(x1 y1, x2 y2), ...);例如,GEOMETRYCOLLECTION (POINT (40 10), LINESTRING (10 10, 20 20, 10 40), POLYGON ((40 40, 20 45, 45 30, 40 40)))

基本工作流

使用 GEOMETRY 字段的工作流程包括在 Collection Schema 中定义字段、插入几何数据,然后使用特定的过滤表达式查询数据。

步骤 1:定义 Geometry 字段

要使用 GEOMETRY 字段,请在 Collection Schema 中显式定义该字段。下面的示例创建一个 Collection,并将 geo 字段定义为 DataType.GEOMETRY

Python
from pymilvus import MilvusClient, DataType
import numpy as np

dim = 8
collection_name = "geo_collection"
milvus_client = MilvusClient("http://localhost:19530")

# Create schema with a GEOMETRY field
schema = milvus_client.create_schema(enable_dynamic_field=True)
schema.add_field("id", DataType.INT64, is_primary=True)
schema.add_field("embeddings", DataType.FLOAT_VECTOR, dim=dim)
schema.add_field("geo", DataType.GEOMETRY, nullable=True)
schema.add_field("name", DataType.VARCHAR, max_length=128)

milvus_client.create_collection(collection_name, schema=schema, consistency_level="Strong")
说明

本示例将 GEOMETRY 字段设为可空。有关可空字段的约束与默认值行为,请参阅 Nullable 与默认值

步骤 2:插入数据

WKT 格式写入 Geometry 数据。下面的示例插入多个地理坐标点:

Python
rng = np.random.default_rng(seed=19530)
geo_points = [
'POINT(13.399710 52.518010)',
'POINT(13.403934 52.522877)',
'POINT(13.405088 52.521124)',
'POINT(13.408223 52.516876)',
'POINT(13.400092 52.521507)',
'POINT(13.408529 52.519274)',
]

rows = [
{"id": 1, "name": "Shop A", "embeddings": rng.random((1, dim))[0], "geo": geo_points[0]},
{"id": 2, "name": "Shop B", "embeddings": rng.random((1, dim))[0], "geo": geo_points[1]},
{"id": 3, "name": "Shop C", "embeddings": rng.random((1, dim))[0], "geo": geo_points[2]},
{"id": 4, "name": "Shop D", "embeddings": rng.random((1, dim))[0], "geo": geo_points[3]},
{"id": 5, "name": "Shop E", "embeddings": rng.random((1, dim))[0], "geo": geo_points[4]},
{"id": 6, "name": "Shop F", "embeddings": rng.random((1, dim))[0], "geo": geo_points[5]},
]

insert_result = milvus_client.insert(collection_name, rows)
print(insert_result)

# Expected output:
# {'insert_count': 6, 'ids': [1, 2, 3, 4, 5, 6]}

步骤 3:使用空间过滤

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

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

  • 已将 Collection 载入内存。

显示代码
Python
index_params = milvus_client.prepare_index_params()
index_params.add_index(field_name="embeddings", metric_type="L2")

milvus_client.create_index(collection_name, index_params)
milvus_client.load_collection(collection_name)

满足这些要求后,您就可以使用带有专用几何运算符的表达式,根据几何值对 Collection 进行过滤。

定义空间过滤表达式

要在 GEOMETRY 字段上进行筛选,请在表达式中使用几何运算符:

  • 一般:{operator}(geo_field, '{wkt}')

  • 基于距离:ST_DWITHIN(geo_field, '{wkt}', distance)

其中

  • operator 是支持的几何运算符之一(如 ST_CONTAINS,ST_INTERSECTS)。运算符名称必须全部大写或小写。有关支持的运算符列表,请参阅 支持的几何图形运算符

  • geo_fieldGEOMETRY 字段的名称。

  • '{wkt}' 是要查询的几何体的 WKT 表示形式。

  • distance 是专门用于 ST_DWITHIN 的阈值。

以下示例演示了如何在筛选表达式中使用不同的几何图形专用运算符:

示例 1:查找矩形区域内的 Entity

Python
top_left_lon, top_left_lat = 13.403683, 52.520711
bottom_right_lon, bottom_right_lat = 13.455868, 52.495862
bounding_box_wkt = f"POLYGON(({top_left_lon} {top_left_lat}, {bottom_right_lon} {top_left_lat}, {bottom_right_lon} {bottom_right_lat}, {top_left_lon} {bottom_right_lat}, {top_left_lon} {top_left_lat}))"

query_results = milvus_client.query(
collection_name,
filter=f"st_within(geo, '{bounding_box_wkt}')",
output_fields=["name", "geo"]
)
for ret in query_results:
print(ret)

# Expected output:
# {'name': 'Shop D', 'geo': 'POINT (13.408223 52.516876)', 'id': 4}
# {'name': 'Shop F', 'geo': 'POINT (13.408529 52.519274)', 'id': 6}

例 2:查找距离中心点 1km 范围内的 Entity

Python
center_point_lon, center_point_lat = 13.403683, 52.520711
radius_meters = 1000.0
central_point_wkt = f"POINT({center_point_lon} {center_point_lat})"

query_results = milvus_client.query(
collection_name,
filter=f"st_dwithin(geo, '{central_point_wkt}', {radius_meters})",
output_fields=["name", "geo"]
)
for ret in query_results:
print(ret)

# Expected output:
# hit: {'id': 4, 'distance': 0.9823770523071289, 'entity': {'name': 'Shop D', 'geo': 'POINT (13.408223 52.516876)'}}

例 3:将向量相似性与空间过滤条件相结合

Python
vectors_to_search = rng.random((1, dim))
result = milvus_client.search(
collection_name,
vectors_to_search,
limit=3,
output_fields=["name", "geo"],
filter=f"st_within(geo, '{bounding_box_wkt}')"
)
for hits in result:
for hit in hits:
print(f"hit: {hit}")

# Expected output:
# hit: {'id': 6, 'distance': 1.3406795263290405, 'entity': {'name': 'Shop F', 'geo': 'POINT (13.408529 52.519274)'}}

下一步:加速查询

默认情况下,在没有索引的情况下对 GEOMETRY 字段的查询将对所有行执行全扫描,这在大型数据集上可能会很慢。要加速几何查询,请在 GEOMETRY 字段上创建 RTREE 索引。

有关详细信息,请参阅 RTREE

常见问题

如果 Collection 已启用动态字段,能否在动态字段中写入 Geometry 数据?

不能,几何数据不能插入动态字段。在插入几何数据之前,请确保 GEOMETRY 字段已在 Collection Schema 中明确定义。

Geometry 字段支持 mmap 功能吗?

是的,GEOMETRY 字段支持 mmap。有关详细信息,请参阅 使用 mmap

能否将 GEOMETRY 字段定义为可空或设置默认值?

可以,GEOMETRY 字段支持 nullable 属性和 WKT 格式的默认值。有关详细信息,请参阅 可空和默认值