JSON 欄位概述

在建立商品目錄、內容管理系統或使用者偏好引擎等應用程式時,您通常需要在向量嵌入的同時儲存彈性的元資料。產品屬性因類別而異,使用者偏好隨時間演變,而文件屬性則有複雜的嵌套結構。Milvus 的 JSON 欄位可讓您在不犧牲效能的情況下,儲存和查詢彈性的結構化資料,從而解決這項挑戰。

什麼是 JSON 欄位?

在 Milvus 中,JSON 欄位是一種模式定義的資料類型 (DataType.JSON) ,用來儲存結構化的鍵值資料。與傳統僵化的資料庫列不同,JSON 欄位可容納巢狀物件、陣列和混合資料類型,同時提供多種索引選項以進行快速查詢。

JSON 欄位結構範例:

{
  "metadata": { 
    "category": "electronics",
    "brand": "BrandA",
    "in_stock": true,
    "price": 99.99,
    "string_price": "99.99",
    "tags": ["clearance", "summer_sale"],
    "supplier": {
      "name": "SupplierX",
      "country": "USA",
      "contact": {
        "email": "support@supplierx.com",
        "phone": "+1-800-555-0199"
      }
    }
  }
}

在這個範例中,metadata 是一個單一的 JSON 欄位,包含平面值 (例如category,in_stock)、陣列 (tags) 和巢狀物件 (supplier) 的混合資料。

命名慣例:在 JSON 鍵中只使用字母、數字和底線。避免使用特殊字符、空格或點,因為它們可能會在查詢中導致解析問題。

JSON 欄位 vs. 動態欄位

常見的混淆點是 JSON 欄位與動態欄位之間的差異。雖然兩者都與 JSON 有關,但它們有不同的目的。

下表總結了 JSON 欄位與動態欄位之間的主要差異:

特徵

JSON 欄位

動態欄位

模式定義

一個標量欄位,必須在集合模式中以DataType.JSON 類型明確宣告。

一個隱藏的 JSON 欄位 (命名為$meta),可自動儲存未宣告的欄位。

使用情況

儲存模式已知且一致的結構化資料。

儲存不符合固定模式的彈性、演進或半結構化資料。

控制

您可以控制欄位名稱和結構。

系統管理未定義的欄位。

查詢

使用您的欄位名稱或 JSON 欄位內的目標關鍵查詢:metadata["key"]

直接使用動態欄位關鍵查詢:"dynamic_key" 或透過$meta$meta["dynamic_key"]

基本操作

使用 JSON 欄位的基本工作流程包括在模式中定義、插入資料,然後透過特定的篩選表達式查詢資料。

定義 JSON 欄位

要使用 JSON 欄位,請在建立集合時,在集合模式中明確定義。下面的示例演示了如何使用metadata 欄位類型DataType.JSON 來創建一個集合:

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530") # Replace with your server address 

# Create schema
schema = client.create_schema(auto_id=False, enable_dynamic_field=True)

schema.add_field(field_name="product_id", datatype=DataType.INT64, is_primary=True) # Primary field
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5) # Vector field
# Define a JSON field that allows null values
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True)

client.create_collection(
    collection_name="product_catalog",
    schema=schema
)

在這個範例中,在集合模式中定義的 JSON 欄位允許使用nullable=True 的 null 值。詳情請參閱Nullable & Default

插入資料

建立資料集後,在指定的 JSON 欄位中插入包含結構化 JSON 物件的實體。您的資料格式應為字典清單。

entities = [
    {
        "product_id": 1,
        "vector": [0.1, 0.2, 0.3, 0.4, 0.5],
        "metadata": { # JSON field
            "category": "electronics",
            "brand": "BrandA",
            "in_stock": True,
            "price": 99.99,
            "string_price": "99.99",
            "tags": ["clearance", "summer_sale"],
            "supplier": {
                "name": "SupplierX",
                "country": "USA",
                "contact": {
                    "email": "support@supplierx.com",
                    "phone": "+1-800-555-0199"
                }
            }
        }
    }
]

client.insert(collection_name="product_catalog", data=entities)

過濾作業

在您對 JSON 欄位執行過濾作業之前,請確定

  • 您已在每個向量欄位上建立索引。

  • 集合已載入記憶體。

顯示程式碼

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="vector",
    index_type="AUTOINDEX",
    index_name="vector_index",
    metric_type="COSINE"
)

client.create_index(collection_name="product_catalog", index_params=index_params)

client.load_collection(collection_name="product_catalog")

一旦滿足這些要求,您就可以使用下面的表達式,根據 JSON 欄位內的值對集合進行篩選。這些篩選表達式利用特定的 JSON 路徑語法和專用運算符號。

使用 JSON 路徑語法篩選

若要查詢特定的鍵,請使用括號符號存取 JSON 鍵:json_field_name["key"] 。對於嵌套的鍵,請將它們鏈結在一起:json_field_name["key1"]["key2"]

要過濾category"electronics" 的實體:

# Define filter expression
filter = 'metadata["category"] == "electronics"'

client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

要篩選嵌套鍵supplier["country"]"USA" 的實體:

# Define filter expression
filter = 'metadata["supplier"]["country"] == "USA"'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

print(res)

使用 JSON 特定的運算符號過濾

Milvus 也提供特殊的運算符號來查詢特定 JSON 欄位鍵的陣列值。例如

  • json_contains(identifier, expr):檢查 JSON 陣列中是否存在特定元素或子陣列

  • json_contains_all(identifier, expr):確保指定的 JSON 表達式的所有元素都存在於欄位中

  • json_contains_any(identifier, expr):過濾至少有一個 JSON 表達式成員存在於欄位中的實體

尋找在tags 鍵下有"summer_sale" 值的產品:

# Define filter expression
filter = 'json_contains(metadata["tags"], "summer_sale")'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

print(res)

尋找在tags 鍵下至少有一個"electronics","new", 或"clearance" 值的產品:

# Define filter expression
filter = 'json_contains_any(metadata["tags"], ["electronics", "new", "clearance"])'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

print(res)

有關 JSON 特定運算符號的詳細資訊,請參閱JSON 運算符號

下一步:加速 JSON 查詢

預設情況下,在沒有加速的情況下,對 JSON 欄位的查詢會對所有行執行完整掃描,這在大型資料集上可能會很慢。為了加速 JSON 查詢,Milvus 提供了先進的索引和儲存優化功能。

下表總結了它們的差異和最佳使用情境:

技術

最適用於

陣列 加速

注意事項

JSON 索引

一小組經常存取的鍵,特定陣列鍵上的陣列

是(在索引陣列鍵上)

必須預先選擇鍵,如果模式演進則需要維護

JSON 切碎

在多個鍵值上普遍加速,可彈性處理各種查詢

否(不會加速陣列內的值)

額外的儲存配置,陣列仍需要每個鍵的索引

NGRAM 索引

通配符搜尋、文字欄位中的子串匹配

不適用

不適用於數值/範圍篩選器

提示:您可以結合這些方法--例如,使用 JSON 切碎來加速廣泛的查詢,使用 JSON 索引來處理高頻陣列鍵,使用 NGRAM 索引來處理彈性的文字搜尋。

如需實施細節,請參閱:

常見問題

JSON 欄位的大小有任何限制嗎?

有。每個 JSON 欄位的大小限制為 65,536 位元組。

JSON 欄位是否支援設定預設值?

不,JSON 欄位不支援預設值。但是,您可以在定義欄位時設定nullable=True ,以允許空項目。

詳情請參閱Nullable & Default

JSON 欄位鍵有任何命名慣例嗎?

有,以確保與查詢和索引的相容性:

  • 在 JSON 鍵中只使用字母、數字和底線。

  • 避免使用特殊字符、空格或點 (.,/, 等等)。

  • 不相容的鍵可能會在篩選表達式中造成解析問題。

Milvus 如何處理 JSON 欄位中的字串值?

Milvus 完全按照 JSON 輸入中出現的字串值來儲存,沒有語義轉換。引號不當的字串可能會在解析過程中導致錯誤。

有效字串的範例

"a\"b", "a'b", "a\\b"

無效字串的範例

'a"b', 'a\'b'