ms-dred
@ms-dred
Вечно что то не то и что то не так...

Как реализовать ТОП просмотров за день, неделю и месяц?

Интересует сама логика реализации.
У меня на данный момент существует данный рейтинг, но при перерасчете который выполняется каждый час создается очень большая нагрузка на базу данных, в связи с этим нужны какие то альтернативы.
Как сейчас все работает:
У меня есть коллекция, допустим analytics, со сбором статистики, куда прописывается URL с просмотром документа
{
   _id: ID,
   page: "http:......post/id/",
   count: 1, // поле лишнее, просто для наглядности
   createdAt: new Date()
}


Если пользователь просматривает пост, то идет запись в analytics.
Далее я каждый час обновляю данные по крону и собираю информацию сколько пользователей просмотрело определенные URL (суммирую просмотры).

За День этот URL просмотрело N пользователей
За Неделю этот URL просмотрело N пользователей
За Месяц этот URL просмотрело N пользователей
И таких разных URL тысячи.

В коллекции порядка 10 миллионов последних записей, более старые удаляются по крону, так как нет смысла их хранить.
Так вот, даже выборка просмотров за один день создает приличную нагрузку на сервер базы данных.
Пример выборки
return Analytics.aggregate([
        {
            $match: {
                count: { $exists: !0 },
                createdAt: { $gte: new Date(new Date().setDate(new Date().getDate() - 1)) }
            }
           //....
           {
            $group: {
                _id: "$page",
                count: {
                    $sum: "$count"
                }
            }
        }
    ])


С индексами все в порядке, они есть...

Затем банально сумму просмотров я записываю в коллекцию с постами, обновляю документ, а именно поле popular
//db.posts
{
    _id: ID,
    url: String,
    popular: {
        day: Number,
        week: Number,
        month: Number
    }
}


Как можно перестроить/переделать рейтинг для меньшей нагрузки на базу. Может доп. коллекцию создать для этого дела, но придется как то регулировать актуальность данных для расчета времени просмотров, в общем мне совсем не понятна альтернативная логика текущей.
Любые советы по этому поводу будут полезны для меня.
  • Вопрос задан
  • 347 просмотров
Пригласить эксперта
Ответы на вопрос 3
saboteur_kiev
@saboteur_kiev
software engineer
В свободное от нагрузки время аггрегировать данные за прошлые периоды.
Прошел день, за прошлый день посчитал, добавил в отдельную таблицу сумму одной строкой и прошлый день весь можно грохнуть.
Ответ написан
Комментировать
nokimaro
@nokimaro
Меня невозможно остановить, если я смогу начать.
Не храните каждый просмотр, храните кол-во просмотров каждой страницы за день.
Так как минимальная группировка это день, то стоит данные так и хранить
item_id
date_day
counter


если нужно отдельно отсеивать повторные просмотры одного пользователя, то для этого можно завести отдельную таблицу для того чтобы делать проверки перед увеличением счётчика
item_id + user_id

одна эта оптимизация позволит сократить количество хранимых и обрабатываемых данных в аналитике

ещё один трюк который использую для построения топа за день/неделю/месяц это внутри каждого элемента хранить три счётчика для сортировки
item_id
counter_1
counter_7
counter_30

Смысл в том что в течении дня эти счётчики увеличиваются при просмотрах независимо от счётчиков с аналитикой
Раз в сутки делается синхронизация, и для каждого item_id выставляются актуальные значения по сумме из аналитики и дальше снова целый день счётчики накручиваются независимо добавляя актуальные данные за день без необходимости что-то синхронизировать каждый час.
Ответ написан
RaShe
@RaShe
По поводу индекса, $exists делает partial colscan. Лучше count $gte 0.

Какой индекс используется можно проверить через .explain
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы