初めての Hive クエリ

ビッグデータBeginner
オンラインで実践に進む

はじめに

小売業者の注文記録を表計算ソフトで開く場面を想像してください。各行は1件の注文を表し、各列は日付や支払い状況などの属性を表します。知りたいのは、「支払い済みの注文のうち、チームはどれから確認すればよいか?」という単純な疑問です。ファイルが大きくなると、すべての行を手で読むのは大変です。

Apache Hive では、ファイルデータをテーブルとして定義し、SQL(Structured Query Language)で質問できます。テーブル定義は列と元のファイルの場所を示し、ファイルには実際の記録が入っています。Hive はその定義でデータを解釈し、クエリを実行します。この準備済み環境では、HDFS が保存を、Hive がテーブルとクエリの層を担当します。ファイルをアップロードしただけでは、自動的に Hive のテーブルになるわけではありません。

Hive は、バッチレポートなど、保存済みのデータを対象とする分析クエリに役立ちます。表計算のセルを編集するのとは異なり、このコースでも、あらゆるアプリケーションのトランザクション用データベースを置き換えるものとは扱いません。まずは読みやすい6件の記録を使い、より大きい入力に進む前に、正しい答えを予想できるようにします。

Hive のターミナルクライアント Beeline を使い、稼働中の HiveServer2 サービスに接続します。サービスとサンプルの表は準備済みです。ソフトウェアのインストール、メタデータの初期化は不要で、Java、Python、Hadoop、SQL の事前知識も必要ありません。基本的なターミナル操作と、表を読む力があれば十分です。ターミナルやデータベースの追加練習には、Linux と Database の学習パスを参照してください。

実際の行を見る、表の構造を調べる、支払い済み注文を選ぶクエリを保存する、条件を1つ変えて理解を確かめる、という順で学びます。

最初の Hive の行を見る

このステップでは、クエリを絞り込む方法を学ぶ前に、Hive に接続して準備済みの表を読みます。

Terminal タブを使います。cd でローカルのプロジェクトディレクトリに移動します。

cd /home/labex/project

Beeline はクライアントです。クエリを扱う HiveServer2 に SQL を送ります。以下のコマンドの -u は接続 URL、-n はセッションのユーザー名、-e は実行する SQL を指定します。実行後は終了してターミナルに戻ります。用意された URL は、このマシンのポート 10000 の Hive サービスに、最初は default データベースで接続します。この学習用サービスに外部アカウントやパスワードは必要ありません。

SQL の SELECT * FROM retail_intro.orders; は、retail_intro データベースの orders テーブルからすべての列(*)を取得する指定です。セミコロンは文の終わりを表します。単一引用符は、SQL 文全体をシェルの1つの引数としてまとめます。

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex -e 'SELECT * FROM retail_intro.orders;'

6行の注文と、order_id、quantity、order_status などの列名を探してください。結果の前後に接続メッセージや表の罫線が表示される場合があります。注文 o1 は、数量が 2、単価が 10.00、状態が paid です。o3 は pending、o5 は refunded です。各行は、1種類の商品を含む単純化した注文1件を表します。

クエリはデータを取得します。この SELECT は支払い状態や元ファイルを変更しません。並べ替えの句がない場合、SQL が特定の行順を保証すると考えないでください。

同じクエリの出力をローカルの記録に保存します。シェルの > はファイルを作成するか、既存の内容を置き換えます。

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex -e 'SELECT * FROM retail_intro.orders;' > /home/labex/project/output/first-look.txt

ローカルで読みます。

cat /home/labex/project/output/first-look.txt

注文の行が引き続きあるはずです。ターミナルが Beeline クライアントを実行し、Hive がテーブル定義とファイルを読み、シェルが表示結果をローカルに保存しました。次はクエリの背後にあるオブジェクトを調べます。

データベース、テーブル、列を調べる

このステップでは、列名を推測せずに、データベースとテーブル定義を調べます。

データベースはテーブルをまとめる名前空間です。SHOW DATABASES は利用可能なデータベースを一覧表示するもので、その全データファイルを読むわけではありません。

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex -e 'SHOW DATABASES;'

default と retail_intro を探します。USE でデータベースを選び、同じ実行内で続けて SHOW TABLES を使います。

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex -e 'USE retail_intro; SHOW TABLES;'

orders が見つかるはずです。-e のコマンドは毎回新しい Beeline セッションを開くため、ある実行の USE が次の実行に自動で引き継がれることはありません。各 SQL ファイルでデータベースを選ぶか、修飾名 retail_intro.orders を使ってください。

DESCRIBE は表の列と型を一覧表示します。例えば、STRING はテキスト、INT は整数、DECIMAL(10,2) は小数点以下2桁の固定小数点数、DATE はカレンダーの日付を表します。

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex -e 'DESCRIBE retail_intro.orders;'

最初のクエリの行とフィールドを対応させてください。数量と価格は、どちらも数値に見えても意味と型が違います。金額の計算は後の実験で行い、今回は提供されたフィールドを読むだけです。

クエリ結果を保存する際、Beeline では単純なテキスト形式を使えます。--outputformat=tsv2 はタブ区切り、--showHeader=false はヘッダー行の省略、--silent=true はクライアントのメッセージの削減を指定します。これらの出力オプションで、確認したスキーマを保存します。

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex --silent=true --showHeader=false --outputformat=tsv2 -e 'DESCRIBE retail_intro.orders;' > /home/labex/project/output/table-schema.txt

記録には実行時メッセージも含まれる場合があります。重要なのは、7列すべての名前と型を示すスキーマの行です。テーブル定義はメタデータであり、保存されたファイルをどう解釈するかを Hive に伝えます。次の実験では、この対応付けを自分で作ります。

最初の支払い済み注文を取得するクエリを保存する

このステップでは、確認チームに必要な列と支払い済みの行だけを、予測可能な順番で選びます。

クエリには、互いに独立した複数の絞り込み方法があります。

句 今回の目的
SELECT 出力する列を選ぶ
FROM 元のテーブルを選ぶ
WHERE 条件が真の行を残す
ORDER BY 結果を明示的に並べ替える
LIMIT 指定した数を上限として行を返す

order_id、order_status、quantity を取得し、paid の行だけを残し、注文 ID で並べ替えて最初の2件を返します。残る行を予想してください。提供された6注文のうち、その順番で最初の支払い済み ID は o1 と o2 です。

確認や再実行ができるよう、SQL をローカルファイルに保存します。次のシェルコマンドの cat > file <<'SQL' は、ヒアドキュメントを始めます。閉じる SQL までの行を、そのままファイルに書き込みます。中身はシェルコマンドではなく SQL テキストです。区切り行も含め、ブロック全体をコピーしてください。

cat > /home/labex/project/queries/first-query.sql <<'SQL'
USE retail_intro;
SELECT order_id, order_status, quantity
FROM orders
WHERE order_status = 'paid'
ORDER BY order_id
LIMIT 2;
SQL

SQL 内で引用符の付いた 'paid' はテキスト値です。= は各行の状態をその値と比較し、新しい状態を代入するわけではありません。USE 文により、ファイルは以前のクライアントセッションに依存しなくなります。

Beeline の -f は、ローカルの SQL ファイルを読みます。先ほど学んだテキスト形式のオプションでファイルを実行し、出力を保存します。

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex --silent=true --showHeader=false --outputformat=tsv2 -f /home/labex/project/queries/first-query.sql > /home/labex/project/output/first-query.txt

保存した記録を読みます。

cat /home/labex/project/output/first-query.txt

結果の行は次のようになるはずです。

o1 paid 2
o2 paid 1

前後の実行時メッセージは注文の記録ではありません。LIMIT 2 は任意の2行という意味ではなく、明示した並び順が、条件に合うどの行を先に返すかを決めています。チームの疑問に対して、再利用できるクエリファイルと確認できる結果ができました。

条件を1つ変えた効果を予想する

このステップでは、状態の条件だけを変え、返される行が予想と一致するか確かめます。

支払い済み注文のクエリはそのまま残してください。同じ表には、数量 1 の pending 注文 o3 があります。状態の条件を paid から pending に変えると、上限2件で何行が返るでしょうか? 上限は最大数なので、答えは1行です。

その条件だけを変え、同じクエリを書きます。

cat > /home/labex/project/queries/pending-query.sql <<'SQL'
USE retail_intro;
SELECT order_id, order_status, quantity
FROM orders
WHERE order_status = 'pending'
ORDER BY order_id
LIMIT 2;
SQL

独立して実行します。

beeline -u 'jdbc:hive2://localhost:10000/default' -n labex --silent=true --showHeader=false --outputformat=tsv2 -f /home/labex/project/queries/pending-query.sql > /home/labex/project/output/pending-query.txt

保存した結果を読みます。

cat /home/labex/project/output/pending-query.txt

注文の行は次の1行だけのはずです。

o3 pending 1

フィルターを変えることで、保存済みの記録を変更せずに別の行を選べました。同じ基本的なクエリ構造で、2つの疑問に答えられました。次は、準備済みの表に頼る代わりに、既存の CSV ファイルをテーブル定義に結び付けます。

まとめ

ファイルからテーブル、クエリへという流れの中で Hive の役割を理解し、Beeline で接続して、データベース、テーブル、スキーマを調べました。列の選択、フィルター、明示的な並べ替え、行数の上限を使った再利用可能な SQL ファイルを書き、条件を1つ変えた結果を予想して確認しました。

最初の体験では表が準備されていました。次の実験では、CSV ファイルを自分の外部テーブルに対応付け、メタデータと元のファイルの関係を学びます。