私は両方がテーブルの列で実行されることを知っていますが、各操作はどのように異なっています。
パーティショニングデータは、負荷を水平に分散するためによく使用されます。これにはパフォーマンス上の利点があり、データを論理的に整理するのに役立ちます。 例:大きな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は論理的に正しいサンプリングを作成できます。バケット化は、効率的なマップ側の結合などの実行にも役立ちます。
前の説明にはいくつかの詳細が欠けています。パーティション化とバケット化の仕組みをよりよく理解するには、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つのフィールドのみでバケット化できます。
私はこの質問に答えるのに遅れていると思いますが、それは私のフィードで増え続けています。
Navneetは優れた答えを提供してくれました。視覚的に追加します。
パーティション化は、WHERE句で使用される場合、データの排除に役立ちます。バケット化は、各パーティションのデータを複数のファイルに整理するのに役立ち、同じデータセットが常に同じバケットに書き込まれます。列の結合に大いに役立ちます。
Name、server_date、some_col3、some_col4、およびsome_col5の5つの列を持つテーブルがあるとします。 server_dateでテーブルをパーティション化し、10バケットのnameカラムでバケット化すると、ファイル構造は次のようになります。
ここで、server_date = xyzはパーティションであり、ファイルは各パーティションのバケットです。バケットはいくつかのハッシュ関数に基づいて計算されるため、name = Sandyの行は常に同じバケットに入れられます。
Hive Partitioning:
パーティションは、テーブル列の値に基づいて大量のデータを複数のスライスに分割します。
196か国以上に散らばる世界中の人々の情報を保存しており、約500キロのエントリがあるとします。特定の国(バチカン市国)の人々にクエリを行いたい場合、パーティションがない場合は、500エントリすべてをスキャンして、国のエントリを取得する必要があります。国に基づいてテーブルをパーティション分割する場合、1つの国パーティションのみのデータをチェックするだけで、クエリプロセスを微調整できます。 Hiveパーティションは、列の値用に個別のディレクトリを作成します。
長所:
短所:
ハイブバケット:
バケット化は、データをより管理しやすい、または同等の部分に分解します。
パーティション化では、列の値に基づいて複数の小さなパーティションを作成できる可能性があります。バケットに行く場合、データを保存するバケットの数を制限しています。この番号は、テーブル作成スクリプト中に定義されます。
長所
Cons
違いはbucketingは列名でファイルを分割し、partitioningはテーブル内の特定の値でファイルを分割します
うまくいけば、正しく定義した
Bucketing
に入る前に、Partitioning
とは何かを理解する必要があります。下の表を例としてみましょう。以下の例では、初心者レベルの理解のために12個のレコードのみを指定していることに注意してください。リアルタイムシナリオでは、数百万のレコードがある場合があります。
パーティショニング
---------------------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
ここでは、パーティションの上にさらにいくつかのファイルにデータを分割します。
3
バケットを指定したため、product_id
ごとに3つのファイルに分割されます。内部でmodulo operator
を使用して、各sales_id
をどのバケットに保存するかを決定します。たとえば、product_id='P1'
の場合、sales_id=1
は000001_0ファイル(つまり、1%3 = 1)に格納され、sales_id=2
は000002_0に格納されますファイル(2%3 = 2)、sales_id=3
は000000_0ファイル(3%3 = 0)などに保存されます。
以下の理由により、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)
長所-より高速な挿入。より高速なクエリ。
短所-バケットを作成すると、より多くのファイルが作成されます。特定のケースでは、多くの小さなファイルに問題がある可能性があります
これが役立つことを願っています!!
ここには素晴らしい反応があります。パーティションとバケットの違いを覚えておくために、できるだけ短くしたいと思います。
通常、一意性の低い列でパーティション分割します。また、一意性の最も高い列でバケット化します。
例として、国、個人名、およびバイオメトリックIDを持つ世界人口を検討する場合の例。ご想像のとおり、国フィールドは一意性の低い列であり、バイオメトリックIDは最も一意性の高い列です。したがって、理想的には、国ごとにテーブルを分割し、バイオメトリックIDごとにバケット化する必要があります。