Milvus(23):过滤
Milvus 提供强大的过滤功能,可精确查询数据。过滤表达式允许你针对特定的标量字段,用不同的条件细化搜索结果。
1 算术操作符
Milvus 提供丰富的基本操作符,帮助您高效地过滤和查询数据。这些操作符允许您根据标量字段、数字计算、逻辑条件等来完善搜索条件。了解如何使用这些操作符对于建立精确查询和最大限度地提高搜索效率至关重要。
1.1 比较操作符
比较操作符用于根据相等、不等或大小过滤数据。它们适用于数字和文本字段。
==
等于!=
(不等于)>
大于<
小于>=
(大于或等于)<=
(小于或等于)
假设有一个名为status
的字段,您想查找status
为 "活动 "的所有实体。您可以使用相等操作符==
:
filter = 'status == "active"'
查找status
不是 "非活动 "的实体:
filter = 'status != "inactive"'
如果要查找age
大于 30 的所有实体:
filter = 'age > 30'
要查找price
小于 100 的实体:
filter = 'price < 100'
如果要查找rating
大于或等于 4 的所有实体:
filter = 'rating >= 4'
要查找discount
小于或等于 10% 的实体:
filter = 'discount <= 10'
1.2 范围操作符
范围操作符有助于根据特定的值集或范围过滤数据。
IN
:用于匹配特定集合或范围内的值。LIKE
:用于匹配模式(主要用于文本字段)。
如果要查找color
为 "红色"、"绿色 "或 "蓝色 "的所有实体:
filter = 'color in ["red", "green", "blue"]'
LIKE
操作符用于字符串字段中的模式匹配。它可以匹配文本中不同位置的子串:前缀、后缀和词缀。LIKE
操作符使用%
符号作为通配符,可以匹配任意数量的字符(包括 0)。
要执行前缀匹配,即字符串以给定的模式开始,可以将模式放在开头,然后使用%
匹配其后的任何字符。例如,要查找name
以 "Prod "开头的所有产品:
filter = 'name LIKE "Prod%"'
在后缀匹配中,如果字符串以给定的模式结尾,则将%
符号放在模式的开头。例如,查找name
以 "XYZ "结尾的所有产品:
filter = 'name LIKE "%XYZ"'
要执行词缀匹配,即模式可以出现在字符串的任何位置,可以在模式的开头和结尾处都加上%
符号。例如,要查找name
中包含 "Pro "一词的所有产品:
filter = 'name LIKE "%Pro%"'
1.3 算术操作符
算术操作符允许您根据涉及数字字段的计算创建条件。
+
加法-
减法*
乘法/
除法%
模乘**
幂
查找id
是偶数(即能被 2 整除)的实体:
filter = 'id % 2 == 0'
查找price
升为 2 的幂大于 1000 的实体:
filter = 'price ** 2 > 1000'
1.4 逻辑操作符
逻辑操作符用于将多个条件组合成更复杂的过滤表达式。这些运算符包括AND
,OR
, 和NOT
。
AND
:组合必须全部为真的多个条件。OR
:组合至少一个必须为真的条件。NOT
:否定一个条件。
查找price
大于 100 且stock
大于 50 的所有产品:
filter = 'price > 100 AND stock > 50'
查找color
为 "红色 "或 "蓝色 "的所有产品:
filter = 'color == "red" OR color == "blue"'
查找color
不是 "绿色 "的所有产品:
filter = 'NOT color == "green"'
1.5 IS NULL 和 IS NOT NULL 操作符
IS NULL
和IS NOT NULL
操作符用于根据字段是否包含空值(无数据)过滤字段。操作符不区分大小写,因此可以使用IS NULL
或is null
,以及IS NOT NULL
或is not null
。
IS NULL
:识别特定字段包含空值(即值不存在或未定义)的实体。IS NOT NULL
:识别特定字段包含除空值以外的任何值的实体,即字段具有有效的定义值。
1.5.1 具有空值的正则标量字段
Milvus 允许过滤带空值的常规标量字段,如字符串或数字。空字符串""
不会被视为VARCHAR
字段的空值。
检索description
字段为空值的实体:
filter = 'description IS NULL'
检索description
字段不是空值的实体:
filter = 'description IS NOT NULL'
检索description
字段不是空值且price
字段大于 10 的实体:
filter = 'description IS NOT NULL AND price > 10'
1.5.2 具有空值的 JSON 字段
Milvus 允许过滤包含空值的 JSON 字段。在以下情况下,JSON 字段会被视为空值:
- 整个 JSON 对象被明确设置为 None(空),例如
{"metadata": None}
。 - 实体中完全没有 JSON 字段。
如果 JSON 对象中的某些元素为空(如单个键),则字段仍被视为非空。例如,尽管category
关键字为空,但\{"metadata": \{"category": None, "price": 99.99}}
不会被视为空字段。为进一步说明 Milvus 如何处理带有空值的 JSON 字段,请考虑以下带有 JSON 字段metadata
的示例数据:
data = [{"metadata": {"category": "electronics", "price": 99.99, "brand": "BrandA"},"pk": 1,"embedding": [0.12, 0.34, 0.56]},{"metadata": None, # 整个JSON对象为空"pk": 2,"embedding": [0.56, 0.78, 0.90]},{ # JSON字段‘ metadata ’完全丢失"pk": 3,"embedding": [0.91, 0.18, 0.23]},{"metadata": {"category": None, "price": 99.99, "brand": "BrandA"}, # 单个键值为空"pk": 4,"embedding": [0.56, 0.38, 0.21]}
]
查找metadata
字段丢失或明确设置为 "无 "的实体:
filter = 'metadata IS NULL'# Example output:
# data: [
# "{'metadata': None, 'pk': 2}",
# "{'metadata': None, 'pk': 3}"
# ]
查找metadata
字段不是空值的实体:
filter = 'metadata IS NOT NULL'# Example output:
# data: [
# "{'metadata': {'category': 'electronics', 'price': 99.99, 'brand': 'BrandA'}, 'pk': 1}",
# "{'metadata': {'category': None, 'price': 99.99, 'brand': 'BrandA'}, 'pk': 4}"
# ]
1.5.3 具有空值的 ARRAY 字段
Milvus 允许过滤包含空值的 ARRAY 字段。ARRAY 字段在以下情况下被视为空值:
- 整个 ARRAY 字段明确设置为 None(空),例如
"tags": None
。 - 实体中完全没有 ARRAY 字段。
ARRAY 字段不能包含部分空值,因为 ARRAY 字段中的所有元素必须具有相同的数据类型。为进一步说明 Milvus 如何处理带有空值的 ARRAY 字段,请考虑以下带有 ARRAY 字段tags
的示例数据:
data = [{"tags": ["pop", "rock", "classic"],"ratings": [5, 4, 3],"pk": 1,"embedding": [0.12, 0.34, 0.56]},{"tags": None, # 整个数组为空"ratings": [4, 5],"pk": 2,"embedding": [0.78, 0.91, 0.23]},{ # 标签字段完全缺失"ratings": [9, 5],"pk": 3,"embedding": [0.18, 0.11, 0.23]}
]
检索tags
字段丢失或明确设置为None
的实体:
filter = 'tags IS NULL'# Example output:
# data: [
# "{'tags': None, 'ratings': [4, 5], 'embedding': [0.78, 0.91, 0.23], 'pk': 2}",
# "{'tags': None, 'ratings': [9, 5], 'embedding': [0.18, 0.11, 0.23], 'pk': 3}"
# ]
检索tags
字段不为空的实体:
filter = 'tags IS NOT NULL'# Example output:
# data: [
# "{'metadata': {'category': 'electronics', 'price': 99.99, 'brand': 'BrandA'}, 'pk': 1}",
# "{'metadata': {'category': None, 'price': 99.99, 'brand': 'BrandA'}, 'pk': 4}"
# ]
1.6 在 JSON 和 ARRAY 字段中使用基本操作符的提示
虽然 Milvus 的基本操作符用途广泛,可以应用于标量字段,但它们也可以有效地用于 JSON 和 ARRAY 字段中的键和索引。例如,如果product
字段包含多个键,如price
、model
和tags
,则始终直接引用键:
filter = 'product["price"] > 1000'
要查找记录温度的数组中第一个温度超过特定值的记录,请使用:
filter = 'history_temperatures[0] > 30'
2 过滤器模板
在 Milvus 中,包含大量元素的复杂过滤表达式,尤其是那些涉及非 ASCII 字符(如中日韩字符)的表达式,会严重影响查询性能。为了解决这个问题,Milvus 引入了过滤表达式模板机制,旨在通过减少解析复杂表达式所花费的时间来提高效率。本页介绍了在搜索、查询和删除操作中使用过滤表达式模板的方法。
2.1 概述
过滤表达式模板化允许你创建带有占位符的过滤表达式,这些占位符可以在查询执行过程中动态替换为值。使用模板,可以避免直接在过滤器中嵌入大型数组或复杂表达式,从而减少解析时间并提高查询性能。
假设有一个涉及两个字段age
和city
的过滤器表达式,要查找所有年龄大于 25 岁且居住在 "北京"或 "上海"的人。您可以使用模板来代替直接在筛选表达式中嵌入值:
filter = "age > {age} AND city IN {city}"
filter_params = {"age": 25, "city": ["北京", "上海"]}
在这里,{age}
和{city}
是占位符,在执行查询时将被替换为filter_params
中的实际值。在 Milvus 中使用过滤表达式模板有几个主要优点:
- 减少解析时间:通过用占位符替换大型或复杂的过滤器表达式,系统可以减少解析和处理过滤器的时间。
- 提高查询性能:解析开销减少后,查询性能就会提高,从而获得更高的 QPS 和更快的响应时间。
- 可扩展性:随着数据集的增长和过滤器表达式的复杂化,模板化可确保性能保持高效和可扩展。
2.2 搜索操作符
对于 Milvus 中的搜索操作,filter
表达式用于定义过滤条件,filter_params
参数用于指定占位符的值。filter_params
字典包含 Milvus 将用于代入过滤表达式的动态值。在本例中,Milvus 将在执行搜索时用25
动态替换{age}
,用["北京", "上海"]
动态替换{city}
。
expr = "age > {age} AND city IN {city}"
filter_params = {"age": 25, "city": ["北京", "上海"]}
res = client.search("hello_milvus",vectors[:nq],filter=expr,limit=10,output_fields=["age", "city"],search_params={"metric_type": "COSINE", "params": {"search_list": 100}},filter_params=filter_params,
)
2.3 查询操作符
同样的模板机制也可应用于 Milvus 的查询操作符。在query
函数中,您可以定义过滤表达式,并使用filter_params
指定要替换的值。通过使用filter_params
,Milvus 可以有效处理值的动态插入,提高查询执行速度。
expr = "age > {age} AND city IN {city}"
filter_params = {"age": 25, "city": ["北京", "上海"]}
res = client.query("hello_milvus",filter=expr,output_fields=["age", "city"],filter_params=filter_params
)
2.4 删除操作符
在删除操作中也可以使用过滤表达式模板。与搜索和查询类似,filter
表达式定义条件,filter_params
为占位符提供动态值。这种方法可以提高删除操作的性能,尤其是在处理复杂的过滤条件时。
expr = "age > {age} AND city IN {city}"
filter_params = {"age": 25, "city": ["北京", "上海"]}
res = client.delete("hello_milvus",filter=expr,filter_params=filter_params
)
3 JSON 操作符
Milvus 支持用于查询和过滤 JSON 字段的高级操作符,使其成为管理复杂结构化数据的完美工具。这些操作符可实现对 JSON 文档的高效查询,允许您根据 JSON 字段中的特定元素、值或条件检索实体。
JSON 字段无法处理复杂的嵌套结构,而是将所有嵌套结构视为纯字符串。因此,在使用 JSON 字段时,建议避免过深的嵌套,并确保数据结构尽可能扁平,以获得最佳性能。
3.1 可用的 JSON 操作符
Milvus 提供了几个强大的 JSON 操作符,帮助过滤和查询 JSON 数据,这些操作符是
JSON_CONTAINS(identifier, expr)
:过滤在字段中找到指定 JSON 表达式的实体。JSON_CONTAINS_ALL(identifier, expr)
:确保字段中包含指定 JSON 表达式的所有元素。JSON_CONTAINS_ANY(identifier, expr)
:筛选字段中至少存在一个 JSON 表达式成员的实体。
3.2 JSON_CONTAINS
json_contains
操作符检查 JSON 字段中是否存在特定元素或子阵。当你想确保一个 JSON 数组或对象包含一个特定值时,它就非常有用了。假设您有一个产品 Collections,每个 Collections 都有一个tags
字段,其中包含一个由字符串组成的 JSON 数组,如["electronics", "sale", "new"]
。您想过滤带有"sale"
标记的产品。
# JSON data: {"tags": ["electronics", "sale", "new"]}
filter = 'json_contains(product["tags"], "sale")'
在此示例中,Milvus 将返回tags
字段包含"sale"
元素的所有产品。
3.3 json_contains_all
json_contains_all
操作符可确保目标字段中包含指定 JSON 表达式的所有元素。当需要匹配 JSON 数组中的多个值时,该操作符尤其有用。继续使用产品标记方案,如果要查找具有"electronics"
、"sale"
和"new"
标记的所有产品,可以使用json_contains_all
操作符。
# JSON data: {"tags": ["electronics", "sale", "new", "discount"]}
filter = 'json_contains_all(product["tags"], ["electronics", "sale", "new"])'
此查询将返回tags
数组包含所有三个指定元素的所有产品:"electronics"
,"sale"
, 和"new"
。
3.4 json_contains_any
json_contains_any
操作符可过滤字段中至少存在一个 JSON 表达式成员的实体。当您想根据多个可能值中的任意一个值来匹配实体时,该操作符非常有用。假设您想过滤至少有一个标签"electronics"
,"sale"
, 或"new"
的产品。您可以使用json_contains_any
操作符来实现这一目的。
# JSON data: {"tags": ["electronics", "sale", "new"]}
filter = 'json_contains_any(tags, ["electronics", "new", "clearance"])'
在这种情况下,Milvus 将返回列表["electronics", "new", "clearance"]
中至少有一个标签的所有产品。即使产品只有其中一个标签,也会包含在结果中。
4 数组操作符
Milvus 提供功能强大的操作符来查询数组字段,允许你根据数组内容过滤和检索实体。数组中的所有元素必须是同一类型,数组中的嵌套结构将被视为纯字符串。因此,在使用 ARRAY 字段时,最好避免过深的嵌套,并确保数据结构尽可能扁平,以获得最佳性能。
4.1 可用的 ARRAY 操作符
ARRAY 操作符允许在 Milvus 中对数组字段进行精细查询。这些操作符包括
ARRAY_CONTAINS(identifier, expr):
检查数组字段中是否存在特定元素。ARRAY_CONTAINS_ALL(identifier, expr)
:确保指定列表中的所有元素都存在于数组字段中。ARRAY_CONTAINS_ANY(identifier, expr)
:检查指定列表中的任何元素是否存在于数组字段中。ARRAY_LENGTH(identifier, expr)
ARRAY_COTAINS:允许根据数组字段中元素的数量过滤实体。
4.2 ARRAY_CONTAINS
ARRAY_CONTAINS
操作符用于检查数组字段中是否存在特定元素。当您想查找数组中存在给定元素的实体时,它非常有用。假设有一个数组字段history_temperatures
,其中包含不同年份的最低气温记录。要查找数组中包含值23
的所有实体,可以使用以下过滤表达式:
filter = 'ARRAY_CONTAINS(history_temperatures, 23)'
这将返回history_temperatures
数组包含23
值的所有实体。
4.3 array_contains_all
ARRAY_CONTAINS_ALL
操作符可确保指定列表中的所有元素都出现在数组字段中。当您要匹配数组中包含多个值的实体时,此操作符非常有用。如果要查找history_temperatures
数组同时包含23
和24
的所有实体,可以使用 :
filter = 'ARRAY_CONTAINS_ALL(history_temperatures, [23, 24])'
这将返回history_temperatures
数组同时包含指定值的所有实体。
4.4 array_contains_any
ARRAY_CONTAINS_ANY
操作符会检查数组字段中是否存在指定列表中的任何元素。当您想匹配数组中至少包含一个指定值的实体时,此操作非常有用。要查找history_temperatures
数组包含23
或24
的所有实体,可以使用 :
filter = 'ARRAY_CONTAINS_ANY(history_temperatures, [23, 24])'
这将返回history_temperatures
数组包含23
或24
中至少一个值的所有实体。
4.5 ARRAY_LENGTH
ARRAY_LENGTH
操作符允许您根据数组字段中元素的数量过滤实体。这在需要查找具有一定长度数组的实体时非常有用。如果要查找history_temperatures
数组中元素少于 10 个的所有实体,可以使用:
filter = 'ARRAY_LENGTH(history_temperatures) < 10'
这将返回history_temperatures
数组中元素少于 10 个的所有实体。