重み付きランカー
重み付きランカーは、複数の検索パスから得られた結果に異なる重要度の重みを割り当てることで、結果をインテリジェントに組み合わせて優先順位を付けます。熟練したシェフが複数の食材をバランスよく調合して完璧な料理を作るのと同様に、重み付きランカーは異なる検索結果をバランスよく調整して、最も関連性の高い統合された結果を提供します。このアプローチは、特定のフィールドが他のフィールドよりも最終的なランキングに大きく貢献すべきであるような、複数のベクトルフィールドやモダリティにまたがる検索に最適です。
重み付きランカーの使用タイミング
重み付きランカーは、複数のベクトル検索パスからの結果を組み合わせる必要があるハイブリッド検索シナリオのために特別に設計されています。特に効果的なのは:
使用例 | 例 | 重み付きランカーがうまく機能する理由 |
|---|---|---|
EC検索 | 商品検索で画像類似度とテキスト説明を組み合わせる | ファッション商品では視覚的類似度を優先し、技術的商品ではテキスト説明を重視するように小売業者が調整できる |
メディアコンテンツ検索 | 視覚的特徴と音声トランスクリプトの両方を使用したビデオ検索 | クエリの意図に基づいて視覚コンテンツと音声対話の重要度をバランスさせる |
文書検索 | 異なるセクション用に複数の埋め込みを持つ企業文書検索 | 全文埋め込みを考慮しつつ、タイトルや要約の埋め込みにより高い重みを与える |
ハイブリッド検索アプリケーションで複数の検索パスを相対的な重要度を制御しながら組み合わせる必要がある場合、重み付きランカーが最適な選択です。
重み付きランカーの仕組み
重み付きランカー戦略の主なワークフローは以下の通りです:
-
検索スコアの収集: ベクトル検索の各パスからの結果とスコアを収集します(score_1, score_2)。
-
スコアの正規化: 各検索では異なる類似度メトリックが使用されるため、スコア分布が異なります。例えば、Inner Product(IP)を類似度タイプとして使用すると [-∞, +∞] の範囲のスコアになる場合がありますが、ユークリッド距離(L2)を使用すると [0, +∞] の範囲のスコアになります。異なる検索からのスコア範囲は異なり、直接比較できないため、各検索パスのスコアを正規化する必要があります。通常、
arctan関数が適用され、スコアは [0, 1] の範囲に変換されます(score_1_normalized, score_2_normalized)。1に近いスコアほど類似度が高いことを示します。 -
重みの割り当て: 異なるベクトルフィールドに割り当てられた重要度に基づき、重み(wi)が正規化されたスコア(score_1_normalized, score_2_normalized)に割り当てられます。各パスの重みは [0, 1] の範囲にある必要があります。結果として得られる重み付きスコアは score_1_weighted および score_2_weighted です。
-
スコアの統合: 重み付きスコア(score_1_weighted, score_2_weighted)は上位から下位にランク付けされ、最終的なスコアセット(score_final)が生成されます。

重み付きランカーの例
この例は、画像とテキストを含むマルチモーダルハイブリッド検索(topK=5)を示し、重み付きランカー戦略が2つのANN検索からの結果をどのように再ランク付けするかを説明しています。
-
画像に対するANN検索の結果(topK=5):
ID
スコア (画像)
101
0.92
203
0.88
150
0.85
198
0.83
175
0.8
-
テキストに対するANN検索の結果(topK=5):
ID
スコア (テキスト)
198
0.91
101
0.87
110
0.85
175
0.82
250
0.78
-
重み付きランカーを使用して画像とテキスト検索結果に重みを割り当てます。画像ANN検索の重みを0.6、テキスト検索の重みを0.4と仮定します。
ID
スコア (画像)
スコア (テキスト)
重み付きスコア
101
0.92
0.87
0.6×0.92+0.4×0.87=0.90
203
0.88
N/A
0.6×0.88+0.4×0=0.528
150
0.85
N/A
0.6×0.85+0.4×0=0.51
198
0.83
0.91
0.6×0.83+0.4×0.91=0.86
175
0.80
0.82
0.6×0.80+0.4×0.82=0.81
110
画像にはなし
0.85
0.6×0+0.4×0.85=0.34
250
画像にはなし
0.78
0.6×0+0.4×0.78=0.312
-
再ランク付け後の最終結果(topK=5):
ランク
ID
最終スコア
1
101
0.90
2
198
0.86
3
175
0.81
4
203
0.528
5
150
0.51
重み付きランカーの使用法
重み付きランカー戦略を使用する際には、重み値を入力する必要があります。入力する重み値の数は、ハイブリッド検索内の基本的なANN検索リクエストの数に対応する必要があります。入力する重み値は [0,1] の範囲内にある必要があり、1に近い値ほど重要度が高いことを示します。
重み付きランカーの作成
例えば、ハイブリッド検索に2つの基本的なANN検索リクエストがあるとします:テキスト検索と画像検索。テキスト検索がより重要であるとされる場合は、より大きな重みを割り当てる必要があります。
- Python
- Java
- NodeJS
- Go
- cURL
from pymilvus import Function, FunctionType
rerank = Function(
name="weight",
input_field_names=[], # 空のリストでなければなりません
function_type=FunctionType.RERANK,
params={
"reranker": "weighted",
"weights": [0.1, 0.9],
"norm_score": True # オプション
}
)
import io.milvus.common.clientenum.FunctionType;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
CreateCollectionReq.Function rerank = CreateCollectionReq.Function.builder()
.name("weight")
.functionType(FunctionType.RERANK)
.param("reranker", "weighted")
.param("weights", "[0.1, 0.9]")
.param("norm_score", "true")
.build();
import { FunctionType } from '@zilliz/milvus2-sdk-node';
const rerank = {
name: "weight",
input_field_names: [],
function_type: FunctionType.RERANK,
params: {
reranker: "weighted",
weights: [0.1, 0.9],
norm_score: true
}
};
// Go
# Restful
パラメータ | 必須? | 説明 | 値/例 |
|---|---|---|---|
| はい | この関数の一意の識別子 |
|
| はい | 関数を適用するベクトルフィールドのリスト(重み付きランカーでは空のリストでなければなりません) | [] |
| はい | 呼び出す関数のタイプ。再ランク付け戦略を指定するには |
|
| はい | 使用する再ランク付け方法を指定します。 重み付きランカーを使用するには |
|
| はい | 各検索パスに対応する重みの配列。値 ∈ [0,1]。 詳細については 重み付きランカーの仕組み を参照してください。 |
|
| いいえ | 重み付けの前に生のスコア(arctan使用)を正規化するかどうか。 詳細については 重み付きランカーの仕組み を参照してください。 |
|
ハイブリッド検索への適用
重み付きランカーは、複数のベクトルフィールドを組み合わせるハイブリッド検索操作のために特別に設計されています。ハイブリッド検索を実行する際には、各検索パスの重みを指定する必要があります:
- Python
- Java
- NodeJS
- Go
- cURL
from pymilvus import MilvusClient, AnnSearchRequest
# Milvusサーバーに接続
milvus_client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
# コレクションのセットアップがあると仮定
# テキストベクトル検索リクエストを定義
text_search = AnnSearchRequest(
data=["modern dining table"],
anns_field="text_vector",
param={},
limit=10
)
# 画像ベクトル検索リクエストを定義
image_search = AnnSearchRequest(
data=[image_embedding], # 画像埋め込みベクトル
anns_field="image_vector",
param={},
limit=10
)
# 重み付きランカーを製品ハイブリッド検索に適用
# テキスト検索の重みは0.8、画像検索の重みは0.3
hybrid_results = milvus_client.hybrid_search(
collection_name,
[text_search, image_search], # 複数の検索リクエスト
ranker=rerank, # 重み付きランカーを適用
limit=10,
output_fields=["product_name", "price", "category"]
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.AnnSearchReq;
import io.milvus.v2.service.vector.request.HybridSearchReq;
import io.milvus.v2.service.vector.response.SearchResp;
import io.milvus.v2.service.vector.request.data.EmbeddedText;
import io.milvus.v2.service.vector.request.data.FloatVec;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build());
List<AnnSearchReq> searchRequests = new ArrayList<>();
searchRequests.add(AnnSearchReq.builder()
.vectorFieldName("text_vector")
.vectors(Collections.singletonList(new EmbeddedText("\"modern dining table\"")))
.limit(10)
.build());
searchRequests.add(AnnSearchReq.builder()
.vectorFieldName("image_vector")
.vectors(Collections.singletonList(new FloatVec(imageEmbedding)))
.limit(10)
.build());
HybridSearchReq hybridSearchReq = HybridSearchReq.builder()
.collectionName(COLLECTION_NAME)
.searchRequests(searchRequests)
.ranker(ranker)
.limit(10)
.outputFields(Arrays.asList("product_name", "price", "category"))
.build();
SearchResp searchResp = client.hybridSearch(hybridSearchReq);
import { MilvusClient, FunctionType } from "@zilliz/milvus2-sdk-node";
const milvusClient = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
const text_search = {
data: ["modern dining table"],
anns_field: "text_vector",
param: {},
limit: 10,
};
const image_search = {
data: [image_embedding],
anns_field: "image_vector",
param: {},
limit: 10,
};
const rerank = {
name: "weight",
input_field_names: [],
function_type: FunctionType.RERANK,
params: {
reranker: "weighted",
weights: [0.1, 0.9],
norm_score: true,
},
};
const search = await milvusClient.search({
collection_name: collection_name,
limit: 10,
data: [text_search, image_search],
rerank: rerank,
output_fields: ["product_name", "price", "category"],
});
// go
# restful
ハイブリッド検索の詳細については、マルチベクトルハイブリッド検索を参照してください。