Фильтрованный поиск с использованием StructArray
Используйте эту страницу для добавления скалярной фильтрации к векторному поиску по полям StructArray. Фильтрация StructArray имеет два уровня: фильтры на уровне строк выбирают родительские сущности, а фильтры на уровне элементов ограничивают набор элементов Struct, участвующих в векторном поиске на уровне элементов.
На этой странице используется коллекция « tech_articles » из раздела «Создание поля StructArray». В коллекции имеется поле StructArray с именем « chunks », содержащее скалярные подполя, такие как « section », « page », « quality_score » и « has_code », а также векторные подполя для поиска.
Выберите тип фильтра
| Цель | Использование | Поведение результата |
|---|---|---|
Фильтрация по скалярному полю верхнего уровня, например category. | Обычное выражение фильтра. | Выбирает родительские сущности до или во время поиска. |
| Ограничивает векторный поиск на уровне элементов элементами Struct, соответствующими скалярным условиям. | element_filter. | Выполняет поиск только среди соответствующих элементов Struct и может возвращать смещения найденных элементов. |
| Выбор сущностей в зависимости от того, соответствуют ли предкату какие-либо, все или определённое количество элементов Struct. | MATCH_ANY, MATCH_ALL, MATCH_LEAST, MATCH_MOST или MATCH_EXACT. | Фильтрация на уровне строк. Сами по себе эти операторы не возвращают смещения. |
На этой странице объясняется, как использовать фильтры StructArray в рабочих процессах поиска. Полные правила синтаксиса, поддерживаемые типы предикатов и матрица неподдерживаемых предикатов см. в разделе «Операторы StructArray».
Фильтрация по полям верхнего уровня
Используйте обычные выражения фильтрации, если условие относится к родительской сущности, а не к отдельному элементу Struct. Это работает как при поиске по EmbeddingList, так и при поиске на уровне элементов.
from pymilvus import MilvusClient
from pymilvus.client.embedding_list import EmbeddingList
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus",
)
query = EmbeddingList()
query.add([0.12, 0.21, 0.32, 0.44])
query.add([0.18, 0.23, 0.29, 0.36])
results = client.search(
collection_name="tech_articles",
data=[query],
anns_field="chunks[emb_list_vector]",
filter='category == "search"',
limit=3,
output_fields=[
"doc_id",
"title",
"category",
"chunks[text]",
"chunks[section]",
],
)
Приведенный выше фильтр выбирает только сущности, у которых поле верхнего уровня category имеет значение "search". Он не выделяет один конкретный соответствующий элемент Struct.
Фильтрация векторного поиска на уровне элементов
Используйте element_filter(structArrayField, predicate), когда скалярные условия должны применяться к тому же элементу Struct, который участвует в векторном поиске на уровне элементов. Внутри предиката используйте $[subfield] для ссылки на скалярные подполя текущего элемента Struct.
query_vector = [0.19, 0.24, 0.30, 0.37]
filter_expr = (
'category == "search" && '
'element_filter(chunks, '
'$[section] == "index" && '
'$[quality_score] > 0.9 && '
'$[has_code] == true)'
)
results = client.search(
collection_name="tech_articles",
data=[query_vector],
anns_field="chunks[emb]",
filter=filter_expr,
limit=5,
output_fields=[
"doc_id",
"title",
"chunks[text]",
"chunks[section]",
"chunks[page]",
"chunks[quality_score]",
"chunks[has_code]",
],
)
for hits in results:
for hit in hits:
print(
"doc_id:", hit["id"],
"distance:", hit["distance"],
"offset:", hit.get("offset"),
"entity:", hit["entity"],
)
В данном примере предикат верхнего уровня category == "search" выбирает кандидатов, а element_filter ограничивает векторный поиск на уровне элементов фрагментами, в которых section, quality_score и has_code совпадают в одном и том же элементе Struct.
Предупреждение
При объединении предиката верхнего уровня с оператором « element_filter » помещайте оператор « element_filter » в конец выражения. Выражение фильтра может содержать только один оператор « element_filter », и нельзя вкладывать операторы « element_filter » или « MATCH_* » внутрь другого оператора «StructArray».
Фильтрация сущностей с помощью операторов MATCH
Используйте операторы MATCH_*, когда фильтр должен определять, соответствует ли родительская сущность критериям на основе элементов Struct. Эти операторы являются фильтрами на уровне строк: они выбирают сущности, но сами по себе не возвращают смещения элементов.
| Оператор | Используйте его, когда | Пример |
|---|---|---|
MATCH_ANY | По крайней мере один элемент Struct должен удовлетворять предикату. | MATCH_ANY(chunks, $[section] == "index") |
MATCH_ALL | Все элементы Struct должны удовлетворять предикату. | MATCH_ALL(chunks, $[quality_score] > 0.5) |
MATCH_LEAST | По крайней мере N элементов структуры должны удовлетворять предикату. | MATCH_LEAST(chunks, $[has_code] == true, threshold=2) |
MATCH_MOST | Не более чем N элементов структуры должны удовлетворять предикату. | MATCH_MOST(chunks, $[section] == "appendix", threshold=1) |
MATCH_EXACT | Именно N элементов Struct должны удовлетворять предикату. | MATCH_EXACT(chunks, $[section] == "summary", threshold=1) |
filter_expr = (
'category == "search" && '
'MATCH_ANY(chunks, $[section] == "index" && $[quality_score] > 0.9)'
)
results = client.search(
collection_name="tech_articles",
data=[query],
anns_field="chunks[emb_list_vector]",
filter=filter_expr,
limit=3,
output_fields=[
"doc_id",
"title",
"category",
"chunks[text]",
"chunks[section]",
"chunks[quality_score]",
],
)
Здесь используется « MATCH_ANY », поскольку результат поиска EmbeddingList находится на уровне сущности. Фильтр требует, чтобы по крайней мере один фрагмент в сущности был фрагментом « "index" » с высоким качеством, но сам результат поиска по-прежнему представляет родительскую сущность.
Использование фильтров в гибридном поиске
В гибридном поиске применяйте фильтры StructArray там, где условие должно вступать в силу. Фильтр верхнего уровня может использоваться во всем гибридном поиске. Фильтр « element_filter » следует привязывать к запросу на уровне элементов StructArray, который требует ограничений на уровне элементов.
from pymilvus import AnnSearchRequest, RRFRanker
query_vector = [0.19, 0.24, 0.30, 0.37]
title_req = AnnSearchRequest(
data=[query_vector],
anns_field="title_vector",
limit=10,
)
chunk_req = AnnSearchRequest(
data=[query_vector],
anns_field="chunks[emb]",
limit=10,
expr='element_filter(chunks, $[section] == "index" && $[quality_score] > 0.9)',
)
results = client.hybrid_search(
collection_name="tech_articles",
reqs=[title_req, chunk_req],
ranker=RRFRanker(),
filter='category == "search"',
limit=5,
output_fields=[
"doc_id",
"title",
"category",
"chunks[text]",
"chunks[section]",
"chunks[quality_score]",
],
)
Аргумент « filter » применяет условие сущности верхнего уровня, тогда как « expr » в « chunk_req » ограничивает только запрос вектора на уровне элементов StructArray. Поддерживаемые комбинации гибридного поиска и ограничения для конкретных версий см. в разделах «Гибридный поиск с StructArray » и «Ограничения StructArray».
Сводка по поддержке предикатов
Используйте скалярные подполя в предикатах StructArray. Векторные подполя не являются входными данными для скалярных предикатов.
| Тип подполя | Типичные примеры предикатов |
|---|---|
BOOL | $[has_code] == true, !($[has_code] == true) |
| Целые типы | $[page] >= 2, $[page] in [1, 2, 3] |
FLOAT, DOUBLE | $[quality_score] > 0.9, 0.7 < $[quality_score] < 0.95 |
VARCHAR | $[section] == "index", $[text] like "range%" |
| Векторные подполя | Не поддерживаются в качестве входных данных для скалярных предикатов $[...]. Вместо этого используйте векторные подполя с помощью векторного поиска. |
В отношении неподдерживаемых случаев, таких как пути JSON, функции контейнеров массивов, функции сопоставления текста, предикаты null для $[...], функции Geometry, выражения Timestamptz и вызовы обобщённых функций, см. раздел «Операторы StructArray».
Распространённые ошибки
Использование `
$[subfield]` вне контекста `element_filter` или `MATCH_*`.Использование
chunks.sectionвместо синтаксиса операторов StructArray, напримерelement_filter(chunks, $[section] == "index").Использование
element_filter, когда требуется только фильтрация на уровне строк. Если необходимо только выбрать сущности, используйте вместо этогоMATCH_ANY.Ожидание того, что оператор `
MATCH_*` вернет смещения элементов. Эти операторы выбирают сущности и сами по себе не идентифицируют один соответствующий элемент.Написание простых булевых предикатов, таких как
$[has_code]. Используйте явные сравнения, такие как$[has_code] == true.Размещение
element_filterперед предикатом верхнего уровня в одном и том же выражении фильтра.
Следующие шаги
Чтобы ознакомиться с полным синтаксисом фильтров StructArray, прочтите раздел «Операторы StructArray».
Чтобы сначала выполнить поиск по векторам без фильтрации, ознакомьтесь с разделом «Базовый поиск по векторам с помощью StructArray».
Чтобы создать скалярные индексы для часто используемых фильтров StructArray, ознакомьтесь с разделом «Индексирование полей StructArray».
Чтобы ознакомиться с ограничениями на фильтрацию и поиск для конкретных версий, ознакомьтесь с разделом «Ограничения StructArray».