web-dev-qa-db-ja.com

Hiveのテーブルのパーティション化とバケット化の違いは何ですか?

私は両方がテーブルの列で実行されることを知っていますが、各操作はどのように異なっています。

116
NishM

パーティショニングデータは、負荷を水平に分散するためによく使用されます。これにはパフォーマンス上の利点があり、データを論理的に整理するのに役立ちます。 :大きなemployeeテーブルを扱っており、結果を特定の国または部門に制限するWHERE句を含むクエリを頻繁に実行する場合より高速なクエリ応答のために、HiveテーブルはPARTITIONED BY (country STRING, DEPT STRING)にできます。テーブルのパーティション分割により、Hiveがデータストレージを構造化する方法が変更され、Hiveはパーティション構造を反映するサブディレクトリを作成します。

.../employees /country = ABC/DEPT = XYZ

country=ABCからの従業員のクエリ制限がある場合、1つのディレクトリcountry=ABCの内容のみをスキャンします。これにより、クエリのパフォーマンスが劇的に向上しますが、これは、パーティションスキームが一般的なフィルタリングを反映している場合のみです。パーティション機能はHiveで非常に役立ちますが、作成するパーティションが多すぎると、一部のクエリが最適化される場合がありますが、他の重要なクエリには有害です。その他の欠点は、パーティションが多すぎることです。ファイルシステムのすべてのメタデータをメモリに保持する必要があるため、不必要に作成される多数のHadoopファイルとディレクトリとNameNodeのオーバーヘッドです。

バケッティングは、データセットをより管理しやすい部分に分解するための別の手法です。たとえば、dateを最上位パーティションとして使用し、employee_idを第2レベルのパーティションとして使用するテーブルが、非常に多くの小さなパーティションにつながるとします。代わりに、従業員テーブルをバケットし、employee_idをバケット列として使用すると、この列の値はユーザー定義の数値によってバケットにハッシュされます。同じemployee_idを持つレコードは常に同じバケットに保存されます。 employee_idの数がバケットの数よりはるかに大きいと仮定すると、各バケットには多くのemployee_idが含まれます。テーブルを作成するときに、CLUSTERED BY (employee_id) INTO XX BUCKETS;のように指定できます。XXはバケットの数です。バケットにはいくつかの利点があります。バケットの数は固定されているため、データで変動しません。 2つのテーブルがemployee_idによってバケット化されている場合、Hiveは論理的に正しいサンプリングを作成できます。バケット化は、効率的なマップ側の結合などの実行にも役立ちます。

229
Navneet Kumar

前の説明にはいくつかの詳細が欠けています。パーティション化とバケット化の仕組みをよりよく理解するには、Hiveでのデータの保存方法を確認する必要があります。テーブルがあるとしましょう

CREATE TABLE mytable ( 
         name string,
         city string,
         employee_id int ) 
PARTITIONED BY (year STRING, month STRING, day STRING) 
CLUSTERED BY (employee_id) INTO 256 BUCKETS

hiveはデータを次のようなディレクトリ階層に保存します

/user/Hive/warehouse/mytable/y=2015/m=12/d=02

したがって、パーティションを作成するときは注意する必要があります。たとえば、employee_idでパーティションを作成し、数百万人の従業員がいる場合、ファイルシステムに数百万のディレクトリがあることになります。 「カーディナリティ」という用語は、フィールドが持つことのできる値の数を指します。たとえば、「国」フィールドがある場合、世界の国は約300なので、カーディナリティーは約300になります。ミリ秒ごとに変化する「timestamp_ms」のようなフィールドの場合、カーディナリティは数十億になる可能性があります。一般に、パーティション化するフィールドを選択する場合、カーディナリティが高くなるべきではありません。ファイルシステム内のディレクトリが多すぎるためです。

一方、クラスタリング(別名バケット)では、バケットの数を指定するため、ファイルの数が固定されます。 Hiveは、フィールドを取得してハッシュを計算し、そのバケットにレコードを割り当てます。しかし、256個のバケットを使用し、バケットを作成するフィールドのカーディナリティが低い場合(たとえば、米国の州なので、50個の異なる値しか使用できない場合)はどうなりますか?データを含む50個のバケットと、データを含まない206個のバケットがあります。

誰かが、パーティションがクエリ対象のデータ量を劇的に削減する方法について既に述べました。したがって、私の例の表では、特定の日付以降のみをクエリする場合、年/月/日ごとのパーティション分割によりIOの量が劇的に削減されます。私は誰かがバケツが他のテーブルとの結合を高速化する方法についても言及したと思うと思いますそれはまったく同じバケティングを持っていますです。バケットごとにバケットを結合します(すでにソートされている部分をマージソートするため、従業員が既にemployee_idでソートされている場合はさらに良いです。これは、別名O(n)で動作します)。

そのため、フィールドのカーディナリティが高く、データがバケット間で均等に分散されている場合、バケットはうまく機能します。パーティション化フィールドのカーディナリティが高すぎない場合、パーティション化が最適に機能します。

また、複数のフィールドでパーティション化できます、順序付き(年/月/日が良い例です)、1つのフィールドのみでバケット化できます

118
Roberto Congiu

私はこの質問に答えるのに遅れていると思いますが、それは私のフィードで増え続けています。

Navneetは優れた答えを提供してくれました。視覚的に追加します。

パーティション化は、WHERE句で使用される場合、データの排除に役立ちます。バケット化は、各パーティションのデータを複数のファイルに整理するのに役立ち、同じデータセットが常に同じバケットに書き込まれます。列の結合に大いに役立ちます。

Name、server_date、some_col3、some_col4、およびsome_col5の5つの列を持つテーブルがあるとします。 server_dateでテーブルをパーティション化し、10バケットのnameカラムでバケット化すると、ファイル構造は次のようになります。

  1. server_date = xyz
    • 00000_0
    • 00001_0
    • 00002_0
    • ........
    • 00010_0

ここで、server_date = xyzはパーティションであり、ファイルは各パーティションのバケットです。バケットはいくつかのハッシュ関数に基づいて計算されるため、name = Sandyの行は常に同じバケットに入れられます。

18
Priyesh

Hive Partitioning:

パーティションは、テーブル列の値に基づいて大量のデータを複数のスライスに分割します。

196か国以上に散らばる世界中の人々の情報を保存しており、約500キロのエントリがあるとします。特定の国(バチカン市国)の人々にクエリを行いたい場合、パーティションがない場合は、500エントリすべてをスキャンして、国のエントリを取得する必要があります。国に基づいてテーブルをパーティション分割する場合、1つの国パーティションのみのデータをチェックするだけで、クエリプロセスを微調整できます。 Hiveパーティションは、列の値用に個別のディレクトリを作成します。

長所:

  1. 実行負荷を水平に分散する
  2. データ量が少ないパーティションの場合、クエリの実行が高速化されます。例えば「バチカン市国」から人口を取得すると、世界の人口全体を検索する代わりに非常に高速に戻ります。

短所:

  1. 小さすぎるパーティションを作成する可能性-ディレクトリが多すぎる。
  2. 特定のパーティションの少量のデータに効果的です。ただし、大量のデータに対するグループ化などの一部のクエリは、実行に時間がかかります。例えば中国の人口のグループ化は、バチカン市国の人口のグループ化と比較して長い時間がかかります。特定のパーティション値にデータが偏っている場合、パーティションは応答性の問題を解決しません。

ハイブバケット:

バケット化は、データをより管理しやすい、または同等の部分に分解します。

パーティション化では、列の値に基づいて複数の小さなパーティションを作成できる可能性があります。バケットに行く場合、データを保存するバケットの数を制限しています。この番号は、テーブル作成スクリプト中に定義されます。

長所

  1. 各パーティションのデータ量が等しいため、マップ側での結合はより高速になります。
  2. パーティショニングのような高速なクエリ応答

Cons

  1. テーブルの作成中にバケットの数を定義できますが、同量のデータのロードはプログラマーが手動で行う必要があります。
14
Ravindra babu

違いはbucketingは列名でファイルを分割し、partitioningはテーブル内の特定の値でファイルを分割します

うまくいけば、正しく定義した

6
uriya harel

Bucketingに入る前に、Partitioningとは何かを理解する必要があります。下の表を例としてみましょう。以下の例では、初心者レベルの理解のために12個のレコードのみを指定していることに注意してください。リアルタイムシナリオでは、数百万のレコードがある場合があります。

enter image description here



パーティショニング
---------------------
Partitioningは、データのクエリ中にパフォーマンスを取得するために使用されます。たとえば、上記の表で以下のsqlを記述する場合、表内のすべてのレコードをスキャンする必要があるため、パフォーマンスが低下し、オーバーヘッドが増加します。

select * from sales_table where product_id='P1'

テーブル全体のスキャンを回避し、product_id='P1'に関連するレコードのみを読み取るために、product_id列に基づいて複数のファイルにパーティション分割(Hiveテーブルのファイルを分割)できます。これにより、Hiveテーブルのファイルは、product_id='P1'product_id='P2'の2つのファイルに分割されます。上記のクエリを実行すると、product_id='P1'ファイルのみがスキャンされます。

../Hive/warehouse/sales_table/product_id=P1
../Hive/warehouse/sales_table/product_id=P2

パーティションを作成するための構文は次のとおりです。以下の構文では、product_id列定義をパーティション化されていない列と一緒に使用しないでください。これは、partitioned by句にのみ含める必要があります。

create table sales_table(sales_id int,trans_date date, amount int) 
partitioned by (product_id varchar(10))

短所:パーティションを作成する際は非常に注意する必要があります。つまり、繰り返し値の数が非常に少ない列(特に主キー列)には使用しないでください。パーティション化されたファイルの数が増加し、Name nodeのオーバーヘッドが増加します。



バケット
------------------
Bucketingは、パーティションセクションで説明したconsを克服するために使用されます。これは、列に反復値が非常に少ない場合に使用する必要があります(例-主キー列)。これは、RDBMSの主キー列のインデックスの概念に似ています。この表では、バケットにSales_Id列を使用できます。 sales_id列を照会する必要がある場合に役立ちます。

バケットの構文は次のとおりです。

create table sales_table(sales_id int,trans_date date, amount int) 
partitioned by (product_id varchar(10)) Clustered by(Sales_Id) into 3 buckets

ここでは、パーティションの上にさらにいくつかのファイルにデータを分割します。

enter image description here

3バケットを指定したため、product_idごとに3つのファイルに分割されます。内部でmodulo operatorを使用して、各sales_idをどのバケットに保存するかを決定します。たとえば、product_id='P1'の場合、sales_id=1000001_0ファイル(つまり、1%3 = 1)に格納され、sales_id=2000002_0に格納されますファイル(2%3 = 2)、sales_id=3000000_0ファイル(3%3 = 0)などに保存されます。

2
Sarath Avanavu

以下の理由により、Hiveテーブルでパーティションを使用することを強くお勧めします-

  • Hiveテーブルへの挿入は高速になるはずです(複数のスレッドを使用してパーティションにデータを書き込むため)
  • Hiveテーブルからのクエリは、低レイテンシで効率的でなければなりません。

例:-

入力ファイル(100 GB)がtemp-Hive-tableにロードされ、さまざまな地域の銀行データが含まれているとします。

パーティションのないハイブテーブル

Insert into Hive table Select * from temp-Hive-table

/Hive-table-path/part-00000-1  (part size ~ hdfs block size)
/Hive-table-path/part-00000-2
....
/Hive-table-path/part-00000-n

このアプローチの問題は、このテーブルで実行するクエリのデータ全体をスキャンすることです。パーティショニングとバケット化が使用される他のアプローチと比較して、応答時間は長くなります。

パーティションのあるハイブテーブル

Insert into Hive table partition(country) Select * from temp-Hive-table

/Hive-table-path/country=US/part-00000-1       (file size ~ 10 GB)
/Hive-table-path/country=Canada/part-00000-2   (file size ~ 20 GB)
....
/Hive-table-path/country=UK/part-00000-n       (file size ~ 5 GB)

長所-ここでは、特定の地理トランザクションのデータを照会する場合に、データにすばやくアクセスできます。短所-各パーティション内でデータを分割することにより、データの挿入/クエリをさらに改善できます。以下のバケットオプションを参照してください。

パーティションとバケットのあるハイブテーブル

注:「CLUSTERED BY(Partiton_Column)」を使用して、5つのバケットにHiveテーブルを作成します。

Insert into Hive table partition(country) Select * from temp-Hive-table

/Hive-table-path/country=US/part-00000-1       (file size ~ 2 GB)
/Hive-table-path/country=US/part-00000-2       (file size ~ 2 GB)
/Hive-table-path/country=US/part-00000-3       (file size ~ 2 GB)
/Hive-table-path/country=US/part-00000-4       (file size ~ 2 GB)
/Hive-table-path/country=US/part-00000-5       (file size ~ 2 GB)

/Hive-table-path/country=Canada/part-00000-1   (file size ~ 4 GB)
/Hive-table-path/country=Canada/part-00000-2   (file size ~ 4 GB)
/Hive-table-path/country=Canada/part-00000-3   (file size ~ 4 GB)
/Hive-table-path/country=Canada/part-00000-4   (file size ~ 4 GB)
/Hive-table-path/country=Canada/part-00000-5   (file size ~ 4 GB)

....
/Hive-table-path/country=UK/part-00000-1       (file size ~ 1 GB)
/Hive-table-path/country=UK/part-00000-2       (file size ~ 1 GB)
/Hive-table-path/country=UK/part-00000-3       (file size ~ 1 GB)
/Hive-table-path/country=UK/part-00000-4       (file size ~ 1 GB)
/Hive-table-path/country=UK/part-00000-5       (file size ~ 1 GB)

長所-より高速な挿入。より高速なクエリ。

短所-バケットを作成すると、より多くのファイルが作成されます。特定のケースでは、多くの小さなファイルに問題がある可能性があります

これが役立つことを願っています!!

0
NoName

ここには素晴らしい反応があります。パーティションとバケットの違いを覚えておくために、できるだけ短くしたいと思います。

通常、一意性の低い列でパーティション分割します。また、一意性の最も高い列でバケット化します。

例として、国、個人名、およびバイオメトリックIDを持つ世界人口を検討する場合の例。ご想像のとおり、国フィールドは一意性の低い列であり、バイオメトリックIDは最も一意性の高い列です。したがって、理想的には、国ごとにテーブルを分割し、バイオメトリックIDごとにバケット化する必要があります。

0
SVK