CUBE SUGAR CONTAINER

技術系のこと書きます。

Apache Hive を使ったテーブルのサンプリング

Apache Hive では、大規模なデータセットに対してクエリを実行すると完了までに長い時間がかかる。 そこで、全体から一部を抽出した標本に対してクエリを実行する場合がある。 今回は、その標本を抽出する方法 (サンプリング) について扱う。

使った環境は次の通り。

$ cat /etc/redhat-release 
CentOS Linux release 7.4.1708 (Core)
$ uname -r
3.10.0-693.5.2.el7.x86_64
$ hadoop version
Hadoop 2.8.3
Subversion https://git-wip-us.apache.org/repos/asf/hadoop.git -r b3fe56402d908019d99af1f1f4fc65cb1d1436a2
Compiled by jdu on 2017-12-05T03:43Z
Compiled with protoc 2.5.0
From source with checksum 9ff4856d824e983fa510d3f843e3f19d
This command was run using /home/vagrant/hadoop-2.8.3/share/hadoop/common/hadoop-common-2.8.3.jar
$ hive --version
Hive 2.3.2
Git git://stakiar-MBP.local/Users/stakiar/Desktop/scratch-space/apache-hive -r 857a9fd8ad725a53bd95c1b2d6612f9b1155f44d
Compiled by stakiar on Thu Nov 9 09:11:39 PST 2017
From source with checksum dc38920061a4eb32c4d15ebd5429ac8a

下準備

まずは例となるクエリを実行するテーブルを用意しておこう。 これのテーブルは、整数を格納するカラムを一つだけ持っている。

hive> CREATE TABLE numbers (
    >   n INTEGER
    > );
OK
Time taken: 0.066 seconds

上記のテーブルに対してレコードを追加していく。 ここで注意すべきなのは INSERT 文を個別に発行すること。 詳しくは後述するものの、クエリを一つのまとめてしまうとブロックサンプリングという方法を使ったときに上手く動作しない。

hive> INSERT INTO TABLE numbers VALUES (0);
...
hive> INSERT INTO TABLE numbers VALUES (1);
...
hive> INSERT INTO TABLE numbers VALUES (9);
...
OK
_col0
Time taken: 2.384 seconds

テーブルが以下のような状況になっていることを確認する。

hive> SELECT * FROM numbers;;
OK
numbers.n
0
1
2
3
4
5
6
7
8
9
Time taken: 0.139 seconds, Fetched: 10 row(s)

これで、ひとまず準備ができた。

ランダムなサンプリング

Apache Hive でテーブルの一部をサンプリングするには TABLESAMPLE という構文を使う。 この構文にはいくつかの使い方があるものの、基本は次のようなクエリとなる。

hive> SELECT *
    > from numbers
    > TABLESAMPLE(BUCKET 1 OUT OF 10 ON rand());
OK
numbers.n
6
Time taken: 0.048 seconds, Fetched: 1 row(s)

上記のクエリでは、まず格納されているそれぞれのレコードに rand() 関数でランダムな値を割り振っている。 そして、そのランダムな値をハッシュ化して、結果を 10 個のバケットに振り分けていく。 振り分けられたバケットのうち 1 番目を出力する、というのが上記のクエリの意味となる。

乱数をハッシュ化して 10 個のバケットに割り振っているため、それぞれのバケットには概ね 1 つずつレコードが入ることが期待される。 しかし、もちろん偏ることもあるので次のように 2 つ以上入っていたり、反対に全く入らないこともある。

hive> SELECT *
    > from numbers
    > TABLESAMPLE(BUCKET 1 OUT OF 10 ON rand());
OK
numbers.n
5
6
Time taken: 0.047 seconds, Fetched: 2 row(s)

これはもちろんバケットの数を減らしたり増やした場合にも同じことがいえる。

hive> SELECT *
    > from numbers
    > TABLESAMPLE(BUCKET 1 OUT OF 5 ON rand());
OK
numbers.n
3
6
Time taken: 0.046 seconds, Fetched: 2 row(s)
hive> SELECT *
    > from numbers
    > TABLESAMPLE(BUCKET 1 OUT OF 5 ON rand());
OK
numbers.n
2
5
6
Time taken: 0.062 seconds, Fetched: 3 row(s)

特定のカラムをハッシュ化に用いる

先ほどの例ではハッシュ化に用いる値に rand() 関数が返すランダムな値を使った。 しかし、これにはテーブルに存在する特定のカラムを用いることもできる。

例えば numbers テーブルの n カラムをハッシュ化に使ってみよう。

hive> SELECT *
    > from numbers
    > TABLESAMPLE(BUCKET 1 OUT OF 10 ON n);
OK
numbers.n
0
Time taken: 0.065 seconds, Fetched: 1 row(s)

特定のカラムをハッシュ化に使う場合、値は実行ごとに変化することがないため毎回同じ内容が得られる。

hive> SELECT *
    > from numbers
    > TABLESAMPLE(BUCKET 1 OUT OF 10 ON n);
OK
numbers.n
0
Time taken: 0.068 seconds, Fetched: 1 row(s)

取得したい内容を変更するには、選択するバケットを変えるしかない。

hive> SELECT *
    > from numbers
    > TABLESAMPLE(BUCKET 2 OUT OF 10 ON n);
OK
numbers.n
1
Time taken: 0.057 seconds, Fetched: 1 row(s)
hive> SELECT *
    > from numbers
    > TABLESAMPLE(BUCKET 3 OUT OF 10 ON n);
OK
numbers.n
2
Time taken: 0.053 seconds, Fetched: 1 row(s)

ブロックサンプリング

TABLESAMPLE には特定の割合をサンプリングするよう指定する方法もある。 これはブロックサンプリングと呼ばれるやり方で、その名の通りテーブルを構成するブロック単位でサンプリングする。 下準備で INSERT を一つのクエリにまとめなかったのはこのためだった。 一つのクエリにまとめてしまうと、レコードが全て一つのブロックに格納されてしまうため、この機能が上手く動作しない。

ブロックサンプリングでは TABLESAMPLE に百分率で割合を指定する。

hive> SELECT *
    > FROM numbers
    > TABLESAMPLE(10.0 PERCENT);
OK
numbers.n
0
Time taken: 0.026 seconds, Fetched: 1 row(s)
hive> SELECT *
    > FROM numbers
    > TABLESAMPLE(20.0 PERCENT);
OK
numbers.n
0
1
Time taken: 0.029 seconds, Fetched: 2 row(s)

ただし、この実行結果についても、そのままでは毎回同じ内容が得られる。

hive> SELECT *
    > FROM numbers
    > TABLESAMPLE(20.0 PERCENT);
OK
numbers.n
0
1
Time taken: 0.037 seconds, Fetched: 2 row(s)

得られる内容を変更したいときは、明示的に hive.sample.seednumber を変更してやる必要がある。

hive> set hive.sample.seednumber=7;
hive> SELECT *
    > FROM numbers
    > TABLESAMPLE(20.0 PERCENT);
OK
numbers.n
7
8
Time taken: 0.031 seconds, Fetched: 2 row(s)

まとめ

  • Apache Hive でサンプリングするときは TABLESAMPLE を使う
  • サンプリングの挙動について
    • 特定の値をハッシュ化してバケットに振り分ける
    • 振り分けられたバケットを選択する
    • ハッシュ化に使う値は rand() 関数の値や、特定のカラムの内容が使える
  • 上記のやり方の他にブロックサンプリングという方法もある
    • ブロック単位でサンプリングされる点に注意が必要となる
    • サンプリング結果を変えたいときは hive.sample.seednumber を変更する

プログラミング Hive

プログラミング Hive

  • 作者: Edward Capriolo,Dean Wampler,Jason Rutherglen,佐藤直生,嶋内翔,Sky株式会社玉川竜司
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2013/06/15
  • メディア: 大型本
  • この商品を含むブログ (3件) を見る