Decaimento exponencialCompatible with Milvus 2.6.x

O declínio exponencial cria uma queda inicial acentuada seguida de uma cauda longa nos resultados da pesquisa. À semelhança de um ciclo de notícias de última hora em que a relevância diminui rapidamente no início, mas algumas histórias mantêm a importância ao longo do tempo, o declínio exponencial aplica uma penalização acentuada aos itens que se encontram imediatamente para além do seu intervalo ideal, mantendo os itens distantes detectáveis. Esta abordagem é ideal quando se pretende dar prioridade à proximidade ou à atualidade, mas não se pretende eliminar completamente as opções mais distantes.

Ao contrário de outras funções de decaimento:

  • O decaimento gaussiano cria um declínio mais gradual, em forma de sino

  • O decaimento linear diminui a uma taxa constante até atingir exatamente zero

O decaimento exponencial "antecipa" a penalização, aplicando a maior parte da redução de relevância numa fase inicial, mantendo uma cauda longa de relevância mínima mas não nula.

Quando utilizar o decaimento exponencial

O decaimento exponencial é particularmente eficaz para:

Caso de utilização

Exemplo

Porque é que o exponencial funciona bem

Feeds de notícias

Portais de notícias de última hora

Reduz rapidamente a relevância de notícias mais antigas, mas continua a mostrar histórias importantes de há dias atrás

Linhas de tempo das redes sociais

Feeds de actividades, actualizações de estado

Dá ênfase ao conteúdo recente, mas permite que o conteúdo viral mais antigo apareça

Sistemas de notificação

Priorização de alertas

Cria urgência para alertas recentes, mantendo a visibilidade dos alertas importantes

Vendas rápidas

Ofertas por tempo limitado

Diminui rapidamente a visibilidade à medida que o prazo se aproxima

Escolha o decaimento exponencial quando:

  • Os utilizadores esperam que os itens muito recentes ou próximos dominem fortemente os resultados

  • Os itens mais antigos ou mais distantes ainda devem poder ser descobertos se forem excecionalmente relevantes

  • A descida de relevância deve ser frontal (mais acentuada no início, mais gradual mais tarde)

Princípio da queda acentuada

O decaimento exponencial cria uma curva que cai rapidamente no início e, em seguida, se achata gradualmente numa cauda longa que se aproxima mas nunca chega a zero. Este padrão matemático aparece frequentemente em fenómenos naturais como o decaimento radioativo, o declínio da população e a relevância da informação ao longo do tempo.

Todos os parâmetros de tempo (origin, offset, scale) devem utilizar a mesma unidade que os dados da coleção. Se a sua coleção armazena marcas de tempo numa unidade diferente (milissegundos, microssegundos), ajuste todos os parâmetros em conformidade.

Exp Decay Decaimento exponencial

O gráfico acima mostra como o decaimento exponencial afectaria as classificações dos artigos de notícias numa plataforma de notícias digitais:

  • origin (hora atual): O momento atual, onde a relevância está no seu máximo (1.0).

  • offset (3 horas): A "janela de notícias de última hora" - todas as histórias publicadas nas últimas 3 horas mantêm a pontuação de relevância total (1,0), garantindo que as notícias muito recentes não são penalizadas desnecessariamente por pequenas diferenças de tempo.

  • decay (0.5): A pontuação na distância da escala - este parâmetro controla a forma como as pontuações diminuem drasticamente com o tempo.

  • scale (24 horas): O período de tempo em que a relevância cai para o valor de decaimento - os artigos noticiosos com exatamente 24 horas têm as suas pontuações de relevância reduzidas para metade (0,5).

Como pode ver na curva, os artigos de notícias com mais de 24 horas continuam a diminuir em relevância, mas nunca chegam a zero. Mesmo as histórias de há vários dias mantêm alguma relevância mínima, permitindo que notícias importantes mas mais antigas continuem a aparecer no seu feed (embora com uma classificação inferior).

Este comportamento imita a forma como a relevância das notícias funciona normalmente - os artigos muito recentes dominam fortemente, mas os artigos mais antigos e significativos podem ainda passar se forem excecionalmente relevantes para os interesses do utilizador.

Fórmula

A fórmula matemática para calcular uma pontuação de decaimento exponencial é:

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

Onde:

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

Desdobrando isso em linguagem simples:

  1. Calcule o quão longe o valor do campo está da origem: ∣fieldvaluedoc-origin∣|fieldvalue_{doc} - origin|

  2. Subtrair o desvio (se existir), mas nunca abaixo de zero: max(0,distance-offset)\max (0, distance - offset) .

  3. Multiplique por λ\lambda, que é calculado a partir dos seus parâmetros de escala e de decaimento.

  4. Pegue o expoente, que lhe dá um valor entre 0 e 1: exp(λ⋅value)\exp (\lambda \cdot value) .

O cálculo de λ\lambda converte os seus parâmetros de escala e de decaimento no parâmetro de taxa para a função exponencial. Um λ\lambda mais negativo cria uma queda inicial mais acentuada.

Utilizar o decaimento exponencial

O decaimento exponencial pode ser aplicado tanto à pesquisa vetorial padrão como às operações de pesquisa híbrida em Milvus. Abaixo estão os principais trechos de código para implementar esta funcionalidade.

Antes de utilizar as funções de decaimento, deve primeiro criar uma coleção com campos numéricos apropriados (como carimbos de data/hora, distâncias, etc.) que serão utilizados para cálculos de decaimento. Para obter exemplos de trabalho completos, incluindo a configuração da coleção, a definição do esquema e a inserção de dados, consulte Tutorial do Decay Ranker.

Criar um classificador de decaimento

Depois de a coleção estar configurada com um campo numérico (neste exemplo, publish_time), crie um classificador de decaimento exponencial:

Consistência da unidade de tempo: Ao usar o decaimento baseado em tempo, certifique-se de que os parâmetros origin, scale e offset usem a mesma unidade de tempo que os dados da sua coleção. Se a sua coleção armazena carimbos de data/hora em segundos, utilize segundos para todos os parâmetros. Se ela usar milissegundos, use milissegundos para todos os parâmetros.

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

Depois de definir o seu classificador de decaimento, pode aplicá-lo durante as operações de pesquisa, passando-o para o parâmetro 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