Pesquisa híbrida
A pesquisa híbrida refere-se a um método de pesquisa que efectua várias pesquisas ANN em simultâneo, reordena vários conjuntos de resultados dessas pesquisas ANN e, por fim, devolve um único conjunto de resultados. A utilização da Pesquisa Híbrida pode aumentar a precisão da pesquisa. O Zilliz suporta a realização de Pesquisa Híbrida numa coleção com vários campos vectoriais.
A Pesquisa híbrida é mais comumente usada em cenários que incluem pesquisas vetoriais esparso-densas e pesquisas multimodais. Este guia demonstrará como efetuar uma Pesquisa Híbrida no Zilliz com um exemplo específico.
Cenários
A Pesquisa Híbrida é adequada para os dois cenários seguintes.
Pesquisa de vectores esparso-densos
Diferentes tipos de vectores podem representar diferentes informações, e a utilização de vários modelos de incorporação pode representar de forma mais abrangente diferentes caraterísticas e aspectos dos dados. Por exemplo, a utilização de diferentes modelos de incorporação para a mesma frase pode gerar um vetor denso para representar o significado semântico e um vetor esparso para representar a frequência de palavras na frase.
Vectores esparsos: Os vectores esparsos são caracterizados pela sua elevada dimensionalidade vetorial e pela presença de poucos valores não nulos. Esta estrutura torna-os particularmente adequados para aplicações tradicionais de recuperação de informação. Na maioria dos casos, o número de dimensões utilizadas nos vectores esparsos corresponde a diferentes tokens numa ou mais línguas. A cada dimensão é atribuído um valor que indica a importância relativa desse token no documento. Esta disposição revela-se vantajosa para tarefas que envolvem correspondência de texto.
Vectores densos: Os vectores densos são incorporados a partir de redes neuronais. Quando dispostos numa matriz ordenada, estes vectores captam a essência semântica do texto de entrada. Note-se que os vectores densos não se limitam ao processamento de texto; são também amplamente utilizados na visão por computador para representar a semântica dos dados visuais. Estes vectores densos, normalmente gerados por modelos de incorporação de texto, caracterizam-se pelo facto de a maioria ou todos os elementos serem diferentes de zero. Assim, os vectores densos são particularmente eficazes para aplicações de pesquisa semântica, uma vez que podem devolver os resultados mais semelhantes com base na distância vetorial, mesmo na ausência de correspondências exactas de texto. Esta capacidade permite resultados de pesquisa mais matizados e conscientes do contexto, capturando frequentemente relações entre conceitos que podem ser perdidas por abordagens baseadas em palavras-chave.
Para obter mais detalhes, consulte Vetor esparso e Vetor denso.
Pesquisa multimodal
A pesquisa multimodal refere-se à pesquisa de semelhanças de dados não estruturados em várias modalidades (como imagens, vídeos, áudio, texto, etc.). Por exemplo, uma pessoa pode ser representada utilizando várias modalidades de dados, como impressões digitais, impressões de voz e caraterísticas faciais. A pesquisa híbrida suporta várias pesquisas em simultâneo. Por exemplo, procurar uma pessoa com impressões digitais e impressões de voz semelhantes.
Fluxo de trabalho
O fluxo de trabalho principal para efetuar uma Pesquisa Híbrida é o seguinte.
Gerar vectores densos através de modelos de incorporação como BERT e Transformers.
Gerar vectores esparsos através de modelos de incorporação como BM25, BGE-M3, SPLADE, etc.
Criar uma coleção no Zilliz e definir o esquema de coleção que inclui campos vectoriais densos e esparsos.
Insira os vectores esparsos-densos na coleção criada no passo anterior.
Efectue uma pesquisa híbrida: A pesquisa ANN em vectores densos devolverá um conjunto de resultados top-K mais semelhantes e a correspondência de texto em vectores esparsos também devolverá um conjunto de resultados top-K.
Normalização: Normalize as pontuações dos dois conjuntos de resultados top-K, convertendo as pontuações para um intervalo entre [0,1].
Escolher uma estratégia de classificação mais adequada para fundir e classificar novamente os dois conjuntos de resultados top-K e, finalmente, devolver um conjunto final de resultados top-K.
Fluxo de trabalho de pesquisa híbrida
Exemplos
Esta secção utilizará um exemplo específico para ilustrar como conduzir uma Pesquisa Híbrida em vectores esparsos e densos para melhorar a precisão das pesquisas de texto.
Criar uma coleção com vários campos vectoriais
O processo de criação de uma coleção inclui três partes: definir o esquema da coleção, configurar os parâmetros do índice e criar a coleção.
Definir o esquema
Neste exemplo, é necessário definir vários campos vectoriais no esquema da coleção. Atualmente, cada coleção pode incluir até 4 campos vectoriais por predefinição. Mas também é possível modificar o valor de proxy.maxVectorFieldNum
para incluir até 10 campos vectoriais numa coleção, conforme necessário.
O exemplo seguinte define um esquema de coleção, em que dense
e sparse
são os dois campos vectoriais.
id
: Este campo serve como chave primária para armazenar IDs de texto. O tipo de dados deste campo é INT64.text
: Este campo é utilizado para armazenar conteúdos textuais. O tipo de dados deste campo é VARCHAR, com um comprimento máximo de 1000 caracteres.dense
: Este campo é utilizado para armazenar os vectores densos dos textos. O tipo de dados deste campo é FLOAT_VECTOR, com uma dimensão vetorial de 768.sparse
: Este campo é utilizado para armazenar os vectores esparsos dos textos. O tipo de dados deste campo é SPARSE_FLOAT_VECTOR.
# Create a collection in customized setup mode
from pymilvus import (
MilvusClient, DataType
)
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)
# Create schema
schema = MilvusClient.create_schema(
auto_id=False,
enable_dynamic_field=True,
)
# Add fields to schema
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000)
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR)
schema.add_field(field_name="dense", datatype=DataType.FLOAT_VECTOR, dim=5)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("http://localhost:19530")
.token("root:Milvus")
.build());
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(false)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("text")
.dataType(DataType.VarChar)
.maxLength(1000)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("dense")
.dataType(DataType.FloatVector)
.dimension(768)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("sparse")
.dataType(DataType.SparseFloatVector)
.build());
// WIP
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});
// Create a collection in customized setup mode
// Define fields
const fields = [
{
name: "id",
data_type: DataType.Int64,
is_primary_key: true,
auto_id: false
},
{
name: "text",
data_type: DataType.VarChar,
max_length: 1000
},
{
name: "sparse",
data_type: DataType.SPARSE_FLOAT_VECTOR
},
{
name: "dense",
data_type: DataType.FloatVector,
dim: 768
}
]
export schema='{
"autoId": false,
"enabledDynamicField": true,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "text",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 1000
}
},
{
"fieldName": "sparse",
"dataType": "SparseFloatVector"
},
{
"fieldName": "dense",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "768"
}
}
]
}'
Durante as pesquisas de vectores esparsos, pode simplificar o processo de geração de vectores de incorporação esparsos tirando partido das capacidades da Pesquisa de Texto Completo. Para obter mais detalhes, consulte Pesquisa de texto completo.
Criar índice
Depois de definir o esquema de coleção, é necessário configurar os índices de vetor e as métricas de semelhança. Neste exemplo, é criado um índice IVF_FLAT para o campo de vetor denso dense
, e é criado um índice SPARSE_INVERTED_INDEX para o campo de vetor esparso sparse
. Para saber mais sobre os tipos de índices suportados, consulte Índice explicado.
from pymilvus import MilvusClient
# Prepare index parameters
index_params = client.prepare_index_params()
# Add indexes
index_params.add_index(
field_name="dense",
index_name="dense_index",
index_type="IVF_FLAT",
metric_type="IP",
params={"nlist": 128},
)
index_params.add_index(
field_name="sparse",
index_name="sparse_index",
index_type="SPARSE_INVERTED_INDEX", # Index type for sparse vectors
metric_type="IP", # Currently, only IP (Inner Product) is supported for sparse vectors
params={"inverted_index_algo": "DAAT_MAXSCORE"}, # The ratio of small vector values to be dropped during indexing
)
import io.milvus.v2.common.IndexParam;
import java.util.*;
Map<String, Object> denseParams = new HashMap<>();
denseParams.put("nlist", 128);
IndexParam indexParamForDenseField = IndexParam.builder()
.fieldName("dense")
.indexName("dense_index")
.indexType(IndexParam.IndexType.IVF_FLAT)
.metricType(IndexParam.MetricType.IP)
.extraParams(denseParams)
.build();
Map<String, Object> sparseParams = new HashMap<>();
sparseParams.put("inverted_index_algo": "DAAT_MAXSCORE");
IndexParam indexParamForSparseField = IndexParam.builder()
.fieldName("sparse")
.indexName("sparse_index")
.indexType(IndexParam.IndexType.SPARSE_INVERTED_INDEX)
.metricType(IndexParam.MetricType.IP)
.extraParams(sparseParams)
.build();
List<IndexParam> indexParams = new ArrayList<>();
indexParams.add(indexParamForDenseField);
indexParams.add(indexParamForSparseField);
const index_params = [{
field_name: "dense",
index_type: "IVF_FLAT",
metric_type: "IP"
},{
field_name: "sparse",
index_type: "SPARSE_INVERTED_INDEX",
metric_type: "IP"
}]
export indexParams='[
{
"fieldName": "dense",
"metricType": "IP",
"indexName": "dense_index",
"indexType":"IVF_FLAT",
"params":{"nlist":128}
},
{
"fieldName": "sparse",
"metricType": "IP",
"indexName": "sparse_index",
"indexType": "SPARSE_INVERTED_INDEX"
}
]'
Criar coleção
Crie uma coleção com o nome demo
com o esquema de coleção e os índices configurados nos dois passos anteriores.
from pymilvus import MilvusClient
client.create_collection(
collection_name="hybrid_search_collection",
schema=schema,
index_params=index_params
)
CreateCollectionReq createCollectionReq = CreateCollectionReq.builder()
.collectionName("hybrid_search_collection")
.collectionSchema(schema)
.indexParams(indexParams)
.build();
client.createCollection(createCollectionReq);
res = await client.createCollection({
collection_name: "hybrid_search_collection",
fields: fields,
index_params: index_params,
})
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
\"collectionName\": \"hybrid_search_collection\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"
Inserir dados
Insira os vectores esparsos e densos na coleção demo
.
from pymilvus import MilvusClient
data=[
{"id": 0, "text": "Artificial intelligence was founded as an academic discipline in 1956.", "sparse":{9637: 0.30856525997853057, 4399: 0.19771651149001523, ...}, "dense": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, ...]},
{"id": 1, "text": "Alan Turing was the first person to conduct substantial research in AI.", "sparse":{6959: 0.31025067641541815, 1729: 0.8265339135915016, ...}, "dense": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, ...]},
{"id": 2, "text": "Born in Maida Vale, London, Turing was raised in southern England.", "sparse":{1220: 0.15303302147479103, 7335: 0.9436728846033107, ...}, "dense": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, ...]}
res = client.insert(
collection_name="hybrid_search_collection",
data=data
)
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v2.service.vector.request.InsertReq;
Gson gson = new Gson();
JsonObject row1 = new JsonObject();
row1.addProperty("id", 1);
row1.addProperty("text", "Artificial intelligence was founded as an academic discipline in 1956.");
row1.add("dense", gson.toJsonTree(dense1));
row1.add("sparse", gson.toJsonTree(sparse1));
JsonObject row2 = new JsonObject();
row2.addProperty("id", 2);
row2.addProperty("text", "Alan Turing was the first person to conduct substantial research in AI.");
row2.add("dense", gson.toJsonTree(dense2));
row2.add("sparse", gson.toJsonTree(sparse2));
JsonObject row3 = new JsonObject();
row3.addProperty("id", 3);
row3.addProperty("text", "Born in Maida Vale, London, Turing was raised in southern England.");
row3.add("dense", gson.toJsonTree(dense3));
row3.add("sparse", gson.toJsonTree(sparse3));
List<JsonObject> data = Arrays.asList(row1, row2, row3);
InsertReq insertReq = InsertReq.builder()
.collectionName("hybrid_search_collection")
.data(data)
.build();
InsertResp insertResp = client.insert(insertReq);
const { MilvusClient, DataType } = require("@zilliz/milvus2-sdk-node")
var data = [
{id: 0, text: "Artificial intelligence was founded as an academic discipline in 1956.", sparse:[9637: 0.30856525997853057, 4399: 0.19771651149001523, ...] , dense: [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]},
{id: 1, text: "Alan Turing was the first person to conduct substantial research in AI.", sparse:[6959: 0.31025067641541815, 1729: 0.8265339135915016, ...] , dense: [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]},
{id: 2, text: "Born in Maida Vale, London, Turing was raised in southern England." , sparse:[1220: 0.15303302147479103, 7335: 0.9436728846033107, ...] , dense: [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592]}
]
var res = await client.insert({
collection_name: "hybrid_search_collection",
data: data,
})
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"data": [
{"id": 0, "text": "Artificial intelligence was founded as an academic discipline in 1956.", "sparse":{"9637": 0.30856525997853057, "4399": 0.19771651149001523}, "dense": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, ...]},
{"id": 1, "text": "Alan Turing was the first person to conduct substantial research in AI.", "sparse":{"6959": 0.31025067641541815, "1729": 0.8265339135915016}, "dense": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, ...]},
{"id": 2, "text": "Born in Maida Vale, London, Turing was raised in southern England.", "sparse":{"1220": 0.15303302147479103, "7335": 0.9436728846033107}, "dense": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, ...]}
],
"collectionName": "hybrid_search_collection"
}'
Criar várias instâncias de AnnSearchRequest
O Hybrid Search é implementado através da criação de vários AnnSearchRequest
na função hybrid_search()
, em que cada AnnSearchRequest
representa um pedido de pesquisa ANN básico para um campo vetorial específico. Por conseguinte, antes de efetuar uma Pesquisa Híbrida, é necessário criar um AnnSearchRequest
para cada campo vetorial.
No Hybrid Search, cada AnnSearchRequest
suporta apenas um vetor de consulta.
Suponhamos que o texto da consulta "Who started AI research?" já foi convertido em vectores esparsos e densos. Com base nisto, são criados dois pedidos de pesquisa AnnSearchRequest
para os campos vectoriais sparse
e dense
, respetivamente, como se mostra no exemplo seguinte.
from pymilvus import AnnSearchRequest
query_dense_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
search_param_1 = {
"data": [query_dense_vector],
"anns_field": "dense",
"param": {
"metric_type": "IP",
"params": {"nprobe": 10}
},
"limit": 2
}
request_1 = AnnSearchRequest(**search_param_1)
query_sparse_vector = {3573: 0.34701499565746674}, {5263: 0.2639375518635271}
search_param_2 = {
"data": [query_sparse_vector],
"anns_field": "sparse",
"param": {
"metric_type": "IP",
"params": {}
},
"limit": 2
}
request_2 = AnnSearchRequest(**search_param_2)
reqs = [request_1, request_2]
import io.milvus.v2.service.vector.request.AnnSearchReq;
import io.milvus.v2.service.vector.request.data.BaseVector;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.request.data.SparseFloatVec;
float[] dense = new float[]{-0.0475336798f, 0.0521207601f, 0.0904406682f, ...};
SortedMap<Long, Float> sparse = new TreeMap<Long, Float>() {{
put(3573L, 0.34701499f);
put(5263L, 0.263937551f);
...
}};
List<BaseVector> queryDenseVectors = Collections.singletonList(new FloatVec(dense));
List<BaseVector> querySparseVectors = Collections.singletonList(new SparseFloatVec(sparse));
List<AnnSearchReq> searchRequests = new ArrayList<>();
searchRequests.add(AnnSearchReq.builder()
.vectorFieldName("dense")
.vectors(queryDenseVectors)
.metricType(IndexParam.MetricType.IP)
.params("{\"nprobe\": 10}")
.topK(2)
.build());
searchRequests.add(AnnSearchReq.builder()
.vectorFieldName("sparse")
.vectors(querySparseVectors)
.metricType(IndexParam.MetricType.IP)
.params()
.topK(2)
.build());
const search_param_1 = {
"data": query_vector,
"anns_field": "dense",
"param": {
"metric_type": "IP",
"params": {"nprobe": 10}
},
"limit": 2
}
const search_param_2 = {
"data": query_sparse_vector,
"anns_field": "sparse",
"param": {
"metric_type": "IP",
"params": {}
},
"limit": 2
}
export req='[
{
"data": [[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592,....]],
"annsField": "dense",
"params": {
"params": {
"nprobe": 10
}
},
"limit": 2
},
{
"data": [{"3573": 0.34701499565746674}, {"5263": 0.2639375518635271}],
"annsField": "sparse",
"params": {
"params": {}
},
"limit": 2
}
]'
Como o parâmetro limit
está definido como 2, cada AnnSearchRequest
retorna 2 resultados de pesquisa. Neste exemplo, são criados 2 AnnSearchRequest
, pelo que será devolvido um total de 4 resultados de pesquisa.
Configurar uma estratégia de ranqueamento
Para fundir e classificar novamente os dois conjuntos de resultados de pesquisa ANN, é necessário selecionar uma estratégia de classificação adequada. O Zilliz suporta dois tipos de estratégias de reranking: WeightedRanker e RRFRanker. Ao escolher uma estratégia de reranking, uma coisa a considerar é se existe alguma ênfase para uma ou mais pesquisas ANN básicas nos campos vectoriais.
WeightedRanker: Esta estratégia é recomendada se for necessário que os resultados dêem ênfase a um determinado campo vetorial. O WeightedRanker permite-lhe atribuir pesos mais elevados a determinados campos vectoriais, dando-lhes mais ênfase. Por exemplo, em pesquisas multimodais, as descrições textuais de uma imagem podem ser consideradas mais importantes do que as cores dessa imagem.
RRFRanker (Reciprocal Rank Fusion Ranker): Esta estratégia é recomendada quando não existe uma ênfase específica. O RRF pode equilibrar eficazmente a importância de cada campo vetorial.
Para mais pormenores sobre os mecanismos destas duas estratégias de classificação, consulte Classificação.
Os dois exemplos seguintes demonstram como utilizar as estratégias de reclassificação WeightedRanker e RRFRanker.
Exemplo 1: Usar o WeightedRanker
Ao usar a estratégia WeightedRanker, é necessário inserir valores de peso na função
WeightedRanker
. O número de pesquisas básicas de RNA em uma Pesquisa Híbrida corresponde ao número de valores que precisam ser inseridos. Os valores de entrada devem estar no intervalo [0,1], sendo que os valores mais próximos de 1 indicam maior importância.from pymilvus import WeightedRanker rerank= WeightedRanker(0.8, 0.3)
import io.milvus.v2.service.vector.request.ranker.BaseRanker; import io.milvus.v2.service.vector.request.ranker.WeightedRanker; BaseRanker reranker = new WeightedRanker(Arrays.asList(0.8f, 0.3f));
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node"; const rerank = WeightedRanker(0.8, 0.3);
export rerank='{ "strategy": "ws", "params": {"weights": [0.8,0.3]} }'
Exemplo 2: Usar o RRFRanker
Ao utilizar a estratégia RRFRanker, é necessário introduzir o valor do parâmetro
k
no RRFRanker. O valor padrão dek
é 60. Esse parâmetro ajuda a determinar como as classificações são combinadas de diferentes pesquisas ANN, com o objetivo de equilibrar e misturar a importância em todas as pesquisas.from pymilvus import RRFRanker ranker = RRFRanker(100)
import io.milvus.v2.service.vector.request.ranker.BaseRanker; import io.milvus.v2.service.vector.request.ranker.RRFRanker; BaseRanker reranker = new RRFRanker(100);
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node"; const rerank = RRFRanker("100");
export rerank='{ "strategy": "rrf", "params": { "k": 100} }'
Executar uma pesquisa híbrida
Antes de realizar uma Hybrid Search, é necessário carregar a coleção na memória. Se algum campo de vetor da coleção não tiver um índice ou não estiver carregado, ocorrerá um erro ao chamar o método Hybrid Search.
from pymilvus import MilvusClient
res = client.hybrid_search(
collection_name="hybrid_search_collection",
reqs=reqs,
ranker=ranker,
limit=2
)
for hits in res:
print("TopK results:")
for hit in hits:
print(hit)
import io.milvus.v2.common.ConsistencyLevel;
import io.milvus.v2.service.vector.request.HybridSearchReq;
import io.milvus.v2.service.vector.response.SearchResp;
HybridSearchReq hybridSearchReq = HybridSearchReq.builder()
.collectionName("hybrid_search_collection")
.searchRequests(searchRequests)
.ranker(reranker)
.topK(2)
.consistencyLevel(ConsistencyLevel.BOUNDED)
.build();
SearchResp searchResp = client.hybridSearch(hybridSearchReq);
const { MilvusClient, DataType } = require("@zilliz/milvus2-sdk-node")
res = await client.loadCollection({
collection_name: "hybrid_search_collection"
})
import { MilvusClient, RRFRanker, WeightedRanker } from '@zilliz/milvus2-sdk-node';
const search = await client.search({
collection_name: "hybrid_search_collection",
data: [search_param_1, search_param_2],
limit: 2,
rerank: RRFRanker(100)
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/advanced_search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
\"collectionName\": \"hybrid_search_collection\",
\"search\": ${req},
\"rerank\": {
\"strategy\":\"rrf\",
\"params\": {
\"k\": 10
}
},
\"limit\": 3,
\"outputFields\": [
\"user_id\",
\"word_count\",
\"book_describe\"
]
}"
O resultado é o seguinte.
["['id: 844, distance: 0.006047376897186041, entity: {}', 'id: 876, distance: 0.006422005593776703, entity: {}']"]
Uma vez que limit=2
é especificado na Pesquisa Híbrida, o Zilliz irá classificar novamente os quatro resultados de pesquisa do passo 3 e, por fim, devolver apenas os 2 resultados de pesquisa mais semelhantes.