メインコンテンツまでスキップ
バージョン: User Guides (Cloud)

Decay Ranker の概要

従来のベクトル検索では、結果は純粋にベクトル類似度(数学的空間におけるベクトルの近さ)に基づいてランキングされます。しかし実際のアプリケーションでは、コンテンツの真の関連性は意味的類似度だけではなく、他の要素にも依存することがよくあります。

以下のような日常的なシナリオを考えてみましょう。

  • 昨日のニュース記事が、3年前の類似記事よりも上位に表示されるニュース検索
  • 30分のドライブが必要な店舗よりも、徒歩5分の飲食店を優先するレストラン検索
  • 検索クエリとの類似度がやや低くても、トレンド中の商品を優先表示するECプラットフォーム

これらのシナリオには共通点があります。それは、ベクトル類似度と時間・距離・人気度などの数値的要素をバランスよく考慮する必要があることです。

Zilliz Cloud の Decay ranker は、このニーズに対応するために、数値フィールドの値に基づいて検索結果のランキングを調整します。「新鮮さ(freshness)」や「近接性(nearness)」など、データに含まれる数値的特性とベクトル類似度をバランスさせることで、より直感的で文脈に即した検索体験を実現します。

使用上の注意

  • Decay ranking はグループ化検索とは併用できません。

  • Decay ranking に使用するフィールドは数値型(INT8INT16INT32INT64FLOAT、または DOUBLE)である必要があります。

  • 各 Decay ranker は1つの数値フィールドのみを使用できます。

  • 時間単位の一貫性:時間ベースの decay ranking を使用する場合、originscale、および offset パラメータの単位は、コレクション内のデータで使用されている単位と一致させる必要があります。

    • コレクションがタイムスタンプを単位で保存している場合、すべてのパラメータも秒単位で指定します

    • コレクションがタイムスタンプをミリ秒単位で保存している場合、すべてのパラメータもミリ秒単位で指定します

    • コレクションがタイムスタンプをマイクロ秒単位で保存している場合、すべてのパラメータもマイクロ秒単位で指定します

動作の仕組み

Decay ranking は、時間や地理的距離といった数値的要素をランキング処理に組み込むことで、従来のベクトル検索を強化します。このプロセスは以下のステージで構成されています。

ステージ 1: 正規化された類似度スコアの計算

まず、Zilliz Cloud はベクトル類似度スコアを計算し、一貫した比較が行えるように正規化します。

  • L2 および JACCARD 距離メトリクスの場合(値が小さいほど類似度が高い):

    normalized_score = 1.0 - (2 × arctan(score))/π

    これにより、距離は0〜1の類似度スコアに変換され、値が高いほど良い結果となります。

  • IPCOSINEBM25 メトリクス(スコアが高いほど一致度が高いことを示す場合): スコアは正規化せず、そのまま使用されます。

ステージ 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をベースの類似度スコアとして使用します。

Decay ranking in action

実用的なシナリオで減衰ランキングを見てみましょう。時間ベースの減衰を使用して 「AI研究論文」 を検索します:

📘Notes

この例では、減衰スコアは時間とともに関連性がどのように低下するかを反映しています。新しい論文は1.0に近いスコアを受け取り、古い論文はより低いスコアを受け取ります。これらの値は、特定の減衰ランカーを使用して計算されます。詳細については、適切な減衰ランカーの選択を参照してください。

論文

ベクトル類似度

正規化類似度スコア

公開日

減衰スコア

最終スコア

最終ランク

論文 A

0.85 (COSINE)

2週間前

0.80

0.68

2

論文 B

非常に高い

0.92 (COSINE)

6ヶ月前

0.45

0.41

3

論文 C

0.75 (COSINE)

1日前

0.98

0.74

1

論文 D

中〜高

0.76 (COSINE)

3週間前

0.70

0.53

4

減衰再ランキングがない場合、論文 B は純粋なベクトル類似度(0.92)に基づいて最も高くランク付けされます。しかし、減衰再ランキングが適用されると:

  • 論文 C は類似度が中程度にもかかわらず、非常に新しい(昨日公開された)ため、位置 #1 にジャンプします

  • 論文 B は類似度が優れているにもかかわらず、比較的古いため、位置 #3 に低下します

  • 論文 D は L2 距離(低い方が良い)を使用するため、減衰を適用する前にスコアが 1.2 から 0.76 に正規化されます

適切な減衰ランカーの選択

Zilliz Cloud は、特定のユースケース向けに設計された gaussexplinear という異なる減衰ランカーを提供しています:

減衰ランカー

特性

理想的なユースケース

シナリオ例

ガウス (gauss)

自然な感じの緩やかな減少で、適度に延長する

  • バランスの取れた結果が必要な一般検索

  • ユーザーが距離を直感的に感じるアプリケーション

  • 適度な距離が結果を深刻にペナルティすべきでない場合

レストラン検索では、3 km離れた質の高い店舗も発見可能ですが、近隣の選択肢よりは低くランク付けされます

指数 (exp)

最初は急速に減少するが、長い裾を維持する

  • 新しさが重要なニュースフィード

  • 新鮮なコンテンツが支配すべきソーシャルメディア

  • 近接性が強く好まれるが、例外的な遠方のアイテムも可視性を維持すべき場合

ニュースアプリでは、昨日の記事が1週間前のコンテンツよりはるかに高くランク付けされますが、高度に関連性の高い古い記事も依然として表示されることがあります

線形 (linear)

明確なカットオフを持つ一貫した、予測可能な減少

  • 自然な境界を持つアプリケーション

  • 距離制限のあるサービス

  • 有効期限または明確な閾値を持つコンテンツ

イベントファインダーでは、2週間以上先の未来のイベントはまったく表示されません

各減衰ランカーがスコアを計算する方法と特定の減少パターンについての詳細情報は、専用のドキュメントを参照してください:

実装例

減衰ランカーは、Zilliz Cloud の標準ベクトル検索とハイブリッド検索の両方に適用できます。この機能を実装するための主要なコードスニペットを以下に示します。

📘Notes

減衰関数を使用する前に、まず減衰計算に使用される適切な数値フィールド(タイムスタンプ、距離など)を持つコレクションを作成する必要があります。コレクションのセットアップ、スキーマ定義、データ挿入を含む完全な動作例については、チュートリアル: Milvus で時間ベースのランキングを実装するを参照してください。

減衰ランカーの作成

減衰ランキングを実装するには、まず適切な設定で Function オブジェクトを定義します:

from pymilvus import Function, FunctionType

# Create a decay function for timestamp-based decay
# Note: All time parameters must use the same unit as your collection data
rerank = Function(
name="time_decay", # Function identifier
input_field_names=["timestamp"], # Numeric field to use for decay
function_type=FunctionType.RERANK, # Must be set to RERANK for decay rankers
params={
"reranker": "decay", # Specify decay reranker. Must be "decay"
"function": "gauss", # Choose decay function type: "gauss", "exp", or "linear"
"origin": int(datetime.datetime(2025, 1, 15).timestamp()), # Reference point (seconds)
"scale": 7 * 24 * 60 * 60, # 7 days in seconds (must match collection data unit)
"offset": 24 * 60 * 60, # 1 day no-decay zone (must match collection data unit)
"decay": 0.5 # Half score at scale distance
}
)

パラメータ

必須?

説明

値/例

name

はい

検索実行時に使用される関数の識別子です。ユースケースに関連したわかりやすい名前を指定してください。

"time_decay"

input_field_names

はい

減衰スコア計算に使用する数値フィールドです。減衰計算に使用するデータ属性(例:時間ベースの減衰にはタイムスタンプ、位置ベースの減衰には座標)を決定します。

コレクション内に存在し、関連する数値を含むフィールドである必要があります。INT8/16/32/64、FLOAT、DOUBLE をサポートしています。

["timestamp"]

function_type

はい

作成する関数のタイプを指定します。

すべての減衰ランカーに対して RERANK に設定する必要があります。

FunctionType.RERANK

params.reranker

はい

使用するリランキング手法を指定します。

減衰ランキング機能を有効にするには、"decay" に設定する必要があります。

"decay"

params.function

はい

適用する数学的減衰ランカーを指定します。関連性の低下カーブの形状を決定します。

適切な関数の選択については、適切な減衰ランカーの選択セクションをご参照ください。

"gauss""exp"、または "linear"

params.origin

はい

減衰スコアの計算基準となる参照点です。この値を持つアイテムは最大の関連性スコアを受け取ります。

時間ベースの減衰の場合、時間単位はコレクションのデータと一致している必要があります。

  • タイムスタンプの場合:現在時刻(例:int(time.time())

  • ジオロケーションの場合:ユーザーの現在地座標

params.scale

はい

decay 値となる距離または時間です。関連性がどの程度速く低下するかを制御します。

時間ベースの減衰の場合、時間単位はコレクションのデータと一致している必要があります。

大きな値は関連性の緩やかな低下を、小さな値は急激な低下をもたらします。

  • 時間の場合:秒単位の期間(例:7 * 24 * 60 * 60 で7日間)

  • 距離の場合:メートル(例:5000 で5km)

params.offset

いいえ

origin の周囲に「減衰なしゾーン」を作成し、その範囲内のアイテムは完全なスコア(減衰スコア = 1.0)を維持します。

時間ベースの減衰の場合、時間単位はコレクションのデータと一致している必要があります。

origin からこの範囲内にあるアイテムは最大の関連性を維持します。

  • 時間の場合:秒単位の期間(例:24 * 60 * 60 で1日)

  • 距離の場合:メートル(例:500 で500m)

params.decay

いいえ

scale 距離におけるスコア値で、カーブの急峻さを制御します。低い値は急激な低下カーブを、高い値は緩やかな低下カーブを生成します。

0 から 1 の間である必要があります。

0.5(デフォルト)

減衰ランカーを定義した後、検索操作時に ranker パラメータに渡すことで適用できます:

# Use the decay function in standard vector search
results = milvus_client.search(
collection_name,
data=[your_query_vector], # Replace with your query vector
anns_field="vector_field",
limit=10,
output_fields=["document", "timestamp"], # Include the decay field in outputs to see values
ranker=rerank, # Apply the decay ranker here
consistency_level="Strong"
)