メインコンテンツへジャンプ

Databricks の Notebook を試してみる

2018/11/10/更新

ピボット(PIVOT)は、Apache Spark 1.6 から DataFrame 機能として実装されています。一意の値を1 つの列から複数の個々の列に変換し、テーブル値式を回転させる機能です。

Apache Spark 2.4 リリースでは、この便利なピボット機能を SQL でも利用できるようになりました。このブログでは、気温のデータを対象に、SQL の PIVOT で複雑なデータ変換を容易に行う方法を解説します。UNION ALL や Spark SQL とはどんなものなのかもあわせてご紹介しています。

ピボットで夏の気温を比較する

シアトルではこの夏は普段とは異なり、7月に 9日間、最高気温が 80℉(約27℃)から 90℉ (約32℃)に達し、不快なレベルにまで上昇しました。

日付 気温 (°F)
7/22/2018 86
7/23/2018 90
7/24/2018 91
7/25/2018 92
7/26/2018 92
7/27/2018 88
7/28/2018 85
7/29/2018 94
7/30/2018 89

まず、過去に同様の気温上昇傾向があったかどうかを調べてみましょう。この場合、数値を調べて提示する直感的な方法の 1 つは、列に月を指定、行に年を指定して、各月の平均最高気温を表示させることです。そうすることで、隣り合う月の温度が横に、異なる年の温度が縦になり、両方向での比較が容易になります。

現在、データブリックスの Spark SQL (Spark SQL とは、構造化データ処理のための Spark モジュールのことです。DataFrames と呼ばれるプログラミングの抽象化が可能で、分散型 SQL クエリエンジンとしても機能します。)ではPIVOT 構文をサポートしているので、次の SQL クエリでこれを実現することができます。

上記のクエリは次のような結果を生成します:

YEAR JAN FEB MAR APR MAY JUNE JULY AUG SEPT OCT NOV DEC
2018 49.7 45.8 54.0 58.6 70.8 71.9 82.8 79.1 NULL NULL NULL NULL
2017 43.7 46.6 51.6 57.3 67.0 72.1 78.3 81.5 73.8 61.1 51.3 45.6
2016 49.1 53.6 56.4 65.9 68.8 73.1 76.0 79.5 69.6 60.6 56.0 41.9
2015 50.3 54.5 57.9 59.9 68.0 78.9 82.6 79.0 68.5 63.6 49.4 47.1

気温上昇が大きかった年とそうではない年があることがわかります。2016年は、どちらかというと省エネルギーの年だったようです。

SQL でのピボット(PIVOT)テーブル

このクエリを詳しくみて機能についての理解を深めましょう。まず、ピボットの入力である FROM 句、つまりピボットを実行するベースとなるテーブルまたはサブクエリを指定する必要があります。わたしたちは、年、月、および高い気温を調べたいので、これらがサブクエリに表示されるフィールドになります。

次に、クエリのもう 1 つの重要な部分である PIVOT 句について考えてみます。PIVOT句の最初の引数は、集計関数と集計される列です。次に、FOR サブ句のピボット列を 2 番目の引数として指定し、最後の引数としてピボット列の値を含む IN演算子を指定します。

ピボット列はテーブルを回転するポイントで、ピボット列の値は出力テーブルの列に転置されます。また、IN 句を使用すると、ピボット値ごとにエイリアスも指定でき、より意味のある列名を容易に生成できます。

SQL ピボットに関する重要な考え方は、ピボット列と共に暗黙的なgroup-by 列のリストをベースにグループ化された集計を実行することです。暗黙的なgroup-by列は、どの集計関数にもピボット列としても表示されないFROM 句の列です。

上記のクエリでは、ピボット列が month列、暗黙的な group-by 列が year 列である場合、式avg(temp) は、(year, month) の各個別値ペアに集計され、ここでは、monthは指定されたピボット列の値の 1 つに等しくなります。その結果、このそれぞれの集計値は、year行と monthの対応するセルにマップされます。

注意すべきは、この暗黙的なgroup-byが原因で、ピボット出力の一部にしたくない列をFROM 句から省くことを確認する必要があることで、そうしないとクエリが不要な結果を生成してしまいます。

複数の集計式の指定

上記の例では、PIVOT句で使用されている集計式は 1 つだけ示されていますが、実際には、ユーザーは必要に応じて複数の集計式を指定できます。繰り返しますが、上記の気象データでは、6月から9月までの高温の平均(avg)と併せて最高気温(max)を一覧表示することができます。

複数の集計式の場合、列はピボット列の値のデカルト積と集計式で、名前は<value>_<aggExpr>となります。

year JUN_avg JUN_max JUL_avg JUL_max AUG_avg AUG_max SEP_avg SEP_max
2018 71.9 88 82.8 94 79.1 94 NULL NULL
2017 72.1 96 78.3 87 81.5 94 73.8 90
2016 73.1 93 76.0 89 79.5 95 69.6 78
2015 78.9 92 82.6 95 79.0 92 68.5 81

列のグループ化とピボット列の比較

次に、この毎日の低い気温の表から気温傾向の調査に低い気温を含めます。

日付 気温 (°F)
8/1/2018 59
8/2/2018 58
8/3/2018 59
8/4/2018 58
8/5/2018 59
8/6/2018 59

このテーブルを前に作成した高い気温の表と組み合わせるには、「日付」列でこれらの 2 つのテーブルを結合します。とはいえ、日付にグループ化を実行するピボットを使用するので、単にUNION ALL(UNION ALL とは、2 つの表やテーブルを縦に結合させる操作のことで、重複行についてはそのまま全て表示します。)を使用して 2 つのテーブルを連結するだけです。後でわかりますが、このアプローチで互換性も向上します。

それでは、新しい結合テーブルを使用してピボットクエリを試してみましょう。

その結果、過去4年間の各月の高い気温の平均と低い気温の平均が1つのテーブルに表示されます。ピボットクエリに flag 列を含める必要があることに注意しないと、avg(temp) 式は高い気温と低い気温の混合がベースになってしまいます。

year H/L JUN JUL AUG SEP
2018 H 71.9 82.8 79.1 NULL
2018 L 53.4 58.5 58.5 NULL
2017 H 72.1 78.3 81.5 73.8
2017 L 53.7 56.3 59.0 55.6
2016 H 73.1 76.0 79.5 69.9
2016 L 53.9 57.6 59.9 52.9
2015 H 78.9 82.6 79.0 68.5
2015 L 56.4 59.9 58.5 52.5

お気づきのとおり、各年に行が2つ作成され、気温の高い行(H)と低い行(L)に分かれています。これは、ピボット入力にもう 1つの列、flagを追加したためです。この列は元のyear列に加えて別の暗黙的なグループ化列になります。

もう 1つの方法として、グループ化列ではなく、flagをピボット列として使用することもできます。これで、monthflag の2つのピボット列ができました。

このクエリでは、各年は 1 行ですが、各月では高(hi)/低(lo)2 列ずつ表示され、同じデータの異なるレイアウトを表示できます。

year JUN_hi JUN_lo JUL_hi JUL_lo AUG_hi AUG_lo SEP_hi SEP_lo
2018 71.9 53.4 82.8 58.5 79.1 58.5 NULL NULL
2017 72.1 53.7 78.3 56.3 81.5 59.0 73.8 55.6
2016 73.1 53.9 76.0 57.6 79.5 57.9 69.6 52.9
2015 78.9 56.4 82.6 59.9 79.0 58.5 68.5 52.5

次のステップ

このブログで使用されているクエリの例を実行するには、この付属 Notebook のピボット SQL のサンプルを参照してください。
SQL のピボット機能の使い方、UNION ALL や Spark SQL とはどんなものなのか知りたい方にとって参考になれば幸いです。

Apache Spark コミュニティに貢献していただいている皆様に感謝します。

Databricks 無料トライアル

関連記事

SQL でピボット(PIVOT)を使用したデータ変換:行から列への変換

November 1, 2018 MaryAnn Xue による投稿 in
Databricks の Notebook を試してみる 2018/11/10/更新 ピボット(PIVOT)は、Apache Spark 1.6 から DataFrame 機能として実装されています。一意の値を1 つの列から複数の個々の列に変換し、テーブル値式を回転させる機能です。 Apache Spark 2.4 リリースでは、この便利なピボット機能を SQL でも利用できるようになりました。このブログでは、気温のデータを対象に、SQL の PIVOT で複雑なデータ変換を容易に行う方法を解説します。UNION ALL や...
エンジニアリングのブログ一覧へ