メインコンテンツまでスキップ
バージョン: User Guides (BYOC)

ジオメトリーフィールド

地理情報システム(GIS)、マッピングツール、位置ベースのサービスなどのアプリケーションを構築する際、ジオメトリーデータを保存およびクエリする必要がよくあります。Milvusの GEOMETRY データ型は、柔軟なジオメトリーデータを保存およびクエリするためのネイティブな方法を提供することでこの課題を解決します。

ベクトル類似性と空間制約を組み合わせる必要がある場合に、ジオメトリーフィールドを使用してください。以下のような例があります:

  • 位置ベースサービス(LBS): "この街区内で類似するPOIを検索"

  • マルチモーダル検索: "この地点から1km以内で類似する写真を検索"

  • マップと物流: "ある領域の資産" または "あるルートと交差する経路"

📘注意

ジオメトリーフィールドを使用するには、SDKを最新バージョンにアップグレードしてください。

ジオメトリーフィールドとは?

ジオメトリーフィールドは、Zilliz Cloudのスキーマ定義データ型(DataType.GEOMETRY)であり、ジオメトリーデータを格納します。ジオメトリーフィールドを使用する際は、Well-Known Text (WKT)形式を使用してデータを操作します。これは、データの挿入とクエリの両方で使用される人間が読める形式です。内部的には、Zilliz CloudはWKTをWell-Known Binary (WKB)に変換して効率的な保存と処理を行いますが、WKBを直接操作する必要はありません。

GEOMETRY データ型は以下のジオメトリーオブジェクトをサポートします:

  • ポイント(POINT): POINT (x y);例:POINT (13.403683 52.520711) ただし x = 経度、y = 緯度

  • ラインストリング(LINESTRING): LINESTRING (x1 y1, x2 y2, …);例:LINESTRING (13.40 52.52, 13.41 52.51)

  • ポリゴン(POLYGON): POLYGON ((x1 y1, x2 y2, x3 y3, x1 y1));例:POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))

  • マルチポイント(MULTIPOINT): MULTIPOINT ((x1 y1), (x2 y2), …)、例:MULTIPOINT ((10 40), (40 30), (20 20), (30 10))

  • マルチラインストリング(MULTILINESTRING): MULTILINESTRING ((x1 y1, …), (xk yk, …))、例:MULTILINESTRING ((10 10, 20 20, 10 40), (40 40, 30 30, 40 20, 30 10))

  • マルチポリゴン(MULTIPOLYGON): MULTIPOLYGON (((outer ring ...)), ((outer ring ...)))、例:MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))

  • ジオメトリコレクション(GEOMETRYCOLLECTION): GEOMETRYCOLLECTION(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 フィールドを使用するワークフローには、コレクションスキーマ内でそれを定義し、ジオメトリーデータを挿入し、特定のフィルター式を使用してデータをクエリすることが含まれます。

ステップ1: ジオメトリーフィールドを定義

GEOMETRY フィールドを使用するには、コレクションを作成する際にコレクションスキーマで明示的に定義します。以下の例は、DataType.GEOMETRY 型の geo フィールドを持つコレクションを作成する方法を示しています。

from pymilvus import MilvusClient, DataType
import numpy as np

dim = 8
collection_name = "geo_collection"
milvus_client = MilvusClient("YOUR_CLUSTER_ENDPOINT")

# GEOMETRYフィールドを持つスキーマを作成
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=Trueでnull値を許容します。詳細はNull許容性とデフォルトを参照してください。

ステップ2: データを挿入

Well-Known Text (WKT)形式でジオメトリーデータをエンティティに挿入します。以下はいくつかのジオポイントを持つ例です:

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)

# 期待される出力:
# {'insert_count': 6, 'ids': [1, 2, 3, 4, 5, 6]}

ステップ3: フィルタリング操作

GEOMETRY フィールドに対してフィルタリング操作を実行する前に、以下のことを確認してください:

  • すべてのベクトルフィールドにインデックスを作成しました。

  • コレクションがメモリにロードされています。

コードを表示
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)

これらの要件を満たしたら、ジオメトリーオペレータを持つ式を使用してジオメトリ値に基づいてコレクションをフィルタリングできます。

フィルター式の定義

GEOMETRY フィールドをフィルタリングするには、式でジオメトリーオペレータを使用します:

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

  • 距離ベース: ST_DWITHIN(geo_field, '{wkt}', distance)

以下は上記のパラメータを説明します:

  • operator はサポートされているジオメトリーオペレータのいずれか(例:ST_CONTAINSST_INTERSECTS)です。オペレータ名はすべて大文字またはすべて小文字にする必要があります。サポートされているオペレータのリストはサポートされているジオメトリーオペレータを参照してください。

  • geo_fieldGEOMETRY フィールドの名前です。

  • '{wkt}' はクエリするジオメトリのWKT表現です。

  • distanceST_DWITHIN に特化したしきい値です。

以下の例は、フィルター式でさまざまなジオメトリ固有のオペレータを使用する方法を示しています:

例1: 矩形領域内のエンティティを検索

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)

# 期待される出力:
# {'name': 'Shop D', 'geo': 'POINT (13.408223 52.516876)', 'id': 4}
# {'name': 'Shop F', 'geo': 'POINT (13.408529 52.519274)', 'id': 6}
# {'name': 'Shop A', 'geo': 'POINT (13.39971 52.51801)', 'id': 1}
# {'name': 'Shop B', 'geo': 'POINT (13.403934 52.522877)', 'id': 2}
# {'name': 'Shop C', 'geo': 'POINT (13.405088 52.521124)', 'id': 3}
# {'name': 'Shop D', 'geo': 'POINT (13.408223 52.516876)', 'id': 4}
# {'name': 'Shop E', 'geo': 'POINT (13.400092 52.521507)', 'id': 5}
# {'name': 'Shop F', 'geo': 'POINT (13.408529 52.519274)', 'id': 6}

例2: 中心点から1km以内のエンティティを検索

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)

# 期待される出力:
# hit: {'id': 4, 'distance': 0.9823770523071289, 'entity': {'name': 'Shop D', 'geo': 'POINT (13.408223 52.516876)'}}

例3: ベクトル類似性と空間フィルターを組み合わせる

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}")

# 期待される出力:
# hit: {'id': 6, 'distance': 1.3406795263290405, 'entity': {'name': 'Shop F', 'geo': 'POINT (13.408529 52.519274)'}}

次へ: クエリの高速化

デフォルトでは、インデックスなしの GEOMETRY フィールドに対するクエリはすべての行を完全スキャンするため、大規模データセットでは遅くなる可能性があります。ジオメトリッククエリを高速化するには、GEOMETRYフィールドに AUTOINDEX インデックスを作成します。

詳細はスカラーフィールドのインデックスを参照してください。

よくある質問

コレクションで動的フィールド機能を有効にしている場合、動的フィールドキーにジオメトリーデータを挿入できますか?

いいえ、ジオメトリーデータは動的フィールドに挿入できません。ジオメトリーデータを挿入する前に、GEOMETRY フィールドがコレクションスキーマで明示的に定義されていることを確認してください。

GEOMETRYフィールドはmmap機能をサポートしていますか?

はい、GEOMETRY フィールドはmmapをサポートしています。詳細はmmapの使用を参照してください。

GEOMETRYフィールドをNull許容として定義したり、デフォルト値を設定したりできますか?

はい、GEOMETRYフィールドは nullable 属性とWKT形式のデフォルト値をサポートしています。詳細はNull許容性とデフォルトを参照してください。