全員:
いいです!今日、私はハイブ分析機能の質問を見ました。これは非常に興味深いものです。みんなに役立つことを願って、答えを整理して共有しました。要件は次のとおりです。
この質問を最初に見たとき、分析機能を使うべきだと感じましたが、使い方がわかりませんでした。幸いなことに、最終的にはそれが書かれ、アイデアは次のとおりです。
----テストテーブルのテーブル構造とデータは次のとおりです。
hive> desc sales;
OK
id int
produce_name string
start_time date
end_time date
days int
Time taken: 0.354 seconds, Fetched: 5 row(s)
hive> select * from sales;
OK
1 nike 2011-09-01 2011-09-05 5
2 nike 2011-09-03 2011-09-06 4
3 nike 2011-09-09 2011-09-15 7
4 oppo 2011-08-04 2011-08-05 2
5 oppo 2011-08-04 2011-08-15 12
6 vivo 2011-08-15 2011-08-21 7
7 vivo 2011-09-02 2011-09-12 11
Time taken: 0.223 seconds, Fetched: 7 row(s)
---ステップ1:各開始時間の前のプロモーションの開始時間と終了時間を見つけます
select id,produce_name,start_time,end_time,
lag(start_time) over(partition by produce_name order by id) before_start_time,
lag(end_time) over(partition by produce_name order by id) before_end_time
from sales;
---最初のステップ:実行結果(最初のステップ)
1 nike 2011-09-01 2011-09-05 NULL NULL
2 nike 2011-09-03 2011-09-06 2011-09-01 2011-09-05
3 nike 2011-09-09 2011-09-15 2011-09-03 2011-09-06
4 oppo 2011-08-04 2011-08-05 NULL NULL
5 oppo 2011-08-04 2011-08-15 2011-08-04 2011-08-05
6 vivo 2011-08-15 2011-08-21 NULL NULL
7 vivo 2011-09-02 2011-09-12 2011-08-15 2011-08-21
---ステップ2前回のプロモーションの開始時間と終了時間に応じて、次のグループ化に備えて、開始時間を最も早いものとして統一します。
select produce_name,start_time,max(end_time) end_time from
(select id,produce_name,case when start_time>=before_start_time and start_time<=before_end_time then before_start_time else start_time end as start_time, end_time
from (select id,produce_name,start_time,end_time,
lag(start_time) over(partition by produce_name order by id) before_start_time,
lag(end_time) over(partition by produce_name order by id) before_end_time
from sales) t) d
group by produce_name,start_time;
--2番目のステップ(2番目のステップ)の実行結果
nike 2011-09-01 2011-09-06
nike 2011-09-09 2011-09-15
oppo 2011-08-04 2011-08-15
vivo 2011-08-15 2011-08-21
vivo 2011-09-02 2011-09-12
---ステップ3合計開始時間に従って、各期間のプロモーション日の合計を計算します
select produce_name,start_time,end_time,datediff(end_time,start_time)+1 days from
(select produce_name,start_time,max(end_time) end_time from
(select id,produce_name,case when start_time>=before_start_time and start_time<=before_end_time then before_start_time else start_time end as start_time, end_time
from (select id,produce_name,start_time,end_time,
lag(start_time) over(partition by produce_name order by id) before_start_time,
lag(end_time) over(partition by produce_name order by id) before_end_time
from sales) t) d
group by produce_name,start_time) e;
-実行結果(3番目のステップ)
nike 2011-09-01 2011-09-06 6
nike 2011-09-09 2011-09-15 7
oppo 2011-08-04 2011-08-15 12
vivo 2011-08-15 2011-08-21 7
vivo 2011-09-02 2011-09-12 11
-ステップ4:製品名に従って、最終プロモーション日の合計を見つけます
select produce_name,sum(days) from
(select produce_name,start_time,end_time,datediff(end_time,start_time)+1 days from
(select produce_name,start_time,max(end_time) end_time from
(select id,produce_name,case when start_time>=before_start_time and start_time<=before_end_time then before_start_time else start_time end as start_time, end_time
from (select id,produce_name,start_time,end_time,
lag(start_time) over(partition by produce_name order by id) before_start_time,
lag(end_time) over(partition by produce_name order by id) before_end_time
from sales) t) d
group by produce_name,start_time) e) f
group by produce_name;
---実行結果(第4ステップ)
nike 13
oppo 12
vivo 18
説明:個人的な意見ですが、皆様のお役に立てれば幸いです。
後で分析した後、この方法には問題があります。連続値に複数の行が含まれる場合、オフセットに従って最小値を取得するときに問題が発生します。
最初のステップは、各行の最後の終了時刻を取得することです
select id,
produce_name,
start_time,
end_time,
lag(end_time,1,start_time) over(partition by produce_name order by id) before_end_time
from sales
効果は次のとおりです。
2番目のステップは、銀行の開始時刻から最後の終了時刻までの日数を計算することです。datediff関数は差分の概念であるため、連続値を1増やす必要があり、間隔の日数を1引く必要があります。
select
id,
produce_name,
end_time,
start_time,
before_end_time,
datediff(end_time,start_time)+1 as cnt_all,
case when start_time<=before_end_time then 0 else datediff(start_time,before_end_time)-1 end cnt
from (select id,
produce_name,
start_time,
end_time,
lag(end_time,1,start_time) over(partition by produce_name order by id) before_end_time
from sales ) t
効果は次のとおりです。
結果は予想通りです。ナイキの3行目の開始時間は9日、最後の終了時間は6日です。途中で2日の違いがあります。
3番目のステップは、製品の要約に従って、連続値と中間間隔値を合計することです。
select
produce_name,
min(start_time) as start_time,
max(end_time) as end_time,
datediff(max(end_time),min(start_time))+1 cnt_all,
sum(case when start_time<=before_end_time then 0 else datediff(start_time,before_end_time)-1 end) cnt
from (select id,
produce_name,
start_time,
end_time,
lag(end_time,1,start_time) over(partition by produce_name order by id) before_end_time
from sales ) t
group by produce_name
結果は次のとおりです。
4番目のステップは、簡略化された最終スクリプトです
select
produce_name,
datediff(max(end_time),min(start_time))+1-
sum(case when start_time<=before_end_time then 0 else datediff(start_time,before_end_time)-1 end) cnt
from (select id,
produce_name,
start_time,
end_time,
lag(end_time,1,start_time) over(partition by produce_name order by id) before_end_time
from sales ) t
group by produce_name
最終結果は次のとおりです。
個人的な意見ですが、訂正してください。