Комплексная статистическая агрегация временных рядов с участием полиморфных ассоциаций

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

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

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

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

Отдел → Основная группа → Промышленная группа → Классификация → Компания

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

  • Добыча полезных ископаемых → Металлургия → Железные руды → Руда руды → Компания A
  • Добыча полезных ископаемых → Металлургия → Железные руды → Руда руды → Компания B
  • Добыча полезных ископаемых → Металлургия → Железные руды → Лимонитовая промышленность → Компания C
  • Добыча полезных ископаемых → Металлургия → Железные руды → Лимонит Майнинг → Компания D
  • Производство → Табачные изделия → Сигары → Стили → Компания E
  • Производство → Табачные изделия → Сигары → Стили → Компания F
  • Производство → Табачные изделия → Сигары → Сигариллы → Компания G
  • Производство → Табачные изделия → Сигары → Сигариллы → Компания H
  • ... и т.д.

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

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

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

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

  • user_id
  • amount_spent (например, $10)
  • (например, WON, LOST)
  • выберите (например, компанию A)
  • matchup_id
  • pick_price_id
  • amount_won
  • разрешено (true или false)
  • 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 DB.

Ответ 1

Я не вижу необходимости в таблице 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

Ответ 2

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

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

Ответ 3

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

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

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

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

Итак, чтобы повторить:

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

Как вы думаете?