指數衰減Compatible with Milvus 2.6.x

指數遞減在您的搜尋結果中創造了一個陡峭的初始下降,接著是一個長尾。就像突發性新聞週期一樣,一開始相關性迅速降低,但隨著時間的推移,有些新聞的重要性仍會保留,指數衰減對超出您理想範圍的項目施加急劇的懲罰,同時仍保持較遠的項目可以被發現。當您想要優先處理近似性或近期性,但又不想完全剔除較遠的選項時,這種方法是最理想的選擇。

與其他衰減函數不同:

  • 高斯衰減創造了更漸進的鐘形衰減

  • 線性衰減以固定速率遞減,直到完全為零

指數遞減獨特地將懲罰 「前置」,提早應用大部分的相關性減量,同時維持最小但非零的長尾相關性。

何時使用指數遞減

指數遞減對以下情況特別有效

使用個案

範例

為什麼指數效果好

新聞饋送

即時新聞入口網站

快速降低舊新聞的相關性,同時仍顯示數天前的重要新聞

社交媒體時間線

活動訊息、狀態更新

強調新鮮內容,但允許病毒性的舊內容浮現

通知系統

警示優先順序

為最近的警示創造緊迫感,同時維持重要警示的能見度

快速銷售

限時優惠

隨著截止日期的臨近快速降低能見度

在下列情況下選擇指數遞減

  • 使用者期望最近或鄰近的項目強烈主導結果

  • 較舊或較遠的項目如果特別相關,仍然應該可以被發現

  • 相關性下降應該是前置的(開始時較陡峭,之後則較漸進)

陡峭下降原則

指數衰減創造了一條曲線,一開始下降得很快,然後逐漸變平,形成一條接近但永遠不會到零的長尾。這種數學模式經常出現在自然現象中,如放射性衰減、人口下降、資訊隨時間的相關性等。

所有時間參數 (origin,offset,scale) 必須使用與收集資料相同的單位。如果您的資料集以不同單位 (毫秒、微秒) 儲存時間戳記,請相應調整所有參數。

Exp Decay 指數衰減

上圖顯示指數衰減如何影響數位新聞平台的新聞文章排名:

  • origin (當前時間):當前時刻,相關性達到最大值 (1.0)。

  • offset (3 小時):突發新聞窗口」- 所有在過去 3 小時內發表的新聞都維持完整的相關性評分 (1.0),確保最近的新聞不會因為微小的時間差異而受到不必要的懲罰。

  • decay (0.5):尺度距離的分數 - 此參數可控制分數隨時間遞減的程度。

  • scale (24 小時):相關性下降至衰減數值的時間段 - 24 小時前的新聞,其相關性評分會減半 (0.5)。

從曲線可以看出,超過 24 小時的新聞文章相關性持續下降,但永遠不會達到零。即使是幾天前的新聞也會保留一些最低限度的相關性,讓重要但較舊的新聞仍會出現在您的 feed 中 (儘管排名較低)。

這種行為模仿了新聞相關性的典型運作方式--非常新的新聞強烈地佔據了優勢,但重要的舊新聞如果與使用者的興趣格外相關,仍然可以突圍而出。

計算公式

計算指數衰減得分的數學公式如下:

S(doc)=exp(λmax(0,fieldvaluedocoriginoffset))S(doc) = \exp\left( \lambda \cdot \max\left(0, \left|fieldvalue_{doc} - origin\right| - offset \right) \right)

其中:

λ=ln(decay)scale\lambda = \frac{\ln(decay)}{scale}

以簡單的語言說明:

  1. 計算欄位值離原點的距離:∣fieldvaluedoc-origin∣|fieldvalue_{doc} - origin| ∣。

  2. 減去偏移量 (如果有的話),但永遠不要低於 0:max(0,distance-offset)\max(0, distance - offset)

  3. 乘以 λ\lambda,這是根據您的比例和衰減參數計算出來的。

  4. 取指數,它會給您介於 0 和 1 之間的值:exp(λ⋅value)\exp(\lambda \cdot value)

計算將您的比例和衰減參數轉換為指數函數的速率參數。較負的 λ\lambda會產生較陡的初始下降。

使用指數衰減

在 Milvus 中,指數遞減可應用於標準向量搜尋和混合搜尋運算。以下是實現此功能的關鍵程式碼片段。

在使用遞減函數之前,您必須先建立一個具有適當數值欄位 (如時間戳記、距離等) 的集合,這些欄位將用於遞減計算。如需完整的工作範例,包括集合設定、模式定義和資料插入,請參閱Decay Ranker Tutorial

建立衰減排名器

在您的資料集中設定了數值欄位 (在本範例中為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

免費嘗試托管的 Milvus

Zilliz Cloud 無縫接入,由 Milvus 提供動力,速度提升 10 倍。

開始使用
反饋

這個頁面有幫助嗎?