Hive パーティションとバケットの例
⚡ スマートサマリー
Apache Hiveでは、パーティションとバケットという2つの方法でテーブルデータをディスク上で分割します。パーティションはキー値ごとに1つのディレクトリを作成し、バケットは行をハッシュ化して固定数のファイルに格納します。
テーブル、パーティション、バケットは、Hiveのデータモデリングを構成する要素です。テーブルはスキーマを定義し、パーティションはそのテーブルをディスク上のディレクトリに分割し、バケットはディレクトリ内のデータを固定数のファイルに分割します。
パーティションとは何ですか?
Hive Partitionsは、パーティションキーに基づいてテーブルを異なる部分に分割することで、テーブルをパーティションに整理する方法です。物理的には、各パーティションはHDFSのテーブルフォルダの下にある個別のサブディレクトリであり、これによりHiveは不要なデータをスキップすることができます。
テーブルに1つ以上のパーティションキーがある場合、パーティション機能は役立ちます。パーティションキーは、テーブル内でデータがどのように格納されるかを決定するための基本要素です。パーティションキーはデータファイル自体には格納されず、その値はディレクトリ名にエンコードされるため、そのキーでフィルタリングするクエリでは、行が読み込まれる前にディレクトリ全体を破棄することができます。これをパーティションプルーニングと呼びます。
例えば: -
「クライアントは、インド国内の事業に関するEコマースデータを保有しており、そのデータには各州(38州)の事業がまとめて記載されています。州列をパーティションキーとして、インド全体のデータに対してパーティション分割を実行すると、インドの州数(38)と同じ数のパーティション(38個)が得られます。これにより、各州のデータをパーティションテーブル内で個別に表示できます。」
サンプル Code パーティションのスニペット
以下の6つのステートメントは、Hiveシェルで順番に実行されます。それぞれが独立したステップであり、続くスクリーンショットは、実際のクラスタで同じシーケンスが実行されている様子を示しています。
- テーブル allstates の作成
create table allstates(state string, District string,Enrolments string) row format delimited fields terminated by ',';
- 作成したテーブル allstates にデータをロードします
Load data local inpath '/home/hduser/Desktop/AllStates.csv' into table allstates;
- パーティションテーブルの作成
create table state_part(District string,Enrolments string) PARTITIONED BY(state string);
- パーティションの場合、このプロパティを設定する必要があります
set hive.exec.dynamic.partition.mode=nonstrict - パーティションテーブルへのデータのロード
INSERT OVERWRITE TABLE state_part PARTITION(state) SELECT district,enrolments,state from allstates;
- パーティションキーとしての状態に基づいた実際の処理とパーティションテーブルの形成
HDFSストレージには、ファイル名が状態名となるパーティション出力が38個作成されます。このステップでは、これを確認します。
以下のスクリーンショットは、上記コードの実行結果を示しています。
最初の画面では、ステップ 1 が実行されます。 ハイブ> プロンプトを作成し、 オールステーツ 3つの列とフィールド区切り文字としてカンマを持つ表。
次の画面では手順2と3について説明します。AllStates.csvファイルが読み込まれ、 オールステーツパーティションテーブル 状態部分 パーティションキーとして宣言された状態を使用して作成されます。
ステップ4と5が次に表示されます。動的パーティションモードは非厳格に設定され、INSERT OVERWRITEステートメントによってMapReduceジョブが起動されます。そのログ行には、各状態値に対して1つのパーティションがロードされていることが示されます。
HDFS 内のウェアハウス ディレクトリを一覧表示すると、ステップ 6 の結果が確認できます。シェルは 38 個のアイテムを報告し、1 つのアイテムを報告します。 state_part/state= 州ごとのディレクトリ。
上記のコードから、次のことを行います
- 「州」「地区」「登録者数」などの3つの列名を持つテーブル「allstates」を作成します。
- テーブル allstates にデータをロードしています
- 状態をパーティションキーとして使用するパーティションテーブルの作成
- この手順では、パーティションモードを非厳格に設定します(このモードでは動的パーティションモードが有効になります)。
- パーティションテーブル state_part にデータをロードしています
- パーティションキーとしての状態に基づいた実際の処理とパーティションテーブルの形成
- HDFSストレージには、ファイル名が状態名となるパーティション出力が38個作成されます。このステップでは、HDFS内の38個のパーティション出力を確認します。
Hiveにおける静的パーティショニングと動的パーティショニング
上記の例では動的パーティショニングを使用していますが、Hive は 2 つのロード スタイルをサポートしており、その違いによって、どれだけの ty を使用するかが決まります。ping そして、それぞれの荷物がどれだけのリスクを伴うか。
静的パーティショニング ステートメント自体にパーティション値を指定するため、ロードを実行する前にその値を把握しておく必要があり、1つのステートメントは正確に1つのパーティションを埋めます。 動的パーティショニング これにより、HiveはSELECTリストの最後の列からパーティション値を読み取り、実行時にディレクトリを作成します。そのため、この例ではINSERTを1回実行するだけで38個のディレクトリを作成できます。
| 側面 | 静的パーティショニング | 動的パーティショニング |
|---|---|---|
| パーティション値 | PARTITION条項に手渡しで記載 | 実行時にSELECT列から読み込む |
| ステートメントごとのパーティション数 | 1 | その他にもたくさんのグーグルの |
| デフォルトの厳格モードで動作します | hive.exec.dynamic.partition.mode を nonstrict に設定する必要があります | |
| 負荷速度 | 値のスキャンが不要なため、より高速です。 | ジョブが行をキーごとにグループ化するため、処理速度が遅くなります。 |
| に最適 | 日々の負荷など、小さく既知のセット | 38州などの大規模または未知のキーセット |
動的負荷にも上限があります。Hive では、1 つのジョブが作成できるパーティションの数に制限があり、デフォルトではマッパーまたはリデューサーごとに 100、ステートメント全体で 1000 となっています。いずれかの上限を超えるとジョブは失敗するため、カーディナリティが非常に高いキーを使用する場合は、これらの制限を引き上げるか、別の設計を検討する必要があります。
バケットとは何ですか?
Hiveのバケットは、Hiveテーブルのデータを複数のファイルまたはディレクトリに分割するために使用されます。バケットは効率的なクエリ処理に役立ち、パーティションとは異なり、テーブル作成時にバケット数が固定されるため、データ量の増加に伴ってバケット数が増大することはありません。
- これらのパーティションに存在するデータは、さらにバケットに分割することができます。
- 分割は、テーブル内で選択した特定の列のハッシュに基づいて実行されます。
- バケットはバックエンドで何らかのハッシュアルゴリズムを使用して各レコードを読み取り、バケットに配置します。
- 列がどのバケットに入るかは、 hash_function(bucketing_column) mod num_buckets同じ値は常に同じファイルに保存される
- Hive 0.x および 1.x では、バケット化を有効にするには、 hive.enforce.bucketing=true を設定します。 挿入前に
最後の設定は、現在のクラスターでは履歴として扱われます。 Apache Hiveのマニュアル Hive 2.x以降では、エンジンがテーブル定義からリデューサー数とクラスタリング列を自動的に選択するため、この設定は不要です。
ステップ1) 以下のようにバケットを作成します。
下の画面は、CREATE TABLE ステートメントを示しています。 サンプルバケット下部の CLUSTERED BY 句でバケット数を固定します。
上のスクリーンショットより
- first_name、job_id、department、salary、countryなどの列名を持つサンプルバケットを作成しています。
- ここでは4つのバケットを作成しています
- データが読み込まれると、自動的に4つのバケットにデータが振り分けられます。
- 国列はクラスタリング列であるため、1つの国に関するすべての行は同じバケットファイルに書き込まれます。
ステップ2) データをテーブル samplebucket にロードしています
Hiveシステムに「employees」テーブルが既に作成されていることを前提として、このステップではemployeesテーブルからsamplebucketテーブルへのデータのロードを見ていきます。
従業員データをバケットに移動する前に、データにfirst_name、job_id、department、salary、countryなどの列名が含まれていることを確認してください。
ここでは、employeesテーブルからsamplebucketにデータをロードしています。下の画面は、コピーを実行するINSERT OVERWRITEステートメントを示しています。
ステップ3) ステップ1で作成した4つのバケットを表示します。
HDFS内のテーブルディレクトリを一覧表示すると、物理的な結果として、1つのデータファイルではなく、4つの番号付きデータファイルが表示されます。
上記のスクリーンショットから、従業員テーブルのデータがステップ1で作成された4つのバケットに転送されていることがわかります。
Hiveのパーティショニングとバケット化:主な違い
どちらの機能もテーブルをより小さな断片に分割しますが、ファイルシステムの異なるレベルで分割を行い、異なる問題に対応します。以下の表は、それらを並べて比較したものです。
| 比較のポイント | パーティショニング | バケット |
|---|---|---|
| ユニットが作成されました | キー値ごとのディレクトリ | ハッシュバケットごとに1つのファイル |
| 宣言済み | 分割基準 | …によってn個のバケットにグループ化されます |
| 個数 | 異なる値の数に応じて増加する | テーブル作成時に修正 |
| データファイルに保存されている列 | いいえ、値はディレクトリ名の中にあります | はい、列は通常の列のままです |
| 最適な列タイプ | 州、年、国などのカーディナリティの低い要素 | ユーザーIDやトランザクションIDなど、カーディナリティの高いもの |
| 主なメリット | パーティションの整理により、不要なディレクトリがスキップされます。 | ファイルサイズが均一で、サンプリングコストが低く、マップ側で結合できる |
この2つは競合関係にありません。一般的な運用レイアウトでは、ファクトテーブルを日付で分割し、結合キーに基づいて各日をバケットに分割します。そのため、クエリはまず1つのディレクトリに絞り込み、そのディレクトリ内でバケット間を結合します。
パーティショニング、バケット化、またはその両方を使用するタイミング
どちらを選択するかは、まず列のカーディナリティと、テーブルを読み取るクエリの構造によって決まります。
- パーティション クエリがほぼ常に同じ低カーディナリティ列でフィルタリングされ、一意の値の数が数百万ではなく数百にとどまる場合
- バケット 有用な列にディレクトリとして扱うには多すぎる一意の値がある場合、またはその列でテーブルが繰り返し結合またはサンプリングされる場合
- 両方を使う 大規模なファクトテーブルの場合:日付でパーティションを作成し、各パーティション内で結合キーに基づいてバケットを作成します。
注意すべき障害モードは、小ファイル問題です。タイムスタンプや顧客識別子など、カーディナリティが非常に高い列でパーティショニングを行うと、HDFSブロックサイズをはるかに下回るファイルを格納する小さなディレクトリが数千個生成されます。これによりNameNodeのメモリが膨張し、スキャン速度が低下します。これはまさにパーティショニングの目的である問題です。バケット化では、ファイル数がテーブル定義によって制限されるため、この問題を回避できます。
バケット化には注意点があります。レイアウトが正しく機能するのは、すべての書き込み処理がそのレイアウトを遵守する場合に限られます。作成時に宣言されるバケット数はメタデータであるため、正しくクラスタリングせずにテーブルに書き込むジョブは、宣言されたレイアウトと一致しないファイルを残す可能性があり、後続のサンプリングやバケット結合で誤った行が読み取られることになります。








