Рекомендации по расчету общего рейтинга

У меня есть бизнес-приложение на основе LAMP. SugarCRM, если быть точнее. На данный момент более 120 активных пользователей. Каждый день каждый пользователь генерирует несколько записей, которые используются в сложном расчете для получения так называемого «индивидуального рейтинга».

Расчет одного значения «индивидуального рейтинга» занимает около 6 секунд. А раньше не было большой проблемы: каждый пользователь переходит по предоставленной ссылке для запуска расчета «индивидуального рейтинга», ждет 6-7 секунд и получает отображаемое значение.

Но теперь мне нужно реализовать расчет «общего рейтинга». То есть помимо «индивидуального рейтинга» я должен вычислить и отобразить пользователю:

  • минимальный индивидуальный рейтинг среди ВСЕХ пользователей приложения

  • максимальный индивидуальный рейтинг среди ВСЕХ пользователей приложения

  • текущая позиция пользователя в диапазоне всех индивидуальных оценок.

Скажем, текущий пользователь имеет индивидуальный рейтинг 220 баллов, минимальное значение рейтинга 80, максимальное 235 и он находится на 23 месте среди всех пользователей.

Каковы (имхо) основные проблемы, которые необходимо решить?

  1. Если один расчет длится 6 секунд, общий расчет займет более 10 минут. Я думаю, что нет смысла делать приложение почти недоступным на этот период. А что если количество пользователей вырастет в ближайшее время в 2-3 раза?

  2. Эти расчеты можно было бы выполнять как ночную работу, но все пользователи находятся в разных часовых поясах. В России разница между крайними часовыми поясами составляет 9 часов. Так что люди в западной части России все еще работают «сегодня». В то время как люди в восточной части просыпаются, чтобы работать в «завтра». Так какое лучшее время для ночной работы в этом случае?

Существуют ли какие-либо передовые методы|подходы|алгоритмы для построения такой рейтинговой системы?


person erop    schedule 24.06.2013    source источник
comment
Я думаю, основная проблема заключается в следующем: почему для расчета одного рейтинга требуется 6-7 секунд?   -  person alzaimar    schedule 24.06.2013
comment
В основном это время выполнения SQL-запроса.   -  person erop    schedule 24.06.2013


Ответы (2)


Учитывая только предоставленную информацию, единственные варианты, которые я вижу:

  1. Очевидный - сократить время, затрачиваемое на расчет рейтинга (6 секунд для расчета рейтинга 1 пользователя - это много)

  2. Если возможно, используйте промежуточные значения, из которых вы будете пересчитывать только некоторые из них по мере необходимости (например, иметь 10 значений, составляющих рейтинг, все основанные на разных данных, когда некоторые данные изменяются, помечайте соответствующие значения для пересчета). Либо выполните этот пересчет:

    • During your daily recalculation or
    • When the update happens

  3. Partial batch calculation - only recalculate x of the users' ratings at chosen intervals (where x is some chosen value) - has the disadvantage that, at all times, some of the ratings can be out of date

  4. Вычислять, если не занят - либо постоянно пересчитывать рейтинги, либо делать это только через выбранный интервал, но вместо блокировки системы запускать его как фоновый процесс, выполняя работу только в том случае, если система простаивает.

person Bernhard Barker    schedule 24.06.2013

(Извините, не удалось опубликовать «длинный» комментарий, поэтому решил опубликовать как ответ)

@Dukeling

SQL-запрос, который занимает почти все время для вычислений, упомянутых выше, является просто репликацией бизнес-логики, которая должна выполняться в PHP-коде. Логика была перенесена в SQL в надежде сократить время вычислений. Хорошо, я попробую оптимизировать SQL-запрос и поиграться с выполнением логики в PHP-коде.

Предположим, после этого оптимизированное приложение вычисляет индивидуальный рейтинг всего за 1 секунду. Большой! Но даже в этом случае первый пользователь, вошедший в систему, должен ждать 120 секунд (120+ пользователей * 1 секунда = 120 секунд), чтобы подсчитать общий рейтинг и получить в нем свою позицию.

Я думаю о реализации следующего подхода:

  1. Пусть будет 2 «общих рейтинга» — «сегодня» и «вчера».

  2. Для отображения мы будем использовать общий рейтинг «вчера», представленный в виде огромного уже отсортированного массива PHP.

  3. Когда пользователь нажимает на ссылку расчета, он начинает расчет «сегодня», но приложение отображает ему значение «вчера». Таким образом, у нас есть быстро доступный «вчерашний» рейтинг, и каждый пользователь случайным образом запускает расчет рейтинга, который будет отображаться для него завтра.

  4. Список пользователей разделен по часовым поясам. Каждый час задание cron начинало проверять, есть ли пользователи в выбранном часовом поясе, для которых не рассчитан индивидуальный рейтинг «сегодня» (например, пользователь не вошел в приложение). Если это так, приложение запускает расчет индивидуального рейтинга и помещает его значение в массив «сегодня» (еще невидимый) общего рейтинга. Таким образом, у нас есть задание cron, которое запускается каждую ночь для каждой группы пользователей, зависящих от часового пояса, и заполняет вероятные пробелы в случае, если пользователи не вошли в систему.

  5. After all users in all timezones had been worked out, application
    1. sorts “today” array,
    2. роняет «вчерашний» один,
    3. переименовать «сегодня» в «вчера» и
    4. инициализировать новое «сегодня».

Что ты думаешь об этом? Это достаточно разумно или нет?

person erop    schedule 24.06.2013