Coincidencia de texto
La coincidencia de texto en Milvus permite la recuperación precisa de documentos basada en términos específicos. Esta función se utiliza principalmente para la búsqueda filtrada con el fin de cumplir condiciones específicas y puede incorporar el filtrado escalar para refinar los resultados de la consulta, lo que permite realizar búsquedas por similitud dentro de vectores que cumplan criterios escalares.
TEXT_MATCH La búsqueda de coincidencia exacta (exact match) encuentra términos analizados exactos, mientras que la búsqueda de similitud ( TEXT_MATCH_FUZZY ) puede tolerar una pequeña distancia de edición entre los tokens de la consulta y los tokens indexados. Ambas son operaciones de filtrado booleano y no evalúan la relevancia de los documentos coincidentes. Si deseas recuperar los documentos más relevantes en función del significado semántico y la importancia de los términos de la consulta, te recomendamos que utilices la búsqueda de texto completo.
Descripción general
Milvus integra Tantivy para impulsar su índice invertido subyacente y la búsqueda de texto basada en términos. Milvus indexa cada entrada de texto siguiendo este procedimiento:
Analizador: El analizador procesa el texto de entrada dividiéndolo en palabras individuales, o tokens, y aplicando luego los filtros necesarios. Esto permite a Milvus crear un índice basado en estos tokens.
Indexación: Tras el análisis del texto, Milvus crea un índice invertido que asocia cada token único a los documentos que lo contienen.
Cuando un usuario realiza una búsqueda de texto, se utiliza el índice invertido para recuperar rápidamente todos los documentos que contienen los términos. Esto es mucho más rápido que examinar cada documento por separado.
Búsqueda por palabras clave
Habilitar la búsqueda de texto
La búsqueda de texto funciona en campos de cadena en los que está habilitada la búsqueda. Los ejemplos de esta página utilizan VARCHAR, que es compatible con todos los SDK de cliente. En Milvus 3.0.x, TEXT los campos también admiten la búsqueda de texto cuando Storage V3 está habilitado. Para cualquiera de los dos tipos de campo, configura tanto enable_analyzer como enable_match en True y, a continuación, configura opcionalmente un analizador al definir el esquema de tu colección.
Establezca enable_analyzer y enable_match
Para habilitar la coincidencia de texto en un campo « VARCHAR » específico, establece los parámetros « enable_analyzer » y « enable_match » en « True » al definir el esquema del campo. Esto indica a Milvus que tokenice el texto y cree un índice invertido para el campo especificado, lo que permite realizar coincidencias de texto rápidas y eficientes.
from pymilvus import MilvusClient, DataType
schema = MilvusClient.create_schema(enable_dynamic_field=False)
schema.add_field(
field_name="id",
datatype=DataType.INT64,
is_primary=True,
auto_id=True
)
schema.add_field(
field_name='text',
datatype=DataType.VARCHAR,
max_length=1000,
enable_analyzer=True, # Whether to enable text analysis for this field
enable_match=True # Whether to enable text match
)
schema.add_field(
field_name="embeddings",
datatype=DataType.FLOAT_VECTOR,
dim=5
)
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder()
.enableDynamicField(false)
.build();
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("text")
.dataType(DataType.VarChar)
.maxLength(1000)
.enableAnalyzer(true)
.enableMatch(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("embeddings")
.dataType(DataType.FloatVector)
.dimension(5)
.build());
import "github.com/milvus-io/milvus/client/v2/entity"
schema := entity.NewSchema().WithDynamicFieldEnabled(false)
schema.WithField(entity.NewField().
WithName("id").
WithDataType(entity.FieldTypeInt64).
WithIsPrimaryKey(true).
WithIsAutoID(true),
).WithField(entity.NewField().
WithName("text").
WithDataType(entity.FieldTypeVarChar).
WithEnableAnalyzer(true).
WithEnableMatch(true).
WithMaxLength(1000),
).WithField(entity.NewField().
WithName("embeddings").
WithDataType(entity.FieldTypeFloatVector).
WithDim(5),
)
const schema = [
{
name: "id",
data_type: DataType.Int64,
is_primary_key: true,
},
{
name: "text",
data_type: "VarChar",
enable_analyzer: true,
enable_match: true,
max_length: 1000,
},
{
name: "embeddings",
data_type: DataType.FloatVector,
dim: 5,
},
];
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "text",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 1000,
"enable_analyzer": true,
"enable_match": true
}
},
{
"fieldName": "embeddings",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
}
]
}'
Opcional: configurar un analizador
El rendimiento y la precisión de la búsqueda por palabras clave dependen del analizador seleccionado. Los distintos analizadores están adaptados a diversos idiomas y estructuras de texto, por lo que elegir el adecuado puede influir significativamente en los resultados de búsqueda para tu caso de uso específico.
Por defecto, Milvus utiliza el analizador « standard », que tokeniza el texto basándose en los espacios en blanco y la puntuación, elimina los tokens de más de 40 caracteres y convierte el texto a minúsculas. No se necesitan parámetros adicionales para aplicar esta configuración predeterminada. Para obtener más información, consulta «Estándar».
En los casos en los que se requiera un analizador diferente, puede configurar uno utilizando el parámetro ` analyzer_params `. Por ejemplo, para aplicar el analizador ` english ` al procesamiento de texto en inglés:
analyzer_params = {
"type": "english"
}
schema.add_field(
field_name='text',
datatype=DataType.VARCHAR,
max_length=200,
enable_analyzer=True,
analyzer_params = analyzer_params,
enable_match = True,
)
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("type", "english");
schema.addField(AddFieldReq.builder()
.fieldName("text")
.dataType(DataType.VarChar)
.maxLength(200)
.enableAnalyzer(true)
.analyzerParams(analyzerParams)
.enableMatch(true)
.build());
analyzerParams := map[string]any{"type": "english"}
schema.WithField(entity.NewField().
WithName("text").
WithDataType(entity.FieldTypeVarChar).
WithEnableAnalyzer(true).
WithEnableMatch(true).
WithAnalyzerParams(analyzerParams).
WithMaxLength(200),
)
const schema = [
{
name: "id",
data_type: DataType.Int64,
is_primary_key: true,
},
{
name: "text",
data_type: "VarChar",
enable_analyzer: true,
enable_match: true,
max_length: 1000,
analyzer_params: { type: 'english' },
},
{
name: "embeddings",
data_type: DataType.FloatVector,
dim: 5,
},
];
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "text",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 200,
"enable_analyzer": true,
"enable_match": true,
"analyzer_params": {"type": "english"}
}
},
{
"fieldName": "embeddings",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
}
]
}'
Milvus también ofrece otros analizadores adaptados a diferentes idiomas y escenarios. Para obtener más detalles, consulta la Descripción general de los analizadores.
Utilizar la coincidencia de texto
Una vez que haya habilitado la coincidencia de texto para un campo « VARCHAR » o « TEXT » en el esquema de su colección, podrá realizar coincidencias de texto utilizando la expresión « TEXT_MATCH ».
Sintaxis de la expresión TEXT_MATCH
La expresión TEXT_MATCH se utiliza para especificar el campo y los términos que se van a buscar. Su sintaxis es la siguiente:
TEXT_MATCH(field_name, text)
field_name: El nombre del campoVARCHARoTEXThabilitado para la coincidencia en el que se va a realizar la búsqueda.text: Los términos que se van a buscar. Se pueden introducir varios términos separados por espacios u otros delimitadores adecuados, en función del idioma y del analizador configurado.
Por defecto, TEXT_MATCH utiliza la lógica de coincidencia «OR», lo que significa que devolverá documentos que contengan cualquiera de los términos especificados. Por ejemplo, para buscar documentos que contengan el término machine o deep en el campo text, utiliza la siguiente expresión:
filter = "TEXT_MATCH(text, 'machine deep')"
String filter = "TEXT_MATCH(text, 'machine deep')";
filter := "TEXT_MATCH(text, 'machine deep')"
const filter = "TEXT_MATCH(text, 'machine deep')";
export filter="\"TEXT_MATCH(text, 'machine deep')\""
También puedes combinar varias expresiones « TEXT_MATCH » utilizando operadores lógicos para realizar una búsqueda «AND ».
Para buscar documentos que contengan tanto «
machine» como «deep» en el campo «text», utiliza la siguiente expresión:filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')"String filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')";filter := "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')"const filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')"export filter="\"TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')\""Para buscar documentos que contengan tanto
machinecomolearning, pero sindeepen el campotext, utiliza las siguientes expresiones:filter = "not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')"String filter = "not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')";filter := "not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')"const filter = "not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')";export filter="\"not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')\""
Sintaxis de la expresión TEXT_MATCH_FUZZYCompatible with Milvus 3.0.0+
Utiliza TEXT_MATCH_FUZZY para tolerar diferencias ortográficas entre los tokens de la consulta y los tokens indexados. Milvus analiza el texto de la consulta con el analizador del campo y aplica la coincidencia difusa a cada token resultante. Si la consulta genera varios tokens, la expresión coincide con una entidad cuando cualquier token cumple la distancia de edición configurada.
La sintaxis es la siguiente:
TEXT_MATCH_FUZZY(field_name, text, max_edit_distance = 1)
field_name: El nombre del campo «VARCHAR» o «TEXT» habilitado para la coincidencia en el que se va a realizar la búsqueda.text: El texto de la consulta que se va a analizar y comparar con los tokens indexados.max_edit_distance: La distancia de edición máxima permitida para cada token de la consulta. El nombre de la opción debe ser exactamente «max_edit_distance», y su valor debe ser «0», «1» o «2». Un valor de «0» realiza una coincidencia exacta de tokens, equivalente a «TEXT_MATCH».
Por ejemplo, la siguiente expresión encuentra tokens que difieran en una sola letra de machne, incluyendo machine:
filter = "TEXT_MATCH_FUZZY(text, 'machne', max_edit_distance = 1)"
String filter = "TEXT_MATCH_FUZZY(text, 'machne', max_edit_distance = 1)";
filter := "TEXT_MATCH_FUZZY(text, 'machne', max_edit_distance = 1)"
const filter = "TEXT_MATCH_FUZZY(text, 'machne', max_edit_distance = 1)";
export filter="\"TEXT_MATCH_FUZZY(text, 'machne', max_edit_distance = 1)\""
TEXT_MATCH_FUZZY forma parte de la sintaxis de la expresión de filtro, por lo que los SDK de cliente no requieren un método específico de coincidencia aproximada. Pasa la expresión a través del mismo parámetro filter utilizado para TEXT_MATCH en operaciones de búsqueda o consulta.
Búsqueda con coincidencia de texto
La coincidencia de texto se puede utilizar en combinación con la búsqueda por similitud vectorial para reducir el alcance de la búsqueda y mejorar el rendimiento de la misma. Al filtrar la colección mediante la coincidencia de texto antes de la búsqueda por similitud vectorial, se puede reducir el número de documentos que hay que buscar, lo que se traduce en tiempos de consulta más rápidos.
En este ejemplo, la expresión filter filtra los resultados de la búsqueda para incluir únicamente los documentos que coincidan con el término especificado keyword1 o keyword2. A continuación, la búsqueda por similitud vectorial se realiza sobre este subconjunto filtrado de documentos.
Puedes resaltar los términos coincidentes en los resultados de búsqueda configurando un resaltador de texto. Consulta Resaltador de texto para obtener más detalles.
# Match entities with `keyword1` or `keyword2`
filter = "TEXT_MATCH(text, 'keyword1 keyword2')"
# Assuming 'embeddings' is the vector field and 'text' is the VARCHAR field
result = client.search(
collection_name="my_collection", # Your collection name
anns_field="embeddings", # Vector field name
data=[query_vector], # Query vector
filter=filter,
search_params={"params": {"nprobe": 10}},
limit=10, # Max. number of results to return
output_fields=["id", "text"] # Fields to return
)
String filter = "TEXT_MATCH(text, 'keyword1 keyword2')";
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("my_collection")
.annsField("embeddings")
.data(Collections.singletonList(queryVector)))
.filter(filter)
.topK(10)
.outputFields(Arrays.asList("id", "text"))
.build());
filter := "TEXT_MATCH(text, 'keyword1 keyword2')"
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"my_collection", // collectionName
10, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithANNSField("embeddings").
WithFilter(filter).
WithOutputFields("id", "text"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
// Match entities with `keyword1` or `keyword2`
const filter = "TEXT_MATCH(text, 'keyword1 keyword2')";
// Assuming 'embeddings' is the vector field and 'text' is the VARCHAR field
const result = await client.search(
collection_name: "my_collection", // Your collection name
anns_field: "embeddings", // Vector field name
data: [query_vector], // Query vector
filter: filter,
params: {"nprobe": 10},
limit: 10, // Max. number of results to return
output_fields: ["id", "text"] //Fields to return
);
export filter="\"TEXT_MATCH(text, 'keyword1 keyword2')\""
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "my_collection",
"annsField": "embeddings",
"data": [[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]],
"filter": '"$filter"',
"searchParams": {
"params": {
"nprobe": 10
}
},
"limit": 10,
"outputFields": ["text","id"]
}'
Consulta con coincidencia de texto
La coincidencia de texto también se puede utilizar para el filtrado escalar en operaciones de consulta. Al especificar una expresión de « TEXT_MATCH » en el parámetro « expr » del método « query() », se pueden recuperar documentos que coincidan con los términos indicados.
El ejemplo siguiente recupera documentos en los que el campo « text » contiene ambos términos: « keyword1 » y « keyword2 ».
# Match entities with both `keyword1` and `keyword2`
filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')"
result = client.query(
collection_name="my_collection",
filter=filter,
output_fields=["id", "text"]
)
String filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')";
QueryResp queryResp = client.query(QueryReq.builder()
.collectionName("my_collection")
.filter(filter)
.outputFields(Arrays.asList("id", "text"))
.build()
);
filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')"
resultSet, err := client.Query(ctx, milvusclient.NewQueryOption("my_collection").
WithFilter(filter).
WithOutputFields("id", "text"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
// Match entities with both `keyword1` and `keyword2`
const filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')";
const result = await client.query(
collection_name: "my_collection",
filter: filter,
output_fields: ["id", "text"]
)
export filter="\"TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')\""
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "my_collection",
"filter": '"$filter"',
"outputFields": ["id", "text"]
}'
Consideraciones
Al habilitar la coincidencia de términos para un campo, se crea un índice invertido, lo que consume recursos de almacenamiento. Ten en cuenta el impacto en el almacenamiento a la hora de decidir si habilitas esta función, ya que varía en función del tamaño del texto, los tokens únicos y el analizador utilizado.
Una vez que haya definido un analizador en su esquema, su configuración se vuelve permanente para esa colección. Si decide que otro analizador se adapta mejor a sus necesidades, puede considerar eliminar la colección existente y crear una nueva con la configuración de analizador deseada.
Reglas de escape en expresiones de «
filter»:Los caracteres entre comillas dobles o simples dentro de las expresiones se interpretan como constantes de cadena. Si la constante de cadena incluye caracteres de escape, estos deben representarse mediante una secuencia de escape. Por ejemplo, utiliza
\\para representar\,\\tpara representar una tabulación\ty\\npara representar un salto de línea.Si una constante de cadena está entre comillas simples, una comilla simple dentro de la constante debe representarse como
\\', mientras que una comilla doble puede representarse como"o\\". Ejemplo:'It\\'s milvus'.Si una constante de cadena está entre comillas dobles, una comilla doble dentro de la constante debe representarse como
\\", mientras que una comilla simple puede representarse como'o\\'. Ejemplo:"He said \\"Hi\\"".