Correspondência de texto
A correspondência de texto em Milvus permite a recuperação precisa de documentos com base em termos específicos. Esta funcionalidade é utilizada principalmente para pesquisa filtrada para satisfazer condições específicas e pode incorporar filtragem escalar para refinar os resultados da consulta, permitindo pesquisas de semelhança dentro de vectores que satisfaçam critérios escalares.
A correspondência de texto concentra-se em encontrar ocorrências exactas dos termos de consulta, sem pontuar a relevância dos documentos correspondentes. Se pretender obter os documentos mais relevantes com base no significado semântico e na importância dos termos de consulta, recomendamos que utilize a Pesquisa de texto integral.
Visão geral
O Milvus integra o Tantivy para alimentar o seu índice invertido subjacente e a pesquisa de texto baseada em termos. Para cada entrada de texto, Milvus indexa-o seguindo o procedimento.
Analisador: O analisador processa o texto de entrada, transformando-o em palavras individuais, ou tokens, e aplicando filtros conforme necessário. Isto permite ao Milvus construir um índice baseado nestes tokens.
Indexação: Após a análise do texto, o Milvus cria um índice invertido que mapeia cada token único para os documentos que o contêm.
Quando um utilizador efectua uma correspondência de texto, o índice invertido é utilizado para recuperar rapidamente todos os documentos que contêm os termos. Isto é muito mais rápido do que analisar cada documento individualmente.
Correspondência de texto
Ativar a correspondência de texto
A correspondência de texto funciona no tipo de campo VARCHAR
, que é essencialmente o tipo de dados de cadeia em Milvus. Para ativar a correspondência de texto, defina enable_analyzer
e enable_match
para True
e, em seguida, configure opcionalmente um analisador para análise de texto ao definir o esquema da coleção.
Definir enable_analyzer
e enable_match
Para ativar a correspondência de texto para um campo VARCHAR
específico, defina os parâmetros enable_analyzer
e enable_match
para True
ao definir o esquema do campo. Isto instrui o Milvus a tokenizar o texto e a criar um índice invertido para o campo especificado, permitindo correspondências de texto rápidas e eficientes.
from pymilvus import MilvusClient, DataType
schema = MilvusClient.create_schema(auto_id=True, enable_dynamic_field=False)
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
)
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("text")
.dataType(DataType.VarChar)
.maxLength(1000)
.enableAnalyzer(true)
.enableMatch(true)
.build());
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: "sparse",
data_type: DataType.SparseFloatVector,
},
];
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": "sparse",
"dataType": "SparseFloatVector"
}
]
}'
Opcional: Configurar um analisador
O desempenho e a precisão da correspondência de texto dependem do analisador selecionado. Diferentes analisadores são adaptados a várias línguas e estruturas de texto, pelo que a escolha do analisador correto pode ter um impacto significativo nos resultados da pesquisa para o seu caso de utilização específico.
Por predefinição, o Milvus utiliza o analisador standard
, que define os tokens do texto com base nos espaços em branco e na pontuação, remove os tokens com mais de 40 caracteres e converte o texto em minúsculas. Não são necessários parâmetros adicionais para aplicar essa configuração padrão. Para obter mais informações, consulte Padrão.
Nos casos em que um analisador diferente é necessário, você pode configurá-lo usando o parâmetro analyzer_params
. Por exemplo, para aplicar o analisador english
para processar texto em 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());
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: "sparse",
data_type: DataType.SparseFloatVector,
},
];
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": "my_vector",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
}
]
}'
O Milvus também fornece vários outros analisadores adequados a diferentes idiomas e cenários. Para obter mais detalhes, consulte Visão geral.
Utilizar a correspondência de texto
Depois de ativar a correspondência de texto para um campo VARCHAR no seu esquema de coleção, pode efetuar correspondências de texto utilizando a expressão TEXT_MATCH
.
Sintaxe da expressão TEXT_MATCH
A expressão TEXT_MATCH
é utilizada para especificar o campo e os termos a pesquisar. A sua sintaxe é a seguinte.
TEXT_MATCH(field_name, text)
field_name
: O nome do campo VARCHAR a ser pesquisado.text
: Os termos a serem pesquisados. Vários termos podem ser separados por espaços ou outros delimitadores apropriados com base no idioma e no analisador configurado.
Por padrão, TEXT_MATCH
usa a lógica de correspondência OR, o que significa que ele retornará documentos que contêm qualquer um dos termos especificados. Por exemplo, para pesquisar documentos que contenham o termo machine
ou deep
no campo text
, use a seguinte expressão.
filter = "TEXT_MATCH(text, 'machine deep')"
String filter = "TEXT_MATCH(text, 'machine deep')";
const filter = "TEXT_MATCH(text, 'machine deep')";
export filter="\"TEXT_MATCH(text, 'machine deep')\""
Também pode combinar várias expressões TEXT_MATCH
utilizando operadores lógicos para efetuar a correspondência AND. Por exemplo, para procurar documentos que contenham machine
e deep
no campo text
, utilize a seguinte expressão.
filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')"
String 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')\""
Pesquisa com correspondência de texto
A correspondência de texto pode ser usada em combinação com a pesquisa de similaridade de vetor para restringir o escopo da pesquisa e melhorar o desempenho da pesquisa. Ao filtrar a coleção utilizando a correspondência de texto antes da pesquisa de semelhança vetorial, pode reduzir o número de documentos que precisam de ser pesquisados, resultando em tempos de consulta mais rápidos.
Neste exemplo, a expressão filter
filtra os resultados da pesquisa para incluir apenas documentos que correspondam ao termo especificado keyword1
ou keyword2
. A pesquisa de similaridade de vetor é então executada neste subconjunto filtrado de documentos.
# 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 = MilvusClient.search(
collection_name="YOUR_COLLECTION_NAME", # 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("YOUR_COLLECTION_NAME")
.annsField("embeddings")
.data(Collections.singletonList(queryVector)))
.filter(filter)
.topK(10)
.outputFields(Arrays.asList("id", "text"))
.build());
// 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: "YOUR_COLLECTION_NAME", // 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" \
-d '{
"collectionName": "demo2",
"annsField": "my_vector",
"data": [[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]],
"filter": '"$filter"',
"searchParams": {
"params": {
"nprobe": 10
}
},
"limit": 3,
"outputFields": ["text","id"]
}'
Consulta com correspondência de texto
A correspondência de texto também pode ser usada para filtragem escalar em operações de consulta. Ao especificar uma expressão TEXT_MATCH
no parâmetro expr
do método query()
, pode obter documentos que correspondem aos termos fornecidos.
O exemplo abaixo recupera documentos em que o campo text
contém os termos keyword1
e keyword2
.
# Match entities with both `keyword1` and `keyword2`
filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')"
result = MilvusClient.query(
collection_name="YOUR_COLLECTION_NAME",
filter=filter,
output_fields=["id", "text"]
)
String filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')";
QueryResp queryResp = client.query(QueryReq.builder()
.collectionName("YOUR_COLLECTION_NAME")
.filter(filter)
.outputFields(Arrays.asList("id", "text"))
.build()
);
// 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: "YOUR_COLLECTION_NAME",
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" \
-d '{
"collectionName": "demo2",
"filter": '"$filter"',
"outputFields": ["id", "text"]
}'
Considerações
A ativação da correspondência de texto para um campo desencadeia a criação de um índice invertido, que consome recursos de armazenamento. Considere o impacto no armazenamento ao decidir ativar esse recurso, pois ele varia de acordo com o tamanho do texto, tokens exclusivos e o analisador usado.
Depois de definir um analisador no seu esquema, as suas definições tornam-se permanentes para essa coleção. Se decidir que um analisador diferente se adequa melhor às suas necessidades, pode considerar eliminar a coleção existente e criar uma nova com a configuração de analisador pretendida.