Как работает алгоритм ранжирования Hacker News? Перевод
В этом посте я попытаюсь объяснить, как работает алгоритм ранжирования Hacker News и как вы можете повторно использовать его в своих собственных приложениях.
Это очень простой алгоритм ранжирования, который удивительно хорошо работает, когда вы хотите выделить горячие или новые вещи.
Копаемся в коде Hacker News
Hacker News реализован на Arc
, диалекте Lisp
, закодированном Полом Грэхемом. Hacker News имеет открытый исходный код, и его код можно найти на arclanguage.org. Покопавшись в коде news.arc, вы можете найти алгоритм ранжирования, который выглядит следующим образом:
; Голоса делятся на возраст в часах в степени тяжести.
; Было бы интересно масштабировать гравитацию в слайдере.
(= gravity* 1.8 timebase* 120 front-threshold* 1
nourl-factor* .4 lightweight-factor* .3 )
(def frontpage-rank (s (o scorefn realscore) (o gravity gravity*))
(* (/ (let base (- (scorefn s) 1)
(if (> base 0) (expt base .8) base))
(expt (/ (+ (item-age s) timebase*) 60) gravity))
(if (no (in s!type 'story 'poll)) 1
(blank s!url) nourl-factor*
(lightweight s) (min lightweight-factor*
(contro-factor s))
(contro-factor s))))
По сути, рейтинг Hacker News выглядит так:
Оценка = (P-1) / (T + 2) ^ G,
где:
P = количество баллов за элемент (и -1 означает отрицание голоса отправителя)
T = время с момента отправки (в часах)
G = Gravity, по умолчанию 1,8
Как видите, алгоритм довольно тривиален в реализации. В следующем разделе мы увидим, как себя ведет алгоритм.
Влияние силы тяжести (G) и времени (T)
Гравитация и время существенно влияют на оценку предмета. Обычно это справедливо:
- оценка уменьшается по мере увеличения T
- оценка уменьшается намного быстрее для старых предметов, если сила тяжести увеличивается
Вот реализация на Python:
def calculate_score(votes, item_hour_age, gravity=1.8):
return (votes - 1) / pow((item_hour_age+2), gravity)
Наиболее важным аспектом является понимание того, как ведет себя алгоритм и как вы можете настроить его для своего приложения.
В 10 году Пол Грэм поделился обновленным алгоритмом ранжирования HN:
(= gravity* 1.8 timebase* 120 front-threshold* 1
nourl-factor* .4 lightweight-factor* .17 gag-factor* .1)
(def frontpage-rank (s (o scorefn realscore) (o gravity gravity*))
(* (/ (let base (- (scorefn s) 1)
(if (> base 0) (expt base .8) base))
(expt (/ (+ (item-age s) timebase*) 60) gravity))
(if (no (in s!type 'story 'poll)) .8
(blank s!url) nourl-factor*
(mem 'bury s!keys) .001
(* (contro-factor s)
(if (mem 'gag s!keys)
gag-factor*
(lightweight s)
lightweight-factor*
1)))))
Первоначально опубликовано в medium.com.
Возможно тут сделать такое?
Спасибо, пусть будет в одном месте.
Заслуживает внимание ещё алгоритм и метод реализации от Menéame.net расположенном тут:
github.com/gallir/Meneame/tree/master/scripts
Они в чем-то похожи, как и у Reddit:
В Menéame подсчет осуществляется отдельно и данные периодически записывают, например, в пост. В поле вес (или карма), тут есть уже это поле.
Т.е. механизм достаточно простой, настолько, что его нет даже смысла пробовать. А вводить сюда? Сейчас? ИМХО, пока не имеет смысла. Там это сделано потому, что:
В любой момент мы можем добавить что-то подобное, если назреет необходимость.
Обычно делается так:
Menéame интересен ещё тем, что они выводят вес этого поста, например, в виде графика: как меняется этот вес по времени. Там же есть голосование и в минус, что влечет за собой возможное понижение веса, если в минус голосовать будут и удаление поста из ленты. Т.е. вес поста, карма его, может плавать. Как и карма участника кстати.
Это иногда отслеживают, чтобы увидеть какие посты на подходе для публикации в ленте, а какие посты упали.