하이브리드 검색
하이브리드 검색은 여러 개의 ANN 검색을 동시에 수행하고, 이러한 ANN 검색에서 여러 결과 집합의 순위를 재조정하여 최종적으로 하나의 결과 집합을 반환하는 검색 방법을 말합니다. 하이브리드 검색을 사용하면 검색 정확도를 높일 수 있습니다. Zilliz는 여러 개의 벡터 필드가 있는 컬렉션에서 하이브리드 검색을 수행할 수 있도록 지원합니다.
하이브리드 검색은 희소 밀도 벡터 검색과 다중 모드 검색을 포함한 시나리오에서 가장 일반적으로 사용됩니다. 이 가이드에서는 구체적인 예시를 통해 Zilliz에서 하이브리드 검색을 수행하는 방법을 설명합니다.
시나리오
하이브리드 검색은 다음 두 가지 시나리오에 적합합니다.
희소 밀도 벡터 검색
다양한 유형의 벡터는 서로 다른 정보를 나타낼 수 있으며, 다양한 임베딩 모델을 사용하면 데이터의 다양한 특징과 측면을 보다 포괄적으로 나타낼 수 있습니다. 예를 들어, 같은 문장에 대해 서로 다른 임베딩 모델을 사용하면 의미적 의미를 나타내는 고밀도 벡터와 문장의 단어 빈도를 나타내는 스파스 벡터를 생성할 수 있습니다.
스파스 벡터: 스파스 벡터는 벡터 차원이 높고 0이 아닌 값이 거의 없다는 특징이 있습니다. 이러한 구조는 기존의 정보 검색 애플리케이션에 특히 적합합니다. 대부분의 경우, 스파스 벡터에 사용되는 차원 수는 하나 이상의 언어에 걸쳐 서로 다른 토큰에 해당합니다. 각 차원에는 문서 내에서 해당 토큰의 상대적 중요성을 나타내는 값이 할당됩니다. 이 레이아웃은 텍스트 매칭과 관련된 작업에 유리합니다.
고밀도 벡터: 고밀도 벡터는 신경망에서 파생된 임베딩입니다. 이러한 벡터를 정렬된 배열로 배열하면 입력 텍스트의 의미적 본질을 포착할 수 있습니다. 고밀도 벡터는 텍스트 처리에만 국한되지 않고 컴퓨터 비전에서도 시각적 데이터의 의미를 표현하는 데 광범위하게 사용됩니다. 일반적으로 텍스트 임베딩 모델에 의해 생성되는 이러한 고밀도 벡터는 대부분 또는 모든 요소가 0이 아닌 것이 특징입니다. 따라서 고밀도 벡터는 정확한 텍스트가 일치하지 않더라도 벡터 거리를 기반으로 가장 유사한 결과를 반환할 수 있기 때문에 시맨틱 검색 애플리케이션에 특히 효과적입니다. 이 기능을 사용하면 키워드 기반 접근 방식에서는 놓칠 수 있는 개념 간의 관계를 포착하여 보다 미묘하고 문맥을 인식하는 검색 결과를 얻을 수 있습니다.
자세한 내용은 스파스 벡터 및 밀도 벡터를 참조하세요.
멀티모달 검색
멀티모달 검색은 이미지, 동영상, 오디오, 텍스트 등 여러 양식에 걸쳐 비정형 데이터의 유사성 검색을 말합니다. 예를 들어, 지문, 음성, 얼굴 특징 등 다양한 양식의 데이터를 사용하여 사람을 표현할 수 있습니다. 하이브리드 검색은 여러 검색을 동시에 지원합니다. 예를 들어 지문과 음성 지문이 비슷한 사람을 검색할 수 있습니다.
워크플로
하이브리드 검색을 수행하는 주요 워크플로는 다음과 같습니다.
BERT 및 Transformers와 같은 임베딩 모델을 통해 고밀도 벡터를 생성합니다.
Zilliz에서 컬렉션을 생성하고 고밀도 및 스파스 벡터 필드를 모두 포함하는 컬렉션 스키마를 정의합니다.
이전 단계에서 생성한 컬렉션에 스파스-밀도 벡터를 삽입합니다.
하이브리드 검색을 수행합니다: 고밀도 벡터에 대한 ANN 검색은 가장 유사한 상위 K개의 결과 집합을 반환하고, 스파스 벡터에 대한 텍스트 일치도 상위 K개의 결과 집합을 반환합니다.
정규화: 정규화: 상위 K 결과의 두 세트의 점수를 정규화하여 점수를 [0,1] 사이의 범위로 변환합니다.
적절한 재순위 전략을 선택하여 두 개의 상위 K 결과 세트를 병합하고 재순위화하여 최종적으로 상위 K 결과 세트를 반환합니다.
하이브리드 검색 워크플로
예제
이 섹션에서는 구체적인 예시를 통해 희소밀도 벡터에 대해 하이브리드 검색을 수행하여 텍스트 검색의 정확도를 높이는 방법을 설명합니다.
여러 개의 벡터 필드가 있는 컬렉션 만들기
컬렉션을 만드는 과정은 컬렉션 스키마 정의, 인덱스 매개변수 구성, 컬렉션 생성의 세 부분으로 구성됩니다.
스키마 정의
이 예에서는 컬렉션 스키마 내에 여러 개의 벡터 필드를 정의해야 합니다. 현재 각 컬렉션은 기본적으로 최대 4개의 벡터 필드를 포함할 수 있습니다. 그러나 값을 수정하여 proxy.maxVectorFieldNum
값을 수정하여 필요에 따라 컬렉션에 최대 10개의 벡터 필드를 포함할 수도 있습니다.
다음 예는 컬렉션 스키마를 정의하는 예로, dense
및 sparse
은 두 개의 벡터 필드입니다.
id
: 이 필드는 텍스트 ID를 저장하는 기본 키 역할을 합니다. 이 필드의 데이터 유형은 INT64입니다.text
: 이 필드는 텍스트 콘텐츠를 저장하는 데 사용됩니다. 이 필드의 데이터 유형은 최대 길이가 1000자인 VARCHAR입니다.dense
: 이 필드는 텍스트의 밀도 벡터를 저장하는 데 사용됩니다. 이 필드의 데이터 유형은 FLOAT_VECTOR이며 벡터 차원은 768입니다.sparse
: 이 필드는 텍스트의 스파스 벡터를 저장하는 데 사용됩니다. 이 필드의 데이터 유형은 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"
}
}
]
}'
스파스 벡터 검색 시, 전체 텍스트 검색 기능을 활용하여 스파스 임베딩 벡터를 생성하는 프로세스를 간소화할 수 있습니다. 자세한 내용은 전체 텍스트 검색을 참조하세요.
색인 생성
수집 스키마를 정의한 후에는 벡터 인덱스와 유사성 메트릭을 설정해야 합니다. 이 예에서는 고밀도 벡터 필드 dense
에 대해 IVF_FLAT 인덱스가 생성되고, 희소 벡터 필드 sparse
에 대해 SPARSE_INVERTED_INDEX가 생성됩니다. 지원되는 인덱스 유형에 대해 알아보려면 인덱스 설명을 참조하세요.
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"
}
]'
컬렉션 만들기
앞의 두 단계에서 구성한 컬렉션 스키마와 인덱스를 사용하여 demo
이라는 이름의 컬렉션을 만듭니다.
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
}"
데이터 삽입
희소 밀도 벡터를 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"
}'
여러 개의 AnnSearchRequest 인스턴스 만들기
하이브리드 검색은 hybrid_search()
함수에 AnnSearchRequest
을 여러 개 생성하여 구현되며, 각 AnnSearchRequest
은 특정 벡터 필드에 대한 기본 ANN 검색 요청을 나타냅니다. 따라서 하이브리드 검색을 수행하기 전에 각 벡터 필드에 대해 AnnSearchRequest
을 생성해야 합니다.
하이브리드 검색에서 각 AnnSearchRequest
은 하나의 쿼리 벡터만 지원합니다.
"누가 AI 연구를 시작했나요?"라는 쿼리 텍스트가 이미 스파스 및 밀도 벡터로 변환되어 있다고 가정해 보겠습니다. 이를 기반으로 다음 예와 같이 sparse
및 dense
벡터 필드에 대해 각각 두 개의 AnnSearchRequest
검색 요청이 생성됩니다.
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
}
]'
limit
매개 변수가 2로 설정되어 있으므로 AnnSearchRequest
각각 2개의 검색 결과를 반환합니다. 이 예에서는 AnnSearchRequest
2개가 생성되므로 총 4개의 검색 결과가 반환됩니다.
순위 재조정 전략 구성
두 세트의 ANN 검색 결과를 병합하고 재랭크하려면 적절한 재랭크 전략을 선택해야 합니다. 질리즈는 두 가지 유형의 리랭크 전략을 지원합니다: 가중랭커와 RRFRanker입니다. 재랭크 전략을 선택할 때 고려해야 할 한 가지는 벡터 필드에서 하나 이상의 기본 ANN 검색에 중점을 둘 것인지 여부입니다.
가중 랭커: 이 전략은 특정 벡터 필드를 강조하는 결과가 필요한 경우에 권장됩니다. 가중랭커를 사용하면 특정 벡터 필드에 더 높은 가중치를 할당하여 해당 필드를 더 강조할 수 있습니다. 예를 들어, 다중 모드 검색에서는 이미지의 텍스트 설명이 이미지의 색상보다 더 중요하게 고려될 수 있습니다.
상호 순위 퓨전 랭킹(RRFRanker): 이 전략은 특별히 강조할 부분이 없을 때 권장됩니다. RRF는 각 벡터 필드의 중요도를 효과적으로 균형 있게 조정할 수 있습니다.
이 두 가지 순위 재조정 전략의 메커니즘에 대한 자세한 내용은 순위 재조정을 참조하세요.
다음 두 가지 예에서는 WeightedRanker 및 RRFRanker 재랭킹 전략을 사용하는 방법을 설명합니다.
예 1: 가중치랭커 사용하기
WeightedRanker 전략을 사용할 때는
WeightedRanker
함수에 가중치 값을 입력해야 합니다. 하이브리드 검색의 기본 ANN 검색 횟수는 입력해야 하는 값의 수에 해당합니다. 입력 값은 [0,1] 범위여야 하며, 1에 가까운 값일수록 중요도가 높음을 나타냅니다.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]} }'
예 2: RRFRanker 사용
RRFRanker 전략을 사용할 때는 매개 변수 값
k
을 RRFRanker에 입력해야 합니다.k
의 기본값은 60입니다. 이 매개변수는 모든 검색에서 중요도의 균형을 맞추고 혼합하는 것을 목표로 다양한 ANN 검색에서 순위를 결합하는 방법을 결정하는 데 도움이 됩니다.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} }'
하이브리드 검색 수행
하이브리드 검색을 수행하기 전에 컬렉션을 메모리에 로드해야 합니다. 컬렉션의 벡터 필드에 인덱스가 없거나 로드되지 않은 경우, 하이브리드 검색 메서드를 호출할 때 오류가 발생합니다.
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\"
]
}"
다음은 출력입니다.
["['id: 844, distance: 0.006047376897186041, entity: {}', 'id: 876, distance: 0.006422005593776703, entity: {}']"]
하이브리드 검색에 limit=2
이 지정되어 있으므로 Zilliz는 3단계에서 4개의 검색 결과의 순위를 재조정하여 최종적으로 가장 유사한 상위 2개의 검색 결과만 반환합니다.