2013-06-06 2 views
2

У меня есть довольно интересная проблема, которая, как я думал, была бы прямолинейной, но оказалось сложнее.Запуск запроса за прошлые диапазоны дат

У меня есть данные, как это:

Date    User ID 
2012-10-11   a 
2012-10-11   b 
2012-10-12   c 
2012-10-12   d 
2012-10-13   e 
2012-10-14   b 
2012-10-14   e 
...    ... 

Каждая строка имеет дата, идентификатор пользователя пара, которая указывает, что этот пользователь был активен в тот же день. Пользователь может появляться на нескольких датах, а дата будет иметь несколько пользователей - точно так же, как в примере. У меня есть миллионы строк, которые охватывают диапазон времени около 90 дней.

Возникает вопрос: на каждый день я хочу получить число пользователей, которые неактивны в течение последних 10 дней. Например, если пользователь «a» был активен в 2012-05-31, но не был активен ни в один из дней между 06-01 и 06-10, я хочу подсчитать этого пользователя в 6/10. Я не стал бы считать его снова в следующие дни, хотя бы он не стал активным и не исчезнет снова.

Могу ли я сделать это в SQL или мне нужен какой-то скрипт для организации данных так, как я хочу. Какими будут ваши рекомендации? Я использую Hive.

Большое вам спасибо!

+0

Пришли, чтобы добавить +1 для оценки (что вы также делали по предыдущим вопросам). –

+0

Это не так сложно в стандартном SQL, но Hive просто предлагает подмножество функциональных возможностей SQL. Фактически, выражение функциональности в Map-Reduce напрямую было бы немного сложной задачей. –

ответ

2

Я думаю, вы можете сделать это в Hive-совместимом SQL. Вот идея.

  1. Для каждого пользователя/даты введите следующую дату для пользователя.
  2. Отменить оригинальную запись, если следующий срок меньше 10 дней после текущего.
  3. Добавить 10 дату
  4. агрегатных и сосчитать

Я не уверен, что все функции Hive для таких вещей, как даты. Вот пример того, как сделать это:

select date+10, count(*) 
from (select t.userid, t.date, 
      min(case when tnext.date > t.date then tnext.date end) as nextdate 
     from t left outer join 
      t tnext 
      on t.userid = tnext.userid 
     group by t.userid, t.date 
    ) t 
where nextdate is null or nextdate - date >= 10 
group by date+10; 

Обратите внимание, что внутренний подзапрос будет лучше написана с использованием:

on t.userid = tnext.userid and t2.date > t.date 

Однако, я не знаю, если улей поддерживает такие объединения (его не поддерживает не equijoins, и неясно, должно ли одно или все предложения быть равными).

+0

спасибо Гордону за спасение дня снова :) Это потрясающе. один быстрый комментарий ... Я верю в строку 9, «nextdate - date = 10» должен быть скорее «nextdate - date> 10»? –

+0

@ пользователь1621315. , , В OP кажется, что вы хотите считать пользователя только в первый день бездействия («если пользователь« a »был активен в 2012-05-31 и не был активен ни в один из дней между 06 -01 и 06-10, я хочу посчитать этого пользователя по 6/10. Я бы не стал его снова считать »). Конечно, это ваша проблема, поэтому, если неравенство решает вашу проблему, продолжайте! –

+0

@ пользователь1621315. , , Duh. Еще один пример кода, который должен быть достаточно умным, чтобы читать мои мысли. –