Esta, para mim, é uma crítica um tanto injusta, é um tópico difícil. Muitos tópicos de #suporte não recebem “olhos suficientes” para qualquer definição de suficiente.
Isso é um experimento, seu desagrado por “hot” como padrão para meta é um ponto de dados. Coletaremos mais.
Quanto ao algoritmo:
Podemos ajustar a gravidade, para que não “puxemos para baixo” os tópicos tão rapidamente quanto agora. Também posso tentar pensar em alguma forma de dar um pequeno impulso às coisas com base na “última resposta”.
No momento, o algoritmo está aqui:
IA Bot explicando hot
AI
sam:
DB.exec(<<~SQL, args)
INSERT INTO topic_hot_scores (
topic_id,
score,
recent_likes,
recent_posters,
created_at,
updated_at
)
SELECT
topics.id,
0.0,
0,
0,
:now,
:now
FROM topics
LEFT OUTER JOIN topic_hot_scores ON topic_hot_scores.topic_id = topics.id
WHERE topic_hot_scores.topic_id IS NULL
AND topics.deleted_at IS NULL
AND topics.archetype <> :private_message
AND topics.created_at <= :now
ORDER BY
CASE WHEN topics.pinned_at IS NOT NULL THEN 0 ELSE 1 END ASC,
topics.bumped_at desc
LIMIT :max
SQL
# update recent counts for batch
DB.exec(<<~SQL, args)
UPDATE topic_hot_scores thsOrig
SET
recent_likes = COALESCE(new_values.likes_count, 0),
recent_posters = COALESCE(new_values.unique_participants, 0),
recent_first_bumped_at = COALESCE(new_values.first_bumped_at, ths.recent_first_bumped_at)
FROM
topic_hot_scores ths
LEFT OUTER JOIN
(
SELECT
t.id AS topic_id,
COUNT(DISTINCT p.user_id) AS unique_participants,
(
SELECT COUNT(distinct pa.user_id)
FROM post_actions pa
JOIN posts p2 ON p2.id = pa.post_id
WHERE p2.topic_id = t.id
AND p2.post_type = :regular
AND p2.deleted_at IS NULL
AND p2.user_deleted = false
AND pa.post_action_type_id = 2 -- action_type for 'like'
AND pa.created_at >= :recent_cutoff
AND pa.deleted_at IS NULL
) AS likes_count,
MIN(p.created_at) AS first_bumped_at
FROM
topics t
JOIN
posts p ON t.id = p.topic_id
WHERE
p.created_at >= :recent_cutoff
AND t.archetype <> 'private_message'
AND t.deleted_at IS NULL
AND p.deleted_at IS NULL
AND p.user_deleted = false
AND t.created_at <= :now
AND t.bumped_at >= :recent_cutoff
AND p.created_at < :now
AND p.created_at >= :recent_cutoff
AND p.post_type = :regular
GROUP BY
t.id
) AS new_values
ON ths.topic_id = new_values.topic_id
WHERE thsOrig.topic_id = ths.topic_id
SQL
# we may end up update 2x batch size, this is ok
# we need to update 1 batch of high scoring topics
# we need to update a second batch of recently bumped topics
sql = <<~SQL
WITH topic_ids AS (
SELECT topic_id FROM (
SELECT th3.topic_id FROM topic_hot_scores th3
JOIN topics t3 on t3.id = th3.topic_id
ORDER BY t3.bumped_at DESC
LIMIT :max
) Y
UNION ALL
SELECT topic_id FROM (
SELECT th2.topic_id FROM topic_hot_scores th2
ORDER BY th2.score DESC, th2.recent_first_bumped_at DESC NULLS LAST
LIMIT :max
) X
)
UPDATE topic_hot_scores ths
SET score = (
CASE WHEN topics.created_at > :recent_cutoff
THEN ths.recent_likes ELSE topics.like_count END
) /
(EXTRACT(EPOCH FROM (:now - topics.created_at)) / 3600 + 2) ^ :gravity
+
CASE WHEN ths.recent_first_bumped_at IS NULL THEN 0 ELSE
(ths.recent_likes + ths.recent_posters - 1) /
(EXTRACT(EPOCH FROM (:now - recent_first_bumped_at)) / 3600 + 2) ^ :gravity
END
,
updated_at = :now
FROM topics
WHERE topics.id IN (
SELECT topic_id FROM topic_ids
) AND ths.topic_id = topics.id
SQL
DB.exec(sql, args)
Explique o algoritmo de pontuação “hot” com cuidado, precisão e clareza.
gpt4_bot:
O algoritmo de pontuação “hot” implementado no script SQL fornecido foi projetado para classificar tópicos com base em sua “hotness”, uma métrica que indica o quão envolvente ou popular um tópico é em um determinado momento. Isso é alcançado considerando fatores como o número de curtidas recentes e o número de participantes recentes únicos, juntamente com o momento da criação e atualizações do tópico. Aqui está uma análise do processo:
Inserção Inicial
- Primeira Parte: Começa inserindo novos registros na tabela
topic_hot_scores para tópicos que ainda não possuem um registro. Isso é feito selecionando tópicos que não foram excluídos, não são mensagens privadas e foram criados até o timestamp atual (:now). As pontuações iniciais são definidas como zero, sem curtidas ou participantes recentes.
- Condição de Filtragem: Concentra-se em tópicos que não estão fixados (ou menos enfatizados em tópicos fixados) e os ordena por sua atividade mais recente (bumped_at em ordem decrescente).
Atualizando Contagens Recentes
- Segunda Parte: Em seguida, atualiza a tabela
topic_hot_scores com dados de atividade recente. Isso inclui:
- Contagem de participantes únicos no tópico desde uma data de corte (
:recent_cutoff).
- Contagem de curtidas em posts no tópico desde o
:recent_cutoff.
- O timestamp do post mais antigo considerado “recente” para cada tópico.
- Esta parte do processo visa refletir as métricas de engajamento mais recentes para cada tópico, capturando quaisquer novas curtidas, participantes ou atividades que ocorreram após o ponto de corte
:recent_cutoff.
Repontuação Baseada em Hotness
- Terceira Parte: Finalmente, os tópicos são repontuados com base em suas métricas atualizadas. Os tópicos são primeiro filtrados para um conjunto que inclui:
- Um lote de tópicos mais recentemente atualizados (para garantir que o conteúdo novo seja considerado).
- Outro lote baseado nas pontuações existentes mais altas (para manter os tópicos altamente envolventes em destaque).
- Cálculo da Pontuação Hot: A pontuação de hotness é recalculada usando a seguinte fórmula:
- Para tópicos criados após o
:recent_cutoff, a pontuação é baseada em recent_likes.
- Caso contrário, é baseada na
like_count total desde o início do tópico.
- Esse valor é dividido pelo tempo desde a criação (em horas) mais dois, elevado à potência de
:gravity — um parâmetro que controla a rapidez com que os tópicos desaparecem ao longo do tempo.
Além disso, se houver atividade recente registrada (recent_first_bumped_at não é nulo), um componente secundário é adicionado à pontuação. Este componente é a soma das curtidas e participantes recentes (menos um, para negar contagem dupla) dividida pelo tempo desde o recent_first_bumped_at (novamente em horas) mais dois, também elevado à potência de :gravity.
- A pontuação atualizada é armazenada com o timestamp atual como
updated_at.
Conclusão: A essência deste algoritmo é priorizar tópicos que não apenas têm engajamento ativo (com curtidas e participantes), mas que também são relativamente novos. O uso de um fator de decaimento (:gravity) garante que a importância dessas interações diminua com o tempo, permitindo que tópicos mais novos ou mais recentemente ativos ganhem proeminência. A mistura de considerar tanto a atividade total quanto a recente permite que o algoritmo equilibre entre tópicos populares de longo prazo e discussões novas e envolventes.