2014年07月29日

HIVE 0.13でGROUP BYしてCOUNTして上位10件をCOLLECT_ALLしてarrayで取得する

というようなことをする為にクエリを書く。もっと良い書き方があるような気もする。

StackOverFlowを見たらRankを使おうみたいなことが書いてあったけど、サンプルがうまく動かなかったのでROW_NUMBERを使用。0.11以降実装されているらしい。

下記クエリの仕様は、page_id, user_idが記述されているアクセスログ的なテーブルを集計して、各page_idを訪れているuser_id上位10件を出すものとする。page_idはurl encodeする。

SELECT
  REFLECT("java.net.URLEncoder", "encode", page_id),
  COLLECT_ALL( user_id )
FROM
  (
    SELECT
      page_id,
      user_id,
      ROW_NUMBER() OVER ( PATITION BY page_id ORDER BY cnt DESC ) AS rank
    FROM
      (
        SELECT
          page_id,
          user_id,
          COUNT(1) AS cnt
        FROM
          access_log
        GROUP BY
          page_id,
          user_id
      ) a
    DISTRIBUTE BY
      page_id,
      user_id
  ) b
WHERE
  rank <= 10
GROUP BY
  page_id,
  user_id

実際に動かしたクエリからいろいろ改変しているので、このままだと動かないかもしれない。でもイメージはだいたいこんな感じで想定した動きになった。

以下、使っている機能の説明。

REFLECT : Javaのメソッドを直接呼び出す。int, double, string等の基本的なクラスしか引数に渡せない。

COLLECT_ALL : GROUP BYした結果をarrayに展開する。類似の機能にcollect_setなどもある。

ROW_NUMBER : 名前の通りROWにNUMBERを振る。

DISTRIBUTE BY : 同一のReducerで処理するよう指定する。