digdagを使ってhive形式のクエリをinsertしようとするとエラーが出た話


digdagを使ってログから中間テーブルを起こそうとした時に起きた話です。
hiveの独特な書き方みたいなところで引っかかりました。

結論

with句が終わって実際にselectするところに

-- DIGDAG_INSERT_LINEを突っ込め!

やろうとしたこと

すでにTD上にある大量レコードのテーブルから、サマリーをした中間テーブルを作ろうとしました。

before(実データではtimetimestampではなくlongが入ってます)
user_id event time
1 add 2017/12/17 06:34
1 add 2017/12/17 06:35
1 change 2017/12/17 06:36
1 add 2017/12/17 06:37
1 delete 2017/12/17 06:49
1 add 2017/12/18 06:50
after
user_id event date count
1 add 2017/12/17 3
1 add 2017/12/18 1
2 add 2017/12/17 1

こんな感じ。

抽出クエリ
user_event_cnt.sql
with log as (
  select
    user_id
    ,event
    ,td_time_format(time,'yyyy-MM-dd','jst') as date
  from
    event_log
)

select
  user_id
  ,event
  ,date
  ,count(1)
from
  log
group by
  1,2,3,

なんてことはないですね。
実際にtd上で実行しても通りました。

digってみる

user_event_cnt.dig
timezone: Asia/Tokyo

+transport_raw:
  _export:
    td:
      source_db: test
      to_db: event_log

  +drip_user_event_cnt:
    td>: queries/user_event_cnt.sql
    database: ${td.source_db}
    engine: hive
    create_table: ${td.to_db}.user_event_cnt

td wf run --rerun user_event_cnt.dig
えいっ!

あれエラー出ましたね。
FAILED: ParseException line 2:0 cannot recognize input near 'with' 'log' 'as' in select clause
MapReduce time taken: 0.195 seconds

予約語関連でエラー?そんなバカな

というわけで、もろもろ調べてみました。

原因判明

digdagcreate_tableコマンドが何をしているかというと、
指定したsqlの前にこの一文を発行しているようです。
INSERT OVERWRITE TABLE `test `.`user_event_cnt`

INSERTの後にWITH句がおけないというhiveのローカルルールに引っかかりエラーが起きていました。

実際にselectをするところの前に-- DIGDAG_INSERT_LINEを記述してあげないといけません。

user_event_cnt.sql
with log as (
  select
    user_id
    ,event
    ,td_time_format(time,'yyyy-MM-dd','jst') as date
  from
    event_log
)

-- DIGDAG_INSERT_LINE

select
  user_id
  ,event
  ,date
  ,count(1)
from
  log
group by
  1,2,3,

これでおっけい!
実行結果もうまくいきました。

余談

tdといえば、クエリをprestohiveで選べますが、prestoではどうなってるでしょうか。

prestoでは、withの前でinsertが記述されても特に問題なく実行されます。
なので気にせずにinsertとできると思います。

hiveでクエリ書き換えたけど動かねーぞ!となったら、ぜひ試してみてください。