指数関数的減衰Compatible with Milvus 2.6.x
指数関数的減衰は、検索結果にロングテールをもたらす。ニュース速報のように、最初は関連性が急速に低下するが、時間が経つにつれて重要性を保つストーリーもあるように、指数関数的減衰は、理想的な範囲を超えたアイテムに急激なペナルティを適用する一方で、遠くのアイテムは発見可能なままにしておく。このアプローチは、近接性や最新性を優先したいが、より遠い選択肢を完全に排除したくない場合に理想的です。
他の減衰関数とは異なります:
ガウス減衰は、より緩やかな、ベル型の減少を作成します。
線形減衰は、ちょうどゼロになるまで一定の割合で減少します。
指数関数的減衰は、ペナルティをユニークに「フロントロード」し、レリバンスの減少の大部分を早期に適用する一方で、レリバンスは最小だがゼロではないロングテールを維持します。
指数減衰を使用するタイミング
指数減衰は以下のような場合に特に効果的です:
使用例 |
使用例 |
指数関数が有効な理由 |
|---|---|---|
ニュースフィード |
ニュースポータル |
数日前の重要なニュースを表示しながら、古いニュースの関連性を素早く下げることができます。 |
ソーシャルメディアのタイムライン |
アクティビティフィード、ステータス更新 |
新鮮なコンテンツに重点を置くが、バイラルな古いコンテンツも表示可能 |
通知システム |
アラートの優先順位付け |
重要なアラートの可視性を維持しながら、最近のアラートに緊急性を持たせる。 |
フラッシュセール |
期間限定オファー |
期限が近づくにつれ、視認性を急速に低下させる |
次のような場合に指数関数的減衰を選択します:
ユーザーは、ごく最近または近くにあるアイテムが検索結果を強く支配することを期待しています。
古いアイテムや遠いアイテムでも、特別に関連性が高ければ発見できるはずです。
関連性の落ち込みは前倒しで行う(最初は急で、後で緩やかになる)
シャープドロップオフの原則
指数関数的減衰は、最初は急激に低下し、その後徐々に平坦になり、ゼロに近づくが決して到達しない長い尾を引く曲線を作る。この数学的パターンは、放射性物質の減衰、人口の減少、時間の経過に伴う情報の関連性などの自然現象に頻繁に現れる。
すべての時間パラメータ(origin,offset,scale)は、コレクションデータと同じ単位を使用する必要があります。コレクションが異なる単位(ミリ秒、マイクロ秒)でタイムスタンプを保存している場合は、すべてのパラメータをそれに合わせて調整してください。
指数減衰
上のグラフは、指数関数的減衰がデジタルニュースプラットフォームのニュース記事のランキングにどのように影響するかを示しています:
origin(現在時刻):現在時刻):関連性が最大(1.0)である現時点。offset(3時間):過去3時間以内に発表された記事はすべて関連性スコアが満点(1.0)を維持し、ごく最近のニュースがわずかな時間差で不必要なペナルティを受けることはない。decay(0.5):このパラメータは、時間とともにスコアがどの程度劇的に減少するかをコントロールします。scale(24時間):関連性が減衰値まで下がる時間-ちょうど24時間前のニュース記事は関連性スコアが半分(0.5)になる。
曲線からわかるように、24時間以上前のニュース記事は関連性が下がり続けますが、ゼロになることはありません。数日前の記事でも最低限の関連性は保たれるため、重要だが古いニュースも(ランクは下がるものの)フィードに表示される。
この動作は、ニュースの関連性が一般的にどのように働くかを模倣しています。非常に最近のストーリーが強く支配的ですが、ユーザーの関心に特別に関連している場合、重要な古いストーリーがまだ突破できる可能性があります。
計算式
指数減衰スコアの計算式は以下の通りです:
となります:
これをわかりやすく説明すると
フィールド値が原点からどれだけ離れているかを計算: .
オフセット(もしあれば)を引くが、ゼロ以下にはならない: .
スケールと減衰パラメータから計算されるλ乗算する。
λ値 。
計算は、スケールと減衰パラメータを指数関数のレートパラメータに変換する。より負のlambda、より急な初期降下を作成する。
指数減衰の使用
指数関数的減衰はMilvusの標準的なベクトル探索とハイブリッド探索の両方に適用することができます。以下にこの機能を実装するための主なコードスニペットを示します。
減衰関数を使用する前に、まず減衰計算に使用する適切な数値フィールド(タイムスタンプ、距離など)を持つコレクションを作成する必要があります。コレクションのセットアップ、スキーマ定義、データ挿入を含む完全な作業例については、ディケイランカーチュートリアルを参照してください。
ディケイランカーの作成
数値フィールド(この例では、publish_time )でコレクションをセットアップした後、指数ディケイランカを作成します:
時間単位の一貫性:時間ベースのディケイを使用する場合、origin 、scale 、offset パラメータがコレクションデータと同じ時間単位を使用することを確認します。コレクションがタイムスタンプを秒単位で保存する場合、すべてのパラメータに秒を使用します。ミリ秒を使用する場合は、すべてのパラメータにミリ秒を使用する。
from pymilvus import Function, FunctionType
import datetime
# Create an exponential decay ranker for news recency
# Note: All time parameters must use the same unit as your collection data
ranker = Function(
name="news_recency", # Function identifier
input_field_names=["publish_time"], # Numeric field to use
function_type=FunctionType.RERANK, # Function type. Must be RERANK
params={
"reranker": "decay", # Specify decay reranker
"function": "exp", # Choose exponential decay
"origin": int(datetime.datetime.now().timestamp()), # Current time (seconds, matching collection data)
"offset": 3 * 60 * 60, # 3 hour breaking news window (seconds)
"decay": 0.5, # Half score at scale distance
"scale": 24 * 60 * 60 # 24 hours (in seconds, matching collection data)
}
)
import io.milvus.v2.service.vector.request.ranker.DecayRanker;
DecayRanker ranker = DecayRanker.builder()
.name("news_recency")
.inputFieldNames(Collections.singletonList("publish_time"))
.function("exp")
.origin(System.currentTimeMillis())
.offset(3 * 60 * 60)
.decay(0.5)
.scale(24 * 60 * 60)
.build();
import { FunctionType } from "@zilliz/milvus2-sdk-node";
const ranker = {
name: "news_recency",
input_field_names: ["publish_time"],
type: FunctionType.RERANK,
params: {
reranker: "decay",
function: "exp",
origin: new Date(2025, 1, 15).getTime(),
offset: 3 * 60 * 60,
decay: 0.5,
scale: 24 * 60 * 60,
},
};
// go
# restful
標準ベクトル検索への適用
減衰ランカーを定義した後、ranker パラメータに渡すことで、検索操作中に適用できます:
# Apply decay ranker to vector search
result = milvus_client.search(
collection_name,
data=[your_query_vector], # Replace with your query vector
anns_field="dense", # Vector field to search
limit=10, # Number of results
output_fields=["title", "publish_time"], # Fields to return
ranker=ranker, # Apply the decay ranker
consistency_level="Strong"
)
import io.milvus.v2.common.ConsistencyLevel;
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("market analysis")))
.annsField("vector_field")
.limit(10)
.outputFields(Arrays.asList("title", "publish_time"))
.functionScore(FunctionScore.builder()
.addFunction(ranker)
.build())
.consistencyLevel(ConsistencyLevel.STRONG)
.build();
SearchResp searchResp = client.search(searchReq);
import { FunctionType MilvusClient } from "@zilliz/milvus2-sdk-node";
const milvusClient = new MilvusClient("http://localhost:19530");
const result = await milvusClient.search({
collection_name: "collection_name",
data: [your_query_vector], // Replace with your query vector
anns_field: "dense",
limit: 10,
output_fields: ["title", "publish_time"],
rerank: ranker,
consistency_level: "Strong",
});
// go
# restful