1?動態字段
????????Collections 的 Schema 中定義的所有字段都必須包含在要插入的實體中。如果希望某些字段是可選的,可以考慮啟用動態字段。
1.1?概述
????????在 Milvus 中,可以通過設置 Collections 中每個字段的名稱和數據類型來創建 Collections Schema。向 Schema 中添加字段時,請確保該字段包含在要插入的實體中。如果希望某些字段是可選的,啟用動態字段是一種選擇。
????????動態字段是一個名為$meta?的保留字段,屬于 JavaScript Object Notation(JSON)類型。實體中任何未在 Schema 中定義的字段都將以鍵值對的形式存儲在這個保留的 JSON 字段中。對于啟用了動態字段的 Collections,可以使用動態字段中的鍵進行標量過濾,就像使用模式中明確定義的字段一樣。
1.2?啟用動態字段
????????使用 "即時創建集合"中描述的方法創建的集合默認已啟用動態字段。也可以在創建具有自定義設置的 Collections 時手動啟用動態字段。
from pymilvus import MilvusClientclient= MilvusClient(uri="http://localhost:19530")client.create_collection(collection_name="my_collection",dimension=5,# highlight-next-lineenable_dynamic_field=True
)
1.3?使用動態字段
????????當在 Collections 中啟用動態字段時,所有未在 Schema 中定義的字段及其值都將作為鍵值對存儲在動態字段中。例如,假設您的 Collections Schema 只定義了兩個字段,名為id
?和vector
?,并啟用了動態字段。現在,在此 Collections 中插入以下數據集。
[{id: 0, vector: [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592], color: "pink_8682"},{id: 1, vector: [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104], color: "red_7025"},{id: 2, vector: [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592], color: "orange_6781"},{id: 3, vector: [0.3172005263489739, 0.9719044792798428, -0.36981146090600725, -0.4860894583077995, 0.95791889146345], color: "pink_9298"},{id: 4, vector: [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106], color: "red_4794"},{id: 5, vector: [0.985825131989184, -0.8144651566660419, 0.6299267002202009, 0.1206906911183383, -0.1446277761879955], color: "yellow_4222"},{id: 6, vector: [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192, -0.8984947637863987], color: "red_9392"},{id: 7, vector: [-0.33445148015177995, -0.2567135004164067, 0.8987539745369246, 0.9402995886420709, 0.5378064918413052], color: "grey_8510"},{id: 8, vector: [0.39524717779832685, 0.4000257286739164, -0.5890507376891594, -0.8650502298996872, -0.6140360785406336], color: "white_9381"},{id: 9, vector: [0.5718280481994695, 0.24070317428066512, -0.3737913482606834, -0.06726932177492717, -0.6980531615588608], color: "purple_4976"}
]
????????上面的數據集包含 10 個實體,每個實體都包括字段id
,vector
, 和color
?。這里,Schema 中沒有定義color
?字段。由于 Collections 啟用了動態字段,因此字段color
?將作為鍵值對存儲在動態字段中。
1.3.1?插入數據
????????以下代碼演示了如何將此數據集插入 Collections。
data=[{"id": 0, "vector": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592], "color": "pink_8682"},{"id": 1, "vector": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104], "color": "red_7025"},{"id": 2, "vector": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592], "color": "orange_6781"},{"id": 3, "vector": [0.3172005263489739, 0.9719044792798428, -0.36981146090600725, -0.4860894583077995, 0.95791889146345], "color": "pink_9298"},{"id": 4, "vector": [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106], "color": "red_4794"},{"id": 5, "vector": [0.985825131989184, -0.8144651566660419, 0.6299267002202009, 0.1206906911183383, -0.1446277761879955], "color": "yellow_4222"},{"id": 6, "vector": [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192, -0.8984947637863987], "color": "red_9392"},{"id": 7, "vector": [-0.33445148015177995, -0.2567135004164067, 0.8987539745369246, 0.9402995886420709, 0.5378064918413052], "color": "grey_8510"},{"id": 8, "vector": [0.39524717779832685, 0.4000257286739164, -0.5890507376891594, -0.8650502298996872, -0.6140360785406336], "color": "white_9381"},{"id": 9, "vector": [0.5718280481994695, 0.24070317428066512, -0.3737913482606834, -0.06726932177492717, -0.6980531615588608], "color": "purple_4976"}
]res = client.insert(collection_name="my_collection",data=data
)print(res)# Output
# {'insert_count': 10, 'ids': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
1.3.2?在動態字段中索引標量字段
????????啟用動態字段后,任何未定義的標量字段都會以 JSON 格式存儲為鍵值對。Milvus 支持在這種未定義的標量字段上創建索引,有效的方法是建立一個 JSON 路徑索引。具體操作如下
-
選擇要索引的 Dynamic Field 關鍵字。例如,上例中的
"color"
?。 -
為在該關鍵字中找到的值決定一個鑄模類型。Milvus 將解析動態字段,提取指定鍵下的值,并將它們轉換為你配置的類型。
-
支持的
json_cast_type
?值有bool
?(或BOOL
?)、double
?(或DOUBLE
?)和varchar
?(或VARCHAR
?)。 -
如果解析或轉換失敗(例如,試圖將字符串解析為 double),索引將跳過這些行。
-
-
將該鍵的JSON 路徑指定為
json_path
?。由于動態字段是以 JSON 格式存儲的,因此可以指定類似"color"
?這樣的路徑,如果有嵌套結構,則可以指定更深的路徑(例如my_json["field"]["subfield"]
?)。 -
創建 INVERTED 索引。目前,JSON 路徑索引只支持
INVERTED
?類型。
????????下面是如何在"color"
?字段上創建索引的示例:
# 準備索引參數
index_params = client.prepare_index_params()index_params.add_index(field_name="color", # 在查詢中看到的“列”的名稱(動態鍵)。index_type="INVERTED", # 目前,JSON字段的索引只支持“INVERTED”。index_name="color_index", # 為這個索引指定一個名稱。params={"json_path": "color", # 要索引的鍵的JSON路徑。"json_cast_type": "varchar" # Milvus將將提取的值強制轉換到的類型。}
)# Create the index
client.create_index(collection_name="my_collection",index_params=index_params
)
1.3.3?使用動態字段進行查詢和搜索
????????Milvus 支持在查詢和搜索過程中使用過濾表達式,允許您指定在結果中包含哪些字段。下面的示例演示了如何通過動態字段使用color
?字段執行查詢和搜索,該字段在 Schema 中沒有定義。
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]res = client.search(collection_name="my_collection",data=[query_vector],limit=5,# highlight-startfilter='color like "red%"',output_fields=["color"]# highlight-end
)print(res)# Output
# data: ["[{'id': 1, 'distance': 0.6290165185928345, 'entity': {'color': 'red_7025'}}, {'id': 4, 'distance': 0.5975797176361084, 'entity': {'color': 'red_4794'}}, {'id': 6, 'distance': -0.24996188282966614, 'entity': {'color': 'red_9392'}}]"]
????????在上面代碼示例中使用的過濾表達式color like "red%" and likes > 50
?中,條件指定color
?字段的值必須以"紅色 "開頭。
[{"id": 1, "distance": 0.6290165,"entity": {"color": "red_7025"}},{"id": 4, "distance": 0.5975797,"entity": {"color": "red_4794"}},{"id": 6, "distance": -0.24996188,"entity": {"color": "red_9392"}},
]
2?可歸零和默認值
????????Milvus 允許你為標量字段(主字段除外)設置nullable
?屬性和默認值。對于標記為nullable=True
?的字段,您可以在插入數據時跳過該字段,或直接將其設置為空值,系統會將其視為空值而不會導致錯誤。當字段具有默認值時,如果在插入過程中沒有為該字段指定數據,系統將自動應用該值。
????????默認值和可歸零屬性允許處理帶有空值的數據集并保留默認值設置,從而簡化了從其他數據庫系統到 Milvus 的數據遷移。在創建 Collections 時,也可以啟用可歸零屬性或為可能存在不確定值的字段設置默認值。
2.1?限制
- 只有標量字段(主字段除外)支持默認值和 nullable 屬性。
- JSON 和數組字段不支持默認值。
- 默認值或 nullable 屬性只能在創建 Collections 時配置,之后不能修改。
- 啟用了可歸零屬性的標量字段不能在分組搜索中用作
group_by_field
?。 - 標記為可歸零的字段不能用作分區鍵。
- 在啟用了可歸零屬性的標量字段上創建索引時,索引將排除空值。
- JSON 和 ARRAY 字段:當使用
IS NULL
?或IS NOT NULL
?操作符對 JSON 或 ARRAY 字段進行篩選時,這些操作符在列級別工作,這表明它們只評估整個 JSON 對象或數組是否為空。例如,如果 JSON 對象中的某個鍵為空,IS NULL
?過濾器將無法識別該鍵。
2.2?Nullable 屬性
????????通過nullable
?屬性,可以在 Collections 中存儲空值,從而在處理未知數據時提供靈活性。
2.2.1?設置 nullable 屬性
????????創建 Collections 時,使用nullable=True
?定義可歸零字段(默認為False
?)。下面的示例創建了一個名為my_collection
?的 Collection,并將age
?字段設置為可歸零:
from pymilvus import MilvusClient, DataTypeclient = MilvusClient(uri='http://localhost:19530')# 定義集合模式
schema = client.create_schema(auto_id=False,enable_dynamic_schema=True,
)schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)
schema.add_field(field_name="age", datatype=DataType.INT64, nullable=True) # 可空字段# 設置索引參數
index_params = client.prepare_index_params()
index_params.add_index(field_name="vector", index_type="AUTOINDEX", metric_type="L2")# 創建集合
client.create_collection(collection_name="my_collection", schema=schema, index_params=index_params)
2.2.2?插入實體
????????在可空字段中插入數據時,插入空值或直接省略該字段:
data = [{"id": 1, "vector": [0.1, 0.2, 0.3, 0.4, 0.5], "age": 30},{"id": 2, "vector": [0.2, 0.3, 0.4, 0.5, 0.6], "age": None},{"id": 3, "vector": [0.3, 0.4, 0.5, 0.6, 0.7]}
]client.insert(collection_name="my_collection", data=data)
2.2.3?使用空值進行搜索和查詢
????????使用search
?方法時,如果字段包含null
?值,則搜索結果將以空值返回該字段:
res = client.search(collection_name="my_collection",data=[[0.1, 0.2, 0.4, 0.3, 0.128]],limit=2,search_params={"params": {"nprobe": 16}},output_fields=["id", "age"]
)print(res)# Output
# data: ["[{'id': 1, 'distance': 0.15838398039340973, 'entity': {'age': 30, 'id': 1}}, {'id': 2, 'distance': 0.28278401494026184, 'entity': {'age': None, 'id': 2}}]"]
????????當您使用query
?方法進行標量過濾時,空值的過濾結果都是 false,表示不會選擇它們。
# 查看先前插入的數據:
# {"id": 1, "vector": [0.1, 0.2, ..., 0.128], "age": 30}
# {"id": 2, "vector": [0.2, 0.3, ..., 0.129], "age": None}
# {"id": 3, "vector": [0.3, 0.4, ..., 0.130], "age": None} # 省略的age列被視為None
results = client.query(collection_name="my_collection",filter="age >= 0",output_fields=["id", "age"]
)# Example output:
# [
# {"id": 1, "age": 30}
# ]
# Note: ‘ age ’為‘ null ’ (id 2和3)的實體將不會出現在結果中。
????????要返回具有null
?值的實體,可在不使用任何標量過濾條件的情況下進行如下查詢,query
?方法在不帶任何過濾條件的情況下使用時,會檢索 Collections 中的所有實體,包括具有空值的實體。要限制返回實體的數量,必須指定limit
?參數。
null_results = client.query(collection_name="my_collection",filter="", # 不帶任何過濾條件的查詢output_fields=["id", "age"],limit=10
)# Example output:
# [{"id": 2, "age": None}, {"id": 3, "age": None}]
2.3?默認值
????????默認值是分配給標量字段的預設值。如果在插入時沒有為有默認值的字段提供值,系統會自動使用默認值。
2.3.1?設置默認值
????????創建 Collections 時,使用default_value
?參數定義字段的默認值。下面的示例顯示了如何將age
?的默認值設置為18
?,將status
?的默認值設置為"active"
?:
schema = client.create_schema(auto_id=False,enable_dynamic_schema=True,
)schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)
schema.add_field(field_name="age", datatype=DataType.INT64, default_value=18)
schema.add_field(field_name="status", datatype=DataType.VARCHAR, default_value="active", max_length=10)index_params = client.prepare_index_params()
index_params.add_index(field_name="vector", index_type="AUTOINDEX", metric_type="L2")client.create_collection(collection_name="my_collection", schema=schema, index_params=index_params)
2.3.2?插入實體
????????插入數據時,如果省略有默認值的字段或將其值設為空,系統就會使用默認值:
data = [{"id": 1, "vector": [0.1, 0.2, ..., 0.128], "age": 30, "status": "premium"},{"id": 2, "vector": [0.2, 0.3, ..., 0.129]}, # ‘ age ’和‘ status ’使用默認值{"id": 3, "vector": [0.3, 0.4, ..., 0.130], "age": 25, "status": None}, # “status”使用默認值{"id": 4, "vector": [0.4, 0.5, ..., 0.131], "age": None, "status": "inactive"} # ‘ age ’使用默認值
]client.insert(collection_name="my_collection", data=data)
2.3.3?使用默認值進行搜索和查詢
????????在向量搜索和標量過濾過程中,包含默認值的實體與其他實體的處理方式相同。您可以將默認值作為search
?和query
?操作符的一部分。例如,在search
?操作符中,將age
?設置為默認值18
?的實體將包含在結果中:
res = client.search(collection_name="my_collection",data=[[0.1, 0.2, 0.4, 0.3, 0.5]],search_params={"params": {"nprobe": 16}},filter="age == 18", # “age”字段的默認值為18limit=10,output_fields=["id", "age", "status"]
)print(res)# Output
# data: ["[{'id': 2, 'distance': 0.050000004, 'entity': {'id': 2, 'age': 18, 'status': 'active'}}, {'id': 4, 'distance': 0.45000002, 'entity': {'id': 4, 'age': 18, 'status': 'inactive'}}]"]
????????在query
?操作符中,可以直接通過默認值進行匹配或過濾:
# 查詢‘ age ’等于默認值(18)的所有實體
default_age_results = client.query(collection_name="my_collection",filter="age == 18",output_fields=["id", "age", "status"]
)# 查詢“status”等于默認值(“active”)的所有實體
default_status_results = client.query(collection_name="my_collection",filter='status == "active"',output_fields=["id", "age", "status"]
)
2.3.4 適用規則
????????下表總結了可空列和默認值在不同配置組合下的行為。這些規則決定了 Milvus 在嘗試插入空值或未提供字段值時如何處理數據。
可歸零 | 默認值 | 默認值類型 | 用戶輸入 | 結果 | 示例 |
---|---|---|---|---|---|
? | ? | 非空 | 無/空 | 使用默認值 | 字段:? 用戶輸入:空 結果:存儲為 |
? | ? | - | 無/空 | 存儲為空 | 字段:? 用戶輸入:空 結果:存儲為空 |
? | ? | 非空 | 無/空 | 使用默認值 | 字段:? 用戶輸入:空 結果:存儲為 |
? | ? | - | 無/空 | 拋出錯誤 | 字段:? 用戶輸入:空 結果:操作被拒絕,系統提示錯誤 |
? | ? | 空 | 無/空 | 拋出錯誤 | 字段:? 用戶輸入:空 結果:操作符被拒絕,系統提示錯誤 |