Экспоненциальный распад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 часов продолжает снижаться, но так и не достигает нуля. Даже новости, опубликованные несколько дней назад, сохраняют минимальную релевантность, что позволяет важным, но старым новостям по-прежнему появляться в вашей ленте (хотя и с более низким рейтингом).
Такое поведение имитирует то, как обычно работает релевантность новостей - очень свежие истории сильно доминируют, но значимые старые истории все же могут пробиться вперед, если они исключительно релевантны интересам пользователя.
Формула
Математическая формула для расчета показателя экспоненциального распада выглядит следующим образом:
Где:
Если говорить простым языком:
Вычислите, насколько далеко значение поля находится от начала:
Вычтите смещение (если оно есть), но никогда не опускайтесь ниже нуля: \max .
Умножьте на , которая рассчитывается из параметров масштаба и распада.
Возьмите экспоненту, которая дает значение от 0 до 1: \exp .
Расчет преобразует ваши параметры масштаба и распада в параметр скорости для экспоненциальной функции. Более отрицательное значение создает более крутой начальный спад.
Использование экспоненциального распада
Экспоненциальный спад можно применять как к стандартному векторному поиску, так и к гибридным операциям поиска в 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