web-dev-qa-db-ja.com

Hiveクラスターby vs order by vs sort by

私が理解する限りでは;

  • レデューサーでのみソートする

  • グローバルに注文するが、すべてを1つのレデューサーに押し込む

  • クラスターは、キーハッシュによってリデューサーに素材をインテリジェントに分散し、並べ替えを行います

だから私の質問は、クラスターによってグローバルな順序を保証することですか?によって同じキーを同じリデューサーに配置しますが、隣接するキーはどうですか?

これで見つけることができる唯一のドキュメントは here であり、例からはグローバルに注文されているようです。しかし、定義から、私はそれが常にそうするとは限らないと感じています。

51
cashmere

短い答え:はい、CLUSTER BYは、複数の出力ファイルを自分で結合しても構わないという条件で、グローバルな順序付けを保証します。

長いバージョン:

  • ORDER BY x:グローバルな順序付けを保証しますが、1つのレデューサーのみですべてのデータをプッシュすることでこれを行います。これは、大規模なデータセットでは基本的に受け入れられません。出力として1つのソートされたファイルになります。
  • SORT BY x:N個の減速機のそれぞれでデータを順序付けますが、各減速機は重複する範囲のデータを受信できます。結果として、範囲が重複するN個以上のソートされたファイルになります。
  • DISTRIBUTE BY x:N個のレデューサーのそれぞれがxの重複しない範囲を取得することを保証しますが、各レデューサーの出力をソートしません。範囲が重複しないN個以上のソートされていないファイルになります。
  • CLUSTER BY x:N個のレデューサーのそれぞれが重複しない範囲を取得し、レデューサーでそれらの範囲でソートするようにします。これにより、グローバルな順序付けが可能になり、(DISTRIBUTE BY xおよびSORT BY x)と同じです。範囲が重複しないN個以上のソートされたファイルになります。

理にかなっていますか?したがって、CLUSTER BYは基本的にORDER BYのよりスケーラブルなバージョンです。

142
Lars Yencken

最初に明確にします:clustered byは鍵を異なるバケットにのみ配布します、clustered by ... sorted byバケットをソートして取得します。

簡単な実験(下記を参照)を使用すると、デフォルトではグローバルオーダーを取得できないことがわかります。その理由は、デフォルトのパーティショナーは、実際のキーの順序に関係なく、ハッシュコードを使用してキーを分割するためです。

ただし、データを完全に注文できます。

動機は、Tom Whiteによる「Hadoop:The Definitive Guide」(第3版、第8章、274ページ、Total Sort)で、TotalOrderPartitionerについて説明しています。

最初にTotalOrderingの質問に答えてから、私が行ったいくつかのソート関連のHive実験について説明します。

ここで説明しているのは「概念実証」であり、ClauderaのCDH3ディストリビューションを使用して1つの例を処理することができました。

当初は、org.Apache.hadoop.mapred.lib.TotalOrderPartitionerがトリックを行うことを望んでいました。残念ながら、キーではなく、値によるHiveパーティションのように見えるため、そうではありませんでした。そこでパッチを適用します(サブクラスが必要ですが、その時間はありません):

交換

public int getPartition(K key, V value, int numPartitions) {
    return partitions.findPartition(key);
}

public int getPartition(K key, V value, int numPartitions) {
    return partitions.findPartition(value);
}

これで、TotalOrderPartitionerをHiveパーティショナーとして設定(パッチを適用)できます。

Hive> set Hive.mapred.partitioner=org.Apache.hadoop.mapred.lib.TotalOrderPartitioner;

Hive> set total.order.partitioner.natural.order=false

Hive> set total.order.partitioner.path=/user/yevgen/out_data2

私も使った

Hive> set Hive.enforce.bucketing = true; 

Hive> set mapred.reduce.tasks=4;

私のテストで。

ファイルout_data2は、TotalOrderPartitionerに値をバケットする方法を指示します。データをサンプリングしてout_data2を生成します。テストでは、0〜10の4つのバケットとキーを使用しました。アドホックアプローチを使用してout_data2を生成しました。

import org.Apache.hadoop.util.ToolRunner;
import org.Apache.hadoop.util.Tool;
import org.Apache.hadoop.conf.Configured;
import org.Apache.hadoop.fs.Path;
import org.Apache.hadoop.io.NullWritable;
import org.Apache.hadoop.io.SequenceFile;
import org.Apache.hadoop.Hive.ql.io.HiveKey;
import org.Apache.hadoop.fs.FileSystem;


public class TotalPartitioner extends Configured implements Tool{
    public static void main(String[] args) throws Exception{
            ToolRunner.run(new TotalPartitioner(), args);
    }

    @Override
    public int run(String[] args) throws Exception {
        Path partFile = new Path("/home/yevgen/out_data2");
        FileSystem fs = FileSystem.getLocal(getConf());

        HiveKey key = new HiveKey();
        NullWritable value = NullWritable.get();

        SequenceFile.Writer writer = SequenceFile.createWriter(fs, getConf(), partFile, HiveKey.class, NullWritable.class);
        key.set( new byte[]{1,3}, 0, 2);//partition at 3; 1 came from Hive -- do not know why
        writer.append(key, value);
        key.set( new byte[]{1, 6}, 0, 2);//partition at 6
        writer.append(key, value);
        key.set( new byte[]{1, 9}, 0, 2);//partition at 9
        writer.append(key, value);
        writer.close();
        return 0;
    }

}

次に、結果のout_data2をHDFSにコピーしました(/ user/yevgen/out_data2に)

これらの設定で、データをバケット化/ソートしました(実験リストの最後の項目を参照)。

これが私の実験です。

  • サンプルデータを作成する

    bash> echo -e "1\n3\n2\n4\n5\n7\n6\n8\n9\n0"> data.txt

  • 基本的なテストテーブルを作成します。

    Hive> create table test(x int); Hive>データローカルインパス 'data.txt'をテーブルテストに読み込みます。

基本的に、このテーブルには0〜9の値が順序なしで含まれています。

  • テーブルのコピーがどのように機能するかを示します(使用する削減タスクの最大数を設定するmapred.reduce.tasksパラメーターを実際に使用)

    Hive> create test2(x int);

    Hive> set mapred.reduce.tasks = 4;

    ハイブ>上書きテーブルtest2の挿入a.xを選択し、a.x = b.xでテストaを結合します。 -自明でないmap-reduceを強制する愚かな結合

    bash> hadoop fs -cat/user/Hive/warehouse/test2/000001_0

    1

    5

    9

  • バケツの実演。キーはソート順なしでランダムに割り当てられていることがわかります。

    Hive>(x)によって4つのバケットにクラスター化されたテーブルtest3(x int)を作成します。

    Hive> set Hive.enforce.bucketing = true;

    Hive> insert上書きテーブルtest3 select * from test;

    bash> hadoop fs -cat/user/Hive/warehouse/test3/000000_0

    4

    8

  • 並べ替えによるバケット。結果は完全にソートされているのではなく、部分的にソートされています

    Hive>(x)でクラスター化されたテーブルtest4(x int)を(x desc)でソートして4つのバケットに作成します。

    Hive> insert上書きテーブルtest4 select * from test;

    bash> hadoop fs -cat/user/Hive/warehouse/test4/000001_0

    1

    5

    9

値が昇順でソートされていることがわかります。 CDH3のHiveバグのように見えますか?

  • ステートメントによるクラスターなしで部分的にソートする:

    Hive>テーブルtest5を作成します。テストからxを選択し、xでソートx descでソートします。

    bash> hadoop fs -cat/user/Hive/warehouse/test5/000001_0

    9

    5

    1

  • パッチを適用したTotalOrderParitionerを使用します。

    Hive> set Hive.mapred.partitioner = org.Apache.hadoop.mapred.lib.TotalOrderPartitioner;

    Hive> set total.order.partitioner.natural.order = false

    Hive> set total.order.partitioner.path =/user/training/out_data2

    Hive>(x)でクラスター化されたテーブルtest6(x int)を(x)で4つのバケットにソートして作成します

    Hive> insert上書きテーブルtest6 select * from test;

    bash> hadoop fs -cat/user/Hive/warehouse/test6/000000_0

    1

    2

    bash> hadoop fs -cat/user/Hive/warehouse/test6/000001_0

    3

    4

    5

    bash> hadoop fs -cat/user/Hive/warehouse/test6/000002_0

    7

    6

    8

    bash> hadoop fs -cat/user/Hive/warehouse/test6/000003_0

    9

13

CLUSTER BYはグローバルな順序を生成しません。

(Lars Yenckenによる)受け入れられた答えは、レデューサーが重複しない範囲を受け取ると述べることによって誤解を招きます。 Anton ZaviriukhinはBucketedTablesのドキュメントを正しく示しているため、CLUSTER BYは基本的にDISTRIBUTE BY(バケット化と同じ)と各バケット/リデューサー内のSORT BYです。そしてDISTRIBUTE BYは単にハッシュとmodをバケットに入れ、ハッシュ関数 may は順序を維持します(i> jの場合、iのハッシュ> jのハッシュ)、ハッシュ値のmodはそうしません。

重複する範囲を示すより良い例です

http://myitlearnings.com/bucketing-in-Hive/

6
Edi Bice

私が理解しているように、短い答えはいいえです。範囲が重複することになります。

From SortBy documentation :「Cluster Byは、Distribute ByとSort Byの両方のショートカットです。」 「同じ列で分配するすべての行は、同じリデューサーに送られます。」ただし、重複しない範囲を保証して配布する情報はありません。

さらに、from DDL BucketedTables documentation :「Hiveはどのように行をバケットに分散しますか?一般に、バケット番号は式hash_function(bucketing_column)mod num_bucketsによって決定されます。」 SelectステートメントのCluster byは、主な用途がバケットテーブルにデータを入力するためであるため、同じ原則を使用してレデューサー間で行を分散すると考えられます。

1つの整数列「a」を持つテーブルを作成し、そこに0〜9の数字を挿入しました。

次に、リデューサーの数を2 set mapred.reduce.tasks = 2;に設定します。

Cluster by句を含むこのテーブルのselectデータselect * from my_tab cluster by a;

そして、私が期待した結果を受け取りました:

0
2
4
6
8
1
3
5
7
9

そのため、最初のレデューサー(数値0)は偶数になりました(モード2は0を与えるため)

2番目のレデューサー(番号1)が奇数になりました(モード2が1を与えるため)

これが「配布方法」の仕組みです。

そして、「並べ替え」は各レデューサー内の結果をソートします。

4

Cluster byは、リデューサーごとのソートはグローバルではありません。多くの本でも、誤ってまたは混乱して言及されています。具体的には、各部門を特定のレデューサーに配布し、各部門の従業員名でソートし、使用するクラスターの順番を気にせず、ワークロードがレデューサー間で分散されるにつれてパフォーマンスが向上するという特定の用途があります。

0
user3423890

SortBy:重複する範囲を持つN個以上のソート済みファイル。

OrderBy:単一の出力、つまり完全に注文済み。

Distribute By:N個のレデューサーを保護することにより、列の重複しない範囲を取得しますが、各レデューサーの出力は並べ替えません。

詳細情報 http://commandstech.com/Hive-sortby-vs-orderby-vs-distributeby-vs-clusterby/

ClusterBy:上記と同じ例を参照してください。ClusterBy xを使用する場合、2つのリデューサーはxの行をさらにソートします。

0
ss sreekanth

ユースケース:大きなデータセットがある場合、sort byのように並べ替えを行う必要があります。すべてのセットレデューサーは、クラブする前にデータを内部で並べ替えます。これによりパフォーマンスが向上します。 Order byでは、すべてのデータが単一のレデューサーを通過するため、大きなデータセットのパフォーマンスが低下します。これにより、負荷が増加し、クエリの実行に時間がかかります。 11ノードクラスターの以下の例を参照してください。 enter image description here

これはOrder Byの出力例です enter image description here

これはソート出力例です enter image description here

これはクラスタによる例です enter image description here

私が観察したのは、sort by、cluster by、distribute byの数字は[〜#〜] same [〜#〜]ですが、内部メカニズムは異なります。 DISTRIBUTE BYの場合:同じ列の行が1つのレデューサーに送られます。 DISTRIBUTE BY(City)-1列のバンガロールデータ、1レデューサーのデリーデータ:

enter image description here

0
Tutu Kumari