指數衰減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 小時的新聞文章相關性持續下降,但永遠不會達到零。即使是幾天前的新聞也會保留一些最低限度的相關性,讓重要但較舊的新聞仍會出現在您的 feed 中 (儘管排名較低)。
這種行為模仿了新聞相關性的典型運作方式--非常新的新聞強烈地佔據了優勢,但重要的舊新聞如果與使用者的興趣格外相關,仍然可以突圍而出。
計算公式
計算指數衰減得分的數學公式如下:
其中:
以簡單的語言說明:
計算欄位值離原點的距離: ∣。
減去偏移量 (如果有的話),但永遠不要低於 0: 。
乘以,這是根據您的比例和衰減參數計算出來的。
取指數,它會給您介於 0 和 1 之間的值:λ⋅\exp\ value 。
計算將您的比例和衰減參數轉換為指數函數的速率參數。較負的會產生較陡的初始下降。
使用指數衰減
在 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