Комплексная статистическая агрегация временных рядов с участием полиморфных ассоциаций - PullRequest
11 голосов
/ 04 июня 2011

Хорошо. Будьте терпеливы со мной, поскольку мне нужно предоставить много контекстных деталей, прежде чем я смогу найти разумный ответ на свой вопрос.

У меня есть сайт, на котором можно делать ежедневные подборки акций. То, как это работает, заключается в том, что вам предлагается делать выбор между компаниями, которые сталкиваются в течение дня. Например, GE против IBM. Вы можете сделать два типа выбора: производительность (какая акция будет работать лучше?) И общий объем (будут ли комбинированные акции торговаться с объемами выше или ниже X?). Вы получаете 100 виртуальных долларов каждый день, чтобы делать выбор.

В конечном итоге наша цель состоит в том, чтобы отследить, какой пользователь зарабатывает больше всего денег на выбор в различных категориях (поясняется ниже) в следующие периоды времени: 5 дней, 15 дней, 30 дней, 90 дней, 180 дней, 1 год. , все время. Очень просто подсчитать, сколько денег заработано за выбор. Это общая сумма заработанных (или потерянных) денег / количество пиков.

Теперь каждая компания, которую выбирает пользователь, попадает в категориальную иерархию. Как правило, категориальная иерархия выглядит следующим образом:

Дивизион -> Основная группа -> Промышленная группа -> Классификация -> Компания

Вот несколько примеров:

  • Добыча полезных ископаемых -> Добыча металлов -> Железные руды -> Добыча бурых руд -> Компания A
  • Добыча полезных ископаемых -> Добыча металлов -> Железные руды -> Добыча бурых руд -> Компания B
  • Добыча -> Добыча металлов -> Железные руды -> Добыча лимонитов -> Компания C
  • Добыча -> Добыча металлов -> Железные руды -> Добыча лимонитов -> Компания D
  • Производство -> Табачные изделия -> Сигары -> Stogies -> Компания E
  • Производство -> Табачные изделия -> Сигары -> Stogies -> Компания F
  • Производство -> Табачные изделия -> Сигары -> Сигариллы -> Компания G
  • Производство -> Табачные изделия -> Сигары -> Сигариллы -> Фирма H
  • ... и так далее ...

Для каждой категории есть модель (и, конечно, соответствующая таблица), и они связаны (представьте себе Foreign_key), как вы видели выше.

Существует модель для Matchup, где каждая запись показывает, какие компании сталкиваются в течение дня. Каждая запись отслеживает начальные и конечные цены акций для каждой компании, а также общий объем торговли.

У каждого матча есть один или несколько: pick_prices, которые могут меняться в течение дня. Обычно каждый матч имеет цену выбора производительности и цену выбора общего объема. Цена определяет, сколько будет стоить пика и сколько вы зарабатываете за правильный выбор. (Теперь это всего лишь справочная информация. Вам не нужно беспокоиться об этих конкретных расчетах цен.)

В конце торгового дня выборки пользователя разрешаются. Выборы представлены в модели выбора со следующими атрибутами:

  • user_id
  • сумма потрачена (например, 10 долларов США)
  • результат (например, ВЫИГРАЛ, ПОТЕРЯЛ)
  • выбор (например, компания A)
  • pick_price_id
  • amount_won
  • решено (истина или ложь)
  • created_at
  • updated_at

В настоящее время, когда каждый выбор разрешен, обновляется другая таблица с именем pick_records, которая имеет следующие атрибуты:

  • user_id
  • recordable_id
  • recordable_type (подразделение, основная группа, отраслевая группа, классификация или компания)
  • выборок (общее количество выполненных выборок независимо от типа выбора)
  • выиграно (общее количество выигрышей, независимо от типа выбора)
  • потерян (общее количество потерянных пиков, независимо от типа выбора)
  • денег (общая сумма выигранных денег)
  • money_per_pick (деньги / пики)
  • performance_picks
  • performance_won
  • performance_lost
  • performance_money
  • performance_money_per_pick
  • volume_picks
  • volume_won
  • volume_lost
  • volume_money
  • volume_money_per_pick
  • created_at
  • updated_at

Как вы можете сказать, это полиморфная модель. В таблице собрана статистика записей за все время.

Итак, вот задача:

Учитывая существующий дизайн, что мне нужно сделать, чтобы я мог получить записи выбора пользователя за следующие периоды времени: 5 дней, 15 дней, 30 дней, 90 дней, 180 дней, 1 год, все время? Это должно быть просто, эффективно и быстро!

В настоящее время я использую Rails 2.3.11 в БД MySQL.

Ответы [ 3 ]

3 голосов
/ 04 июня 2011

Я не вижу необходимости в таблице pick_records.
Вы можете сделать такой запрос на любое количество дней:

SELECT 
   user_id
   ,sum(amount_spent) 
   ,sum(IF(result = 'WON',1,0)) as WON_count
   ,sum(IF(result = 'LOST',1,0)) as LOST_count
   ,pick 
   /*matchup_id*/
   ,sum(pc.price) as price
   ,sum(IF(result = 'WON'),amount_won,0)) as amount_won
   ,sum(IF(result = 'LOST'),amount_won,0)) as amount_lost
   ,sum(IF(result = 'WON'),amount_won,-amount_won)) as nett_amount
FROM picks
INNER JOIN pick_price pc ON (pc.id = user.pick_price_id)
WHERE created_at BETWEEN DATE_SUB(NOW(), INTERVAL 5 DAY) AND NOW()
  AND resolved = 'true'
GROUP BY user_id, pick
0 голосов
/ 10 июня 2011

Если я правильно понимаю, теперь существует только один pick_record для каждого пользователя, и он содержит обзор его общего выбора и обновляется при разрешении выбора.

Поскольку содержимое pick_record может быть рассчитано, оно просто используется для кэширования и обеспечения возможности очень быстрого предоставления данных / отчета.

Чтобы решить вашу проблему, я бы предложил следующее:

Вместо единственной записи pick_record в течение всей продолжительности жизни, я бы использовал запись pick_record на интересующий вас промежуток времени. Таким образом, у вас будет запись pick_record с результатом за последние 4 дня, одна с результатом для результата последние 14 дней, 29 ... Те, которые вы рассчитываете один раз в день, предпочтительно ночью (или когда ваш сайт мало используется). Когда должен быть показан отчет за выбранный период времени, вам нужно только добавить результат текущего дня и готово!

Итак, резюмируем:

  1. ввести pick_record для интересующего периода (добавить поле с указанием периода: 5, 15, 30, ...)
  2. предварительно вычислять результаты один раз в день (фоновое задание, например, resque или delayed_job)
  3. при получении результатов периода нужно только добавить результаты текущего дня

Что вы думаете?

0 голосов
/ 07 июня 2011

Не уверен, правильно ли я понял вопрос, но ...

@records=Pick_record.all(:conditions => ["user_id = ?", user_id],
                         :group => "date(created_at)", 
                         :having => ["created_at > ?", 5.days.ago])
...