Búsqueda filtrada con StructArray

Utiliza esta página para añadir filtrado escalar a la búsqueda vectorial en campos StructArray. El filtrado de StructArray tiene dos niveles: los filtros a nivel de fila seleccionan entidades principales, mientras que los filtros a nivel de elemento restringen qué elementos de Struct participan en la búsqueda vectorial a nivel de elemento.

Esta página utiliza la colección « tech_articles » de «Crear un campo StructArray». La colección tiene un campo StructArray denominado « chunks », con subcampos escalares como « section », « page », « quality_score » y « has_code », además de subcampos vectoriales para la búsqueda.

Elige un tipo de filtro

ObjetivoUsoComportamiento del resultado
Filtrar por un campo escalar de nivel superior, como category.Expresión de filtro habitual.Selecciona las entidades padre antes o durante la búsqueda.
Restringe la búsqueda vectorial a nivel de elemento a los elementos Struct que cumplan las condiciones escalares.element_filter.Busca únicamente los elementos Struct que coincidan y puede devolver las posiciones de los elementos coincidentes.
Selecciona entidades en función de si alguno, todos o un número específico de elementos Struct cumplen un predicado.MATCH_ANY, MATCH_ALL, MATCH_LEAST, MATCH_MOST o MATCH_EXACT.Filtrado a nivel de fila. Estos operadores no devuelven desplazamientos por sí mismos.

En esta página se explica cómo utilizar los filtros de StructArray en los flujos de trabajo de búsqueda. Para conocer las reglas sintácticas completas, los tipos de predicados admitidos y la matriz de predicados no admitidos, consulta Operadores de StructArray.

Filtrar por campos de nivel superior

Utilice expresiones de filtro habituales cuando la condición se refiera a la entidad principal, y no a un elemento Struct concreto. Esto funciona tanto con la búsqueda EmbeddingList como con la búsqueda a nivel de elemento.

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]",
    ],
)

El filtro anterior selecciona únicamente las entidades cuyo campo de nivel superior « category » sea « "search" ». No identifica un único elemento Struct que coincida.

Utilice « element_filter(structArrayField, predicate) » cuando las condiciones escalares deban aplicarse al mismo elemento Struct que participa en la búsqueda vectorial a nivel de elemento. Dentro del predicado, utilice « $[subfield] » para referirse a los subcampos escalares del elemento Struct actual.

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"],
        )

En este ejemplo, el predicado de nivel superior ` category == "search" ` selecciona entidades candidatas, y ` element_filter ` restringe la búsqueda vectorial a nivel de elemento a los fragmentos en los que ` section`, ` quality_score` y ` has_code ` coinciden todos en el mismo elemento `Struct`.

Advertencia

Cuando se combine un predicado de nivel superior con element_filter, coloque element_filter al final de la expresión. Una expresión de filtro solo puede contener un element_filter, y no se pueden anidar element_filter ni MATCH_* dentro de otro operador StructArray.

Filtrar entidades con operadores MATCH

Utilice los operadores « MATCH_* » cuando el filtro deba decidir si una entidad principal cumple los requisitos en función de sus elementos Struct. Estos operadores son filtros a nivel de fila: seleccionan entidades, pero no devuelven por sí mismos las posiciones de los elementos.

OperadorÚsalo cuandoEjemplo
MATCH_ANYAl menos un elemento Struct debe cumplir el predicado.MATCH_ANY(chunks, $[section] == "index")
MATCH_ALLTodos los elementos Struct deben cumplir el predicado.MATCH_ALL(chunks, $[quality_score] > 0.5)
MATCH_LEASTAl menos N elementos de la estructura deben cumplir el predicado.MATCH_LEAST(chunks, $[has_code] == true, threshold=2)
MATCH_MOSTComo máximo, un N e de elementos de la estructura deben cumplir el predicado.MATCH_MOST(chunks, $[section] == "appendix", threshold=1)
MATCH_EXACTExactament N es elementos Struct deben cumplir el predicado.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]",
    ],
)

Utiliza « MATCH_ANY » aquí porque el resultado de la búsqueda de EmbeddingList es a nivel de entidad. El filtro requiere que al menos un fragmento de la entidad sea un fragmento « "index" » de alta calidad, pero el resultado de la búsqueda en sí mismo sigue representando a la entidad principal.

En la búsqueda híbrida, aplica filtros StructArray donde la condición deba surtir efecto. Un filtro de nivel superior puede ser compartido por toda la búsqueda híbrida. Se debe adjuntar un « element_filter » a la solicitud a nivel de elemento de StructArray que necesite restricciones a nivel de elemento.

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]",
    ],
)

El argumento « filter » aplica la condición de entidad de nivel superior, mientras que « expr » en « chunk_req » restringe únicamente la solicitud de vector a nivel de elemento de StructArray. Para conocer las combinaciones de búsqueda híbrida compatibles y los límites específicos de cada versión, consulta «Búsqueda híbrida con StructArray » y «Límites de StructArray».

Resumen de compatibilidad con predicados

Utilice subcampos escalares en los predicados de StructArray. Los subcampos vectoriales no son entradas de predicados escalares.

Tipo de subcampoEjemplos típicos de predicados
BOOL$[has_code] == true, !($[has_code] == true)
Tipos enteros$[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%"
Subcampos vectorialesNo son compatibles como entradas de predicados escalares de $[...]. En su lugar, utilice subcampos vectoriales mediante la búsqueda vectorial.

Para los casos no admitidos, como las rutas JSON, las funciones de contenedores de matrices, las funciones de coincidencia de texto, los predicados nulos en « $[...] », las funciones de geometría, las expresiones «Timestamptz» y las llamadas a funciones genéricas, consulte Operadores de StructArray.

Errores comunes

  • Utilizar ` $[subfield] ` fuera de ` element_filter ` o ` MATCH_*`.

  • Utilizar « chunks.section » en lugar de la sintaxis de los operadores de StructArray, como « element_filter(chunks, $[section] == "index") ».

  • Utilizar « element_filter » cuando solo se necesita un filtrado a nivel de fila. Utilice « MATCH_ANY » en su lugar si solo necesita seleccionar entidades.

  • Esperar que ` MATCH_* ` devuelva las posiciones de los elementos. Estos operadores seleccionan entidades y no identifican por sí mismos un elemento coincidente.

  • Escribir predicados booleanos sin más, como $[has_code]. Utiliza comparaciones explícitas, como $[has_code] == true.

  • Colocar « element_filter » antes de un predicado de nivel superior en la misma expresión de filtro.

Próximos pasos

  1. Para consultar la sintaxis completa de los filtros de StructArray, lee «Operadores de StructArray».

  2. Para realizar primero búsquedas vectoriales sin filtrar, consulta «Búsqueda vectorial básica con StructArray».

  3. Para crear índices escalares para filtros de StructArray de uso frecuente, consulta «Indexar campos de StructArray».

  4. Para consultar los límites de filtrado y búsqueda específicos de cada versión, consulta «Límites de StructArray».