減衰ランカー概要
従来のベクトル検索では、結果は純粋にベクトル類似度に基づいてランク付けされます—ベクトルが数学的空間でどれほど密接に一致するかに基づいて。しかし、実際のアプリケーションでは、コンテンツの真正の関連性は、意味的類似性だけに依存するとは限りません。
これらの日常的なシナリオを考えてみましょう:
-
3年前の類似した記事より、昨日の記事の方が上位にランクされるニュース検索
-
30分のドライブが必要な場所よりも、5分で行ける場所を優先するレストラン検索
-
検索クエリとの類似性がわずかに低くても、トレンド商品を優先表示するECプラットフォーム
これらのシナリオはすべて共通のニーズを共有しています:ベクトル類似度と時間、距離、人気などの他の数値要因のバランスを取る必要があります。
Zilliz Cloudの減衰ランカーは、数値フィールド値に基づいて検索ランクを調整することでこのニーズに対応します。これにより、ベクトル類似度と「新鮮さ」、「近さ」、または他のデータの数値的特性をバランスさせることができ、より直感的で文脈的に関連性のある検索エクスペリエンスを作成できます。
使用上の注意
-
減衰ランキングはグルーピング検索では使用できません。
-
減衰ランキングに使用されるフィールドは数値(
INT8、INT16、INT32、INT64、FLOAT、またはDOUBLE)でなければなりません。 -
各減衰ランカーは1つの数値フィールドのみを使用できます。
-
時間単位の整合性:時間ベースの減衰ランキングを使用する場合、
origin、scale、およびoffsetパラメータの単位は、コレクションデータで使用される単位と一致する必要があります:-
コレクションがタイムスタンプを秒で保存している場合、すべてのパラメータに秒を使用します
-
コレクションがタイムスタンプをミリ秒で保存している場合、すべてのパラメータにミリ秒を使用します
-
コレクションがタイムスタンプをマイクロ秒で保存している場合、すべてのパラメータにマイクロ秒を使用します
-
仕組み
減衰ランキングは、時間や地理的距離などの数値要因をランキングプロセスに組み込むことで、従来のベクトル検索を強化します。プロセス全体は以下の段階に分かれます:
ステージ1:正規化された類似度スコアの計算
まず、Zilliz Cloudはベクトル類似度スコアを計算し、正規化して一貫した比較を確保します:
-
L2およびJACCARD距離メトリック(値が低いほど類似度が高い)の場合:
normalized_score = 1.0 - (2 × arctan(score))/πこれにより、距離が0〜1の間の類似度スコアに変換され、値が高いほど優れています。
-
IP、COSINE、およびBM25メトリック(値が高いほどマッチ度が高い)の場合:スコアは正規化せずに直接使用されます。
ステージ2:減衰スコアの計算
次に、Zilliz Cloudは選択した減衰ランカーを使用して、数値フィールド値(タイムスタンプや距離など)に基づいた減衰スコアを計算します:
-
各減衰ランカーは、生の数値を0〜1の間の正規化された関連性スコアに変換します
-
減衰スコアは、理想的な点からの「距離」に基づいてアイテムの関連性を表します
特定の計算式は減衰ランカーのタイプによって異なります。減衰スコアの計算方法の詳細については、ガウス減衰、指数減衰、線形減衰の専用ページを参照してください。
ステージ3:最終スコアの計算
最後に、Zilliz Cloudは正規化された類似度スコアと減衰スコアを組み合わせて、最終的なランク付けスコアを生成します:
final_score = normalized_similarity_score × decay_score
ハイブリッド検索(複数のベクトルフィールドを組み合わせる)の場合、Zilliz Cloudは検索要求の中で最も高い正規化スコアを採用します:
final_score = max([normalized_score₁, normalized_score₂, ..., normalized_scoreₙ]) × decay_score
例えば、研究論文がベクトル類似度で0.82、BM25ベースのテキスト検索で0.91のスコアを獲得したハイブリッド検索では、Zilliz Cloudは減衰係数を適用する前に0.91をベース類似度スコアとして使用します。
実際の減衰ランキング
実際のシナリオで減衰ランキングを見てみましょう—時間ベースの減衰を使用した**「AI研究論文」**の検索:
この例では、減衰スコアは時間の経過とともに関連性がどのように低下するかを反映しています—新しい論文は1.0に近いスコアを受け取り、古い論文は低いスコアを受け取ります。これらの値は特定の減衰ランカーを使用して計算されます。詳細については、適切な減衰ランカーを選択するを参照してください。
論文 | ベクトル類似度 | 正規化類似度スコア | 公開日 | 減衰スコア | 最終スコア | 最終ランク |
|---|---|---|---|---|---|---|
論文A | 高 | 0.85 ( | 2週間前 | 0.80 | 0.68 | 2 |
論文B | 非常に高 | 0.92 ( | 6か月前 | 0.45 | 0.41 | 3 |
論文C | 中 | 0.75 ( | 1日前 | 0.98 | 0.74 | 1 |
論文D | 中高 | 0.76 ( | 3週間前 | 0.70 | 0.53 | 4 |
減衰再ランク付けがない場合、論文Bは純粋なベクトル類似度(0.92)に基づいて最上位にランクされます。しかし、減衰再ランク付けを適用すると:
-
論文Cは中程度の類似度でも非常に新しく(昨日公開)なため、1位にジャンプします
-
非常に良い類似度を持つにもかかわらず、論文Bは比較的古いため3位に下がります
-
論文DはL2距離(値が低い方が良い)を使用しており、減衰を適用する前にスコアが1.2から0.76に正規化されます
適切な減衰ランカーの選択
Zilliz Cloudは、gauss、exp、linearという異なる減衰ランカーを提供しており、それぞれ特定のユースケース用に設計されています:
減衰ランカー | 特徴 | 理想的な使用例 | シナリオ例 |
|---|---|---|---|
ガウス ( | 自然に感じられる、ある程度まで続く徐々の下降 |
| レストラン検索では、3km離れた品質の高い店舗も発見可能ですが、近くの選択肢よりも下位にランクされます |
指数 ( | 最初は急速に減少しますが、長い尾を引きます |
| ニュースアプリでは、昨日のストーリーが1週間前のコンテンツよりはるかに高いランクになりますが、非常に関連性の高い古い記事も表示される場合があります |
線形 ( | 一貫した予測可能な下降で、明確なカットオフがあります |
| イベント検索では、2週間先の将来のウィンドウを超えるイベントは全く表示されません |
各減衰ランカーがどのようにスコアを計算し、具体的な下降パターンについての詳細は、専用のドキュメントを参照してください:
実装例
減衰ランカーは、Zilliz Cloudの標準ベクトル検索とハイブリッド検索の両方に適用できます。以下は、この機能を実装するための主要なコードスニペットです。
減衰関数を使用する前に、減衰計算に使用される適切な数値フィールド(タイムスタンプ、距離など)を持つコレクションを作成する必要があります。コレクション設定、スキーマ定義、およびデータ挿入を含む完全な作業例については、チュートリアル:Milvusでの時間ベースのランク付けの実装を参照してください。
減衰ランカーの作成
減衰ランキングを実装するには、まず適切な設定を持つFunctionオブジェクトを定義します:
- Python
- Java
- NodeJS
- Go
- cURL
from pymilvus import Function, FunctionType
# タイムスタンプベースの減衰用の減衰関数を作成します
# 注:すべての時間パラメータは、コレクションデータと単位を一致させる必要があります
decay_ranker = Function(
name="time_decay", # 関数識別子
input_field_names=["timestamp"], # 減衰に使用する数値フィールド
function_type=FunctionType.RERANK, # 減衰ランカーの場合はRERANKに設定する必要があります
params={
"reranker": "decay", # 減衰再ランカーを指定します。"decay"にする必要があります
"function": "gauss", # 減衰関数タイプ:"gauss"、"exp"、または"linear"を選択します
"origin": int(datetime.datetime(2025, 1, 15).timestamp()), # 基準点(秒)
"scale": 7 * 24 * 60 * 60, # 7日間(秒)のスケール(コレクションデータ単位と一致させる必要があります)
"offset": 24 * 60 * 60, # 1日間の減衰なしゾーン(コレクションデータ単位と一致させる必要があります)
"decay": 0.5 # 一定距離での半分のスコア
}
)
import io.milvus.v2.service.vector.request.ranker.DecayRanker;
import java.time.ZoneId;
import java.time.ZonedDateTime;
ZonedDateTime zdt = ZonedDateTime.of(2025, 1, 25, 0, 0, 0, 0, ZoneId.systemDefault());
DecayRanker ranker = DecayRanker.builder()
.name("time_decay")
.inputFieldNames(Collections.singletonList("timestamp"))
.function("gauss")
.origin(zdt.toInstant().toEpochMilli())
.scale(7 * 24 * 60 * 60)
.offset(24 * 60 * 60)
.decay(0.5)
.build();
import {FunctionType } from "@zilliz/milvus2-sdk-node";
const decayRanker = {
name: "time_decay",
input_field_names: ["timestamp"],
function_type: FunctionType.RERANK,
params: {
reranker: "decay",
function: "gauss",
origin: new Date(2025, 1, 15).getTime(),
scale: 7 * 24 * 60 * 60,
offset: 24 * 60 * 60,
decay: 0.5,
},
};
// go
# restful
パラメータ | 必須? | 説明 | 値/例 |
|---|---|---|---|
| はい | 検索実行時に使用される関数の識別子。あなたのユースケースに関連する記述的な名前を選択してください。 |
|
| はい | 減衰スコア計算のための数値フィールド。どのデータ属性が減衰計算に使用されるかを決定します(例:時間ベースの減衰のためのタイムスタンプ、位置ベースの減衰のための座標)。関連する数値値を含むコレクション内のフィールドである必要があります。INT8/16/32/64、FLOAT、DOUBLEをサポートします。 |
|
| はい | 作成される関数のタイプを指定します。すべての減衰ランカーでは |
|
| はい | 使用する再ランク付け方法を指定します。減衰ランキング機能を有効にするには |
|
| はい | 適用する数学的減衰ランカーを指定します。関連性の下降曲線の形状を決定します。適切な減衰ランカーの選択のセクションを参照して、適切な関数を選択してください。 |
|
| はい | 減衰スコアが計算される基準点。この値にあるアイテムは最大関連性スコアを受け取ります。時間ベースの減衰では、時間単位がコレクションデータと一致する必要があります。 |
|
| はい | 関連性が |
|
| いいえ |
|
|
| いいえ |
|
|
標準ベクトル検索への適用
減衰ランカーを定義したら、検索操作中にrankerパラメータに渡すことで適用できます:
- Python
- Java
- NodeJS
- Go
- cURL
# 標準ベクトル検索で減衰関数を使用
results = milvus_client.search(
collection_name,
data=[your_query_vector], # クエリーベクトルに置き換えてください
anns_field="vector_field",
limit=10,
output_fields=["document", "timestamp"], # 出力に減衰フィールドを含めて値を確認
ranker=decay_ranker, # ここに減衰ランカーを適用
consistency_level="Strong"
)
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.response.SearchResp;
import io.milvus.v2.service.vector.request.data.EmbeddedText;
SearchReq searchReq = SearchReq.builder()
.collectionName(COLLECTION_NAME)
.data(Collections.singletonList(new EmbeddedText("search query")))
.annsField("vector_field")
.limit(10)
.outputFields(Arrays.asList("document", "timestamp"))
.functionScore(FunctionScore.builder()
.addFunction(ranker)
.build())
.build();
SearchResp searchResp = client.search(searchReq);
const result = await milvusClient.search({
collection_name: "collection_name",
data: [your_query_vector], // クエリーベクトルに置き換えてください
anns_field: "dense",
limit: 10,
output_fields: ["document", "timestamp"],
rerank: ranker,
consistency_level: "Strong",
});
// go
# restful
ハイブリッド検索への適用
減衰ランカーは、複数のベクトルフィールドを組み合わせたハイブリッド検索操作にも適用できます:
- Python
- Java
- NodeJS
- Go
- cURL
from pymilvus import AnnSearchRequest
# 異なるベクトルフィールドの検索要求を定義
dense_request = AnnSearchRequest(
data=[your_query_vector_1], # クエリーベクトルに置き換えてください
anns_field="dense_vector",
param={},
limit=20
)
sparse_request = AnnSearchRequest(
data=[your_query_vector_2], # クエリーベクトルに置き換えてください
anns_field="sparse_vector",
param={},
limit=20
)
# 減衰ランカーをハイブリッド検索に適用
hybrid_results = milvus_client.hybrid_search(
collection_name,
[dense_request, sparse_request],
ranker=decay_ranker, # 同じ減衰ランカーはハイブリッド検索でも動作します
limit=10,
output_fields=["document", "timestamp"]
)
import io.milvus.v2.service.vector.request.AnnSearchReq;
import io.milvus.v2.service.vector.request.HybridSearchReq;
import io.milvus.v2.service.vector.request.data.EmbeddedText;
import io.milvus.v2.service.vector.request.data.FloatVec;
List<AnnSearchReq> searchRequests = new ArrayList<>();
searchRequests.add(AnnSearchReq.builder()
.vectorFieldName("dense_vector")
.vectors(Collections.singletonList(new FloatVec(embedding)))
.limit(20)
.build());
searchRequests.add(AnnSearchReq.builder()
.vectorFieldName("sparse_vector")
.vectors(Collections.singletonList(new EmbeddedText("search query")))
.limit(20)
.build());
HybridSearchReq hybridSearchReq = HybridSearchReq.builder()
.collectionName(COLLECTION_NAME)
.searchRequests(searchRequests)
.ranker(ranker)
.limit(10)
.outputFields(Arrays.asList("document", "timestamp"))
.build();
SearchResp searchResp = client.hybridSearch(hybridSearchReq);
const denseRequest = {
data: [your_query_vector_1], // クエリーベクトルに置き換えてください
anns_field: "dense_vector",
param: {},
limit: 20,
};
const sparseRequest = {
data: [your_query_vector_2], // クエリーベクトルに置き換えてください
anns_field: "sparse_vector",
param: {},
limit: 20,
};
const hybridResults = await milvusClient.hybrid_search({
collection_name: "collection_name",
data: [denseRequest, sparseRequest],
ranker: decayRanker,
limit: 10,
output_fields: ["document", "timestamp"],
});
// go
# restful
ハイブリッド検索では、Zilliz Cloudはまずすべてのベクトルフィールドから最も高い類似度スコアを見つけ、そのスコアに減衰係数を適用します。