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