Статья

Как работает алгоритм ранжирования 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.

Возможно тут сделать такое?

1 Ответ

  1. Спасибо, пусть будет в одном месте.

    Заслуживает внимание ещё алгоритм и метод реализации от Menéame.net расположенном тут:

    github.com/gallir/Meneame/tree/master/scripts

    Они в чем-то похожи, как и у Reddit:

    • Карма поста не линейна. +1 это не +1
    • Это зависит от времени. Чем быстрей после публикации нажмут, тем выше карма.
    • Иногда еще зависит от TL участника

    В Menéame подсчет осуществляется отдельно и данные периодически записывают, например, в пост. В поле вес (или карма), тут есть уже это поле.

    Т.е. механизм достаточно простой, настолько, что его нет даже смысла пробовать. А вводить сюда? Сейчас? ИМХО, пока не имеет смысла. Там это сделано потому, что:

    • Поток постов просто огромен и действительно необходимо решать, что будет на центральной.
    • Там чуток другая система, тут пока очень все просто.

    Подписался — читаешь, сортировка по времени.

    В любой момент мы можем добавить что-то подобное, если назреет необходимость.


    Обычно делается так:

    при добавление поста ему изначально присваивается вес, чтобы он совсем не пропал из видимости (ведь сортировка идет не по дате). А далее, через скажем 5 минут, потом через 10, идет уточнение этого веса.

    Menéame интересен ещё тем, что они выводят вес этого поста, например, в виде графика: как меняется этот вес по времени. Там же есть голосование и в минус, что влечет за собой возможное понижение веса, если в минус голосовать будут и удаление поста из ленты. Т.е. вес поста, карма его, может плавать. Как и карма участника кстати.

    Это иногда отслеживают, чтобы увидеть какие посты на подходе для публикации в ленте, а какие посты упали.