Hive のバージョンと構成によっては、質問に対する答えが異なる場合があります。正確なクエリと、2 つのテーブルの作成ステートメントおよびそれらのサイズの見積もりを共有できれば、より簡単になります。
問題をよりよく理解するために、「通常の」内部結合が Hive でどのように機能するかを見てみましょう。
MapReduce での Hive の結合:
以下は、Hive の内部結合が MapReduce にコンパイルされる方法を簡単に説明したものです。一般に、次のような結合クエリを持つ 2 つのテーブル t1 と t2 があるとします。
SELECT
t1.key, t1.value, t2.value
FROM
t1
JOIN
t2 (ON t1.key = t2.key);
ここで、t1 の内容は次のとおりです。
k_1 v1_1
k_2 v1_2
k_3 v1_3
ここで、t2 の内容は次のとおりです。
k_2 v2_2
k_3 v2_3
k_4 v2_4
結合結果は次のようになると予想されます
k_2 v1_2 v2_2
k_3 v1_3 v2_3
テーブルが HDFS に保存されていると仮定すると、その内容はファイル分割に分割されます。マッパーはファイル分割を入力として受け取り、キーをテーブルのキー列として出力し、値をテーブルの値列とフラグの複合体として出力します (レコードがどのテーブルからのものか、つまり t1 または t2 を表します)。 .
t1 の場合:
k_1, <v1_1, t1>
k_2, <v1_2, t1>
k_3, <v1_3, t1>
t2 の場合:
k_2, <v2_2, t2>
k_3, <v2_3, t2>
k_4, <v2_4, t2>
ここで、これらの出力されたレコードは、同じキーを持つすべてのレコードがグループ化されてレデューサーに送信されるシャッフル フェーズを通過します。各縮小操作のコンテキストは、1 つのキーと、そのキーに対応するすべての値を含むリストです。実際には、1 つのレデューサーが複数のリデュース操作を実行します。
上記の例では、次のグループ化が得られます。
k_1, <<v1_1, t1>>
k_2, <<v1_2, t1>, <v2_2, t2>>
k_3, <<v1_3, t1>, <v2_3, t2>>
k_4, <<v2_4, t2>>
レデューサーで何が起こるかを次に示します。値のリスト内の各値について、値が異なるテーブルに対応する場合、リデューサーは乗算を実行します。
k_1 の場合、t2 からの値はなく、何も出力されません。
k_2 の場合、値の乗算が発行されます - k_2、v1_2、v2_2 (各テーブルから 1 つの値があるため、1x1 = 1)
k_3 の場合、値の乗算が発行されます - k_3、v1_3、v2_3 (各テーブルから 1 つの値があるため、1x1 = 1)
k_4 の場合、t1 からの値はなく、何も出力されません。したがって、内部結合から期待した結果が得られます。
わかりました、それで私は何をしますか?
データに偏りがある可能性があります。言い換えると、リデューサーがデータを取得するときに、あるキーに対応する値のリストが非常に長く、エラーが発生します。この問題を軽減するには、JVM で使用できるメモリを増やしてみてください。hive-site.xml のmapred.child.java.opts
ような値に設定することで、これを行うことができます。Hive シェルで-Xmx512M
実行することにより、このパラメーターの現在の値を照会できます。set mapred.child.java.opts;
マップ結合など、「通常の」結合に代わる方法を試すことができます。上記の結合の説明は、結合がレデューサーで発生する通常の結合に適用されます。使用している Hive のバージョンによっては、Hive が通常の結合をより高速なマップ結合に自動的に変換できる場合があります (結合はマップ フェーズで発生するため)。最適化を有効にするには、 に設定hive.auto.convert.join
しtrue
ます。このプロパティはHive 0.7で導入されました
に設定hive.auto.convert.join
する以外に、 に設定するtrue
こともできます。これにより、1 で説明したデータの偏りの問題を回避できます。hive.optimize.skewjoin
true