Ricerca ibrida
La ricerca ibrida si riferisce a un metodo di ricerca che conduce simultaneamente più ricerche di RNA, rielabora più serie di risultati da queste ricerche di RNA e alla fine restituisce una singola serie di risultati. L'uso della ricerca ibrida può migliorare l'accuratezza della ricerca. Zilliz supporta l'esecuzione di una ricerca ibrida su una collezione con più campi vettoriali.
La ricerca ibrida è più comunemente utilizzata in scenari che includono ricerche vettoriali rade e dense e ricerche multimodali. Questa guida illustra come condurre una ricerca ibrida in Zilliz con un esempio specifico.
Scenari
La ricerca ibrida è adatta ai due scenari seguenti.
Ricerca vettoriale sparsa e densa
Diversi tipi di vettori possono rappresentare informazioni diverse e l'uso di vari modelli di incorporazione può rappresentare in modo più completo diverse caratteristiche e aspetti dei dati. Ad esempio, l'uso di diversi modelli di incorporamento per la stessa frase può generare un vettore denso per rappresentare il significato semantico e un vettore rado per rappresentare la frequenza delle parole nella frase.
Vettori sparsi: I vettori sparsi sono caratterizzati da un'elevata dimensionalità del vettore e dalla presenza di pochi valori non nulli. Questa struttura li rende particolarmente adatti alle applicazioni tradizionali di information retrieval. Nella maggior parte dei casi, il numero di dimensioni utilizzate nei vettori sparsi corrisponde a diversi token in una o più lingue. A ogni dimensione viene assegnato un valore che indica l'importanza relativa di quel token all'interno del documento. Questa disposizione si rivela vantaggiosa per i compiti che prevedono la corrispondenza del testo.
Vettori densi: I vettori densi sono incorporazioni derivate dalle reti neurali. Disposti in un array ordinato, questi vettori catturano l'essenza semantica del testo in ingresso. Si noti che i vettori densi non sono limitati all'elaborazione del testo; sono anche ampiamente utilizzati nella computer vision per rappresentare la semantica dei dati visivi. Questi vettori densi, di solito generati da modelli di incorporazione del testo, sono caratterizzati dalla maggior parte o da tutti gli elementi non nulli. Pertanto, i vettori densi sono particolarmente efficaci per le applicazioni di ricerca semantica, in quanto possono restituire i risultati più simili in base alla distanza vettoriale anche in assenza di corrispondenze testuali esatte. Questa capacità consente di ottenere risultati di ricerca più sfumati e consapevoli del contesto, spesso cogliendo relazioni tra concetti che potrebbero sfuggire agli approcci basati sulle parole chiave.
Per maggiori dettagli, consultare Sparse Vector e Dense Vector.
Ricerca multimodale
La ricerca multimodale si riferisce alla ricerca di similarità di dati non strutturati attraverso più modalità (come immagini, video, audio, testo, ecc.). Ad esempio, una persona può essere rappresentata utilizzando diverse modalità di dati, come le impronte digitali, le impronte vocali e i tratti del viso. La ricerca ibrida supporta più ricerche simultanee. Ad esempio, la ricerca di una persona con impronte digitali e impronte vocali simili.
Flusso di lavoro
Il flusso di lavoro principale per condurre una ricerca ibrida è il seguente.
Generare vettori densi attraverso modelli di embedding come BERT e Transformers.
Generare vettori radi attraverso modelli di embedding come BM25, BGE-M3, SPLADE, ecc.
Creare una collezione in Zilliz e definire lo schema della collezione che include campi vettoriali densi e radi.
Inserire i vettori sparsi-densi nella collezione appena creata nel passaggio precedente.
Eseguire una ricerca ibrida: La ricerca ANN sui vettori densi restituirà un insieme di risultati top-K più simili, mentre la corrispondenza testuale sui vettori radi restituirà anch'essa un insieme di risultati top-K.
Normalizzazione: Normalizzare i punteggi delle due serie di risultati top-K, convertendo i punteggi in un intervallo compreso tra [0,1].
Scegliere una strategia di reranking appropriata per unire e rerankare i due insiemi di risultati top-K e restituire infine un insieme finale di risultati top-K.
Flusso di lavoro della ricerca ibrida
Esempi
Questa sezione utilizzerà un esempio specifico per illustrare come condurre una ricerca ibrida su vettori sparsi e densi per migliorare l'accuratezza delle ricerche di testo.
Creare una raccolta con più campi vettoriali
Il processo di creazione di una raccolta comprende tre parti: definizione dello schema della raccolta, configurazione dei parametri dell'indice e creazione della raccolta.
Definire lo schema
In questo esempio, è necessario definire più campi vettoriali nello schema della collezione. Attualmente, ogni collezione può includere fino a 4 campi vettoriali per impostazione predefinita. Ma è possibile modificare il valore di proxy.maxVectorFieldNum
per includere fino a 10 campi vettoriali in una collezione, se necessario.
L'esempio seguente definisce uno schema di collezione, dove dense
e sparse
sono i due campi vettoriali.
id
: Questo campo serve come chiave primaria per memorizzare gli ID del testo. Il tipo di dati di questo campo è INT64.text
: Questo campo è utilizzato per memorizzare il contenuto testuale. Il tipo di dati di questo campo è VARCHAR, con una lunghezza massima di 1000 caratteri.dense
: Questo campo viene utilizzato per memorizzare i vettori densi dei testi. Il tipo di dati di questo campo è FLOAT_VECTOR, con una dimensione del vettore di 768.sparse
: Questo campo viene utilizzato per memorizzare i vettori sparsi dei testi. Il tipo di dati di questo 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 le ricerche di vettori sparsi, è possibile semplificare il processo di generazione di vettori di incorporamento sparsi sfruttando le funzionalità di Full Text Search. Per maggiori dettagli, vedere Ricerca a testo completo.
Creare l'indice
Dopo aver definito lo schema della collezione, è necessario impostare gli indici dei vettori e le metriche di somiglianza. In questo esempio, viene creato un indice IVF_FLAT per il campo vettoriale denso dense
, e uno SPARSE_INVERTED_INDEX per il campo vettoriale rado sparse
. Per conoscere i tipi di indici supportati, vedere Indice spiegato.
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={"drop_ratio_build": 0.2}, # 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("drop_ratio_build", 0.2);
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"
}
]'
Creare una collezione
Creare una collezione chiamata demo
con lo schema della collezione e gli indici configurati nei due passi precedenti.
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
}"
Inserire i dati
Inserire i vettori sparsi e densi nella collezione 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"
}'
Creare istanze multiple di AnnSearchRequest
La ricerca ibrida è implementata creando più istanze AnnSearchRequest
nella funzione hybrid_search()
, dove ogni AnnSearchRequest
rappresenta una richiesta di ricerca ANN di base per uno specifico campo vettoriale. Pertanto, prima di effettuare una ricerca ibrida, è necessario creare un AnnSearchRequest
per ogni campo vettoriale.
Nella Ricerca ibrida, ogni AnnSearchRequest
supporta un solo vettore di interrogazione.
Supponiamo che il testo della query "Who started AI research?" sia già stato convertito in vettori sparsi e densi. Su questa base, vengono create due richieste di ricerca AnnSearchRequest
per i campi vettoriali sparse
e dense
rispettivamente, come mostrato nell'esempio seguente.
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": {"drop_ratio_build": 0.2}
},
"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("{\"drop_ratio_build\": 0.2}")
.topK(2)
.build());
const search_param_1 = {
"data": query_vector,
"anns_field": "dense",
"param": {
"metric_type": "IP", // 参数值需要与 Collection Schema 中定义的保持一致
"params": {"nprobe": 10}
},
"limit": 2 // AnnSearchRequest 返还的搜索结果数量
}
const search_param_2 = {
"data": query_sparse_vector,
"anns_field": "sparse",
"param": {
"metric_type": "IP", // 参数值需要与 Collection Schema 中定义的保持一致
"params": {"drop_ratio_build": 0.2}
},
"limit": 2 // AnnSearchRequest 返还的搜索结果数量
}
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": {
"drop_ratio_build": 0.2
}
},
"limit": 2
}
]'
Poiché il parametro limit
è impostato su 2, ogni AnnSearchRequest
restituisce 2 risultati di ricerca. In questo esempio, sono stati creati 2 AnnSearchRequest
, quindi verranno restituiti in totale 4 risultati di ricerca.
Configurare una strategia di reranking
Per unire e classificare i due gruppi di risultati di ricerca ANN, è necessario selezionare una strategia di reranking appropriata. Zilliz supporta due tipi di strategia di reranking: WeightedRanker e RRFRanker. Quando si sceglie una strategia di reranking, una cosa da considerare è se c'è un'enfasi per una o più ricerche RNA di base sui campi vettoriali.
WeightedRanker: Questa strategia è consigliata se si desidera che i risultati enfatizzino un particolare campo vettoriale. Il WeightedRanker consente di assegnare pesi maggiori a determinati campi vettoriali, enfatizzandoli maggiormente. Ad esempio, nelle ricerche multimodali, le descrizioni testuali di un'immagine potrebbero essere considerate più importanti dei colori presenti nell'immagine.
RRFRanker (Reciprocal Rank Fusion Ranker): Questa strategia è consigliata quando non c'è un'enfasi specifica. L'RRF può bilanciare efficacemente l'importanza di ciascun campo vettoriale.
Per maggiori dettagli sui meccanismi di queste due strategie di reranking, consultare Reranking.
I due esempi seguenti mostrano come utilizzare le strategie di reranking WeightedRanker e RRFRanker.
Esempio 1: Uso del WeightedRanker
Quando si utilizza la strategia WeightedRanker, è necessario inserire i valori dei pesi nella funzione
WeightedRanker
. Il numero di ricerche della RNA di base in una ricerca ibrida corrisponde al numero di valori che devono essere immessi. I valori inseriti devono essere compresi nell'intervallo [0,1], con valori più vicini a 1 che indicano una maggiore importanza.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]} }'
Esempio 2: Utilizzo di RRFRanker
Quando si utilizza la strategia RRFRanker, è necessario inserire il valore del parametro
k
nel RRFRanker. Il valore predefinito dik
è 60. Questo parametro aiuta a determinare il modo in cui vengono combinati i ranghi delle diverse ricerche di RNA, con l'obiettivo di bilanciare e fondere l'importanza di tutte le ricerche.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} }'
Eseguire una ricerca ibrida
Prima di eseguire una ricerca ibrida, è necessario caricare la collezione in memoria. Se i campi vettoriali dell'insieme non hanno un indice o non sono caricati, si verificherà un errore durante la chiamata al metodo 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\"
]
}"
L'output è il seguente.
["['id: 844, distance: 0.006047376897186041, entity: {}', 'id: 876, distance: 0.006422005593776703, entity: {}']"]
Dal momento che limit=2
è specificato nella ricerca ibrida, Zilliz esegue un rerank dei quattro risultati di ricerca del passo 3 e restituisce solo i primi due risultati più simili.