January 2016

Volume 31 Number 1

ビッグ データ - ビッグ データのバッチ分析を容易にする U-SQL

Michael Rys | January 2016

Microsoft Azure Data Lake サービス (bit.ly/1VcCkaH、英語) は、クラウドで分析を行うためのサービス群です。このサービスには、ハイパースケール リポジトリ、YARN (bit.ly/1iS8xvP、英語) を基盤とする新しい Analytics サービス、および HDInsight (azure.microsoft.com/ja-jp/services/hdinsight/) が含まれています。データ開発者やデータ科学者は、Analytics サービスを使ってあらゆるデータを分析できるようになります。HDInsight とは、Hadoop、Spark、Storm、および HBase の完全管理型サービスです。Azure Data Lake Analytics には U-SQL も含まれています。U-SQL は、開発者が独自のコードで表現する能力と SQL のメリットを兼ね備えた言語です。U-SQL のスケーラブルな分散クエリ機能は、ストアのデータや、Azure SQL Database などのリレーショナル ストアのデータの効率的な分析を可能にします。今回は、U-SQL を開発した動機、この言語の背後にある考え方や設計哲学を紹介し、この言語の重要な側面をいくつか例を挙げて説明します。

U-SQL を開発した理由

ビッグ データ分析の特徴を考えてみると、使いやすく強力な言語についての要件がいくつか自然に浮かび上がってきます。

  • 処理するデータの種類が多岐に渡る。セキュリティ ログで BotNet 攻撃のパターンを分析することから、機械学習のために画像や動画から特徴を抽出することまで、あらゆる種類のデータを操作できなければなりません。
  • 複雑で、おそらく独自のビジネス アルゴリズムを表現するカスタム コードを簡単に作成できる。最初の箇条書きに例として示したシナリオはどちらも、ユーザー定義関数やカスタム入出力形式など、独自の処理が必要になります。多くの標準クエリ言語では、こうしたカスタム処理を簡単には表現できません。
  • あらゆるサイズのデータを効率的にスケーリングできる。特定の分散インフラストラクチャのスケールアウト トポロジ、プラミング コード、制限などに力を注ぐ必要はありません。

これらの要件に対する既存のビッグ データ言語の対応度

Hive (hive.apache.org、英語) などの SQL ベース言語は、スケーリング、並列実行、および最適化をネイティブに行う宣言型の方法を提供します。そのため、使いやすく、幅広い開発者が好んで使用する言語になっていて、数多くの標準的な種類の分析やウェアハウジングに力を発揮しています。ただし、その拡張モデルと、構造化されていないデータやファイルのサポートの多くは後付けのもので、使いやすくはありません。たとえば、ファイル内のデータやリモート データ ソースをすばやく調査したいとします。このような場合、クエリの前に、ファイル データやリモート ソースをスキーマ化するためにカタログ オブジェクトを作成しておかなければならず、その結果、アジリティが低下します。SQL ベース言語の場合、カスタム フォーマッタ、ユーザー定義関数、アグリゲーターなどに対して拡張ポイントが用意されるのが一般的ですが、プログラミング モデルとの一貫性の程度はさまざまで、構築、統合、および保守はかなり難しくなっています。

プログラミング言語を使ってビッグ データを処理する方法ならば、カスタム コードの追加は簡単です。ただし、スケーリングやパフォーマンスについては、通常プログラマが明示的にコーディングしなければならず、複数の実行段階の同期やスケールアウト アーキテクチャなど、コーディングの範囲が実行トポロジやワークフローの管理まで及ぶこともしばしばです。こうしたコードを正しくコーディングするのは難しく、パフォーマンスの最適化も困難です。フレームワークによっては、統合言語クエリのような宣言型コンポーネントのサポートや、埋め込み SQL のサポートを提供するものもあります。しかし、こうした SQL の多くは、リテラル文字列として統合され、ツールによるサポートがありません。そのため、手続き型コードを使用する場合、拡張機能の統合は、副作用を避けられずに限定的になるか、最適化や再利用が困難になります。

要件を満たす U-SQL

SQL ベース言語と手続き型言語両方の問題点を念頭に、C# で記述したユーザー コードによるネイティブな拡張性を備えた宣言型 SQL 言語へと進化させるために、U-SQL はゼロから設計されました。U-SQL は、以下の特徴を兼ね備えています。

  • 宣言型と命令型のコーディング パラダイムとエクスペリエンス
  • カスタム ユーザー コードによって言語機能を拡張するエクスペリエンス
  • 構造化、非構造化を問わない、あらゆるデータの処理
  • Azure Data Lake などの Azure データ ソースでのフェデレーション クエリを使用したデータ処理

U-SQL は、拡張可能な宣言型スクリプト言語 SCOPE (Structured Computations Optimized for Parallel Execution、bit.ly/1OGUNIY、英語) に関するマイクロソフト社内の経験と、T-SQL、ANSI SQL、Hive などの既存の言語を基に作られています。たとえば、SQL とプログラミング言語の統合と、U-SQL の実行、最適化フレームワークは、現在は社内で毎日数十万ものジョブを実行する SCOPE をベースに作成されています。また、メタデータ システム (データベース、テーブルなど)、SQL 構文、言語セマンティクスは、ほとんどの SQL Server ユーザーが使い慣れているクエリ言語 T-SQL や ANSI SQL に準じています。さらに、C# のデータ型と式言語を使用しているため、開発者は C# の述語や表現を SELECT ステートメント内部にシームレスに記述したり、C# を使用してカスタム ロジックを追加することができます。最後に、パターンやデータ処理の要件を特定し、それをこのフレームワークに統合するために、Hive などのビッグ データ言語にも目を向けました。

簡単に言えば、U-SQL 言語をこれら既存の言語や経験を基に作成することで、ビッグ データ クエリ言語界に真の進化をもたらし、開発者が取り組みやすく、困難な問題に対処するのに十分な力を備えた言語にしています。

U-SQL の例

Twitter の自分のすべてのツイート、リツイート、メンションの履歴を CSV ファイルとしてダウンロードして、Azure Data Lake ストアに置いたとしましょう。Azure Data Lake Tools for Visual Studio を使用すると、このファイルをプレビューして構造を理解できます。これを行うには、サーバー エクスプローラーで Data Lake Storage アカウントを探し、既定のストレージ アカウントでエクスプローラーを開きます。図 1 はデータ ストリーム (この場合は CSV ファイル) を示しています。U-SQL ではデータ ストリームの形式として遅延バインドを使用するため、このプレビューには区切り記号に基づいて列のみが表示され、型は示されません。

Visual Studio におけるデータ ストリームのプレビュー
図 1 Visual Studio におけるデータ ストリームのプレビュー

この例では、処理対象のデータのスキーマはわかっています。最初に、ツイート "ネットワーク" で、著者 (author) ごとのツイート数をカウントします。図 2 の U-SQL スクリプトは、U-SQL によるデータ処理の以下の 3 つの主要手順を示しています。

  1. データをソースから行セットに抽出します。クエリでは EXTRACT ステートメントを使用してデータをスキーマ化しています。データ型は C# データ型に基づき、スクリプトは組み込みの Extractors ライブラリを使用して CSV ファイルを読み取り、スキーマ化します。
  2. U-SQL またはユーザー定義演算子を一連の行セット操作に使用して行セットを変換します。多くの場合、変換は 1 つ以上の過去の行セットに基づいて行われます。図 2 の例は、EXTRACT 式によって生成された行セットに GROUP BY 集計を実行するおなじみの SQL 式です。
  3. 結果の行セットをファイルまたは U-SQL テーブルに出力し、その後の処理用に保存します。

図 2 CSV からツイートを抽出する U-SQL スクリプト

    1 @t = EXTRACT date string
    2            , time string
    3            , author string
    4            , tweet string
    5      FROM "/input/MyTwitterHistory.csv"
    6      USING Extractors.Csv();
    7
    8 @res = SELECT author
    9             , COUNT(*) AS tweetcount
    10        FROM @t
    11        GROUP BY author;
    12
    13 OUTPUT @res TO "/output/MyTwitterAnalysis.csv"
    14 ORDER BY tweetcount DESC
    15 USING Outputters.Csv();

U-SQL の SQL キーワードは大文字で表記する必要があります。これは、同じキーワードでも異なる意味を持つ C# の構文式と区別するためです。先ほどのスクリプトでは、SELECT ステートメントの列に別名を割り当てるときに "AS" ではなく "as" を使用してしまうエラーがよく起こります。SQL 式構文の正しい形式は大文字の AS です。もちろん、このエラーはコンパイル時にキャッチされます。

また、各式を変数 (@t と @res) に代入しています。これにより、U-SQL は、関数ラムダ合成を使用して、式フローとして表現されたデータを段階的に少しずつ変換したり組み合わせたりできます (Pig [pig.apache.org、英語] 言語の機能に似ています)。実行フレームワークは、その後、複数の式をまとめて 1 つの式に合成します。この 1 つの式は、グローバルに最適化して、スケールアウトできます。式が 1 行ごとに実行される場合は、このような最適化やスケーリングは不可能です。図 3 は、後ほど取り上げるクエリの 1 つについて生成した実行グラフです。このグラフは、コンパイラとオプティマイザーによってグローバルに最適化された実行段階を表しています。

Visual Studio のジョブ実行グラフ
図 3 Visual Studio のジョブ実行グラフ

U-SQL における C# 統合

先ほどの例に戻りましょう。ここで、ツイートでメンションしたユーザーの情報を追加し、ツイート ネットワークに含まれるユーザーがツイートする頻度と、そのユーザーがメンションされる頻度を返すよう集計を拡張します。そのため、U-SQL における C# 統合を見てみましょう。

U-SQL は C# の型システムとスカラー式言語を利用しているため、クエリ作成者は C# の機能や、CLR のクラス、メソッド、関数、演算子、型などのライブラリを利用できます。代入演算子 (=、+= など) を除く C# の演算子はすべて、U-SQL スカラー式で有効です。特に、==、!=、<、> などの比較演算子、「<条件> ? <真の式> : <偽の式>」の 3 項比較、Null 合体演算子 ?? がすべてサポートされています。=> を使用するラムダ式も U-SQL 式内部で使用できます。

U-SQL は C# Roslyn コンパイラ (bit.ly/1BsPced、英語) と統合されているため、この非常に密接な統合とシームレスなプログラミング機能が、構文的にも実現されています。実際、U-SQL の統合は、おそらく C# Roslyn コンパイラ プラットフォームにおける最も複雑な応用です。

C# コードを使用して U-SQL 式を拡張する方法は、以下のようにいくつかあります。

  • U-SQL スクリプトに C# インライン式を記述する: 通常、スカラー値の処理に当てはまる C# メソッド (文字列型メソッドや数学関数) が少ない場合に有効です。
  • ユーザー定義関数を C# アセンブリに記述して U-SQL スクリプトでその関数を参照する: 手続き型のロジックや再帰など、式言語で表現できない C# の能力を関数のロジックで完全に引き出す必要がある場合など、複雑な関数にお勧めです。
  • ユーザー定義のアグリゲーターを C# アセンブリに記述して U-SQL スクリプトでそのアグリゲーターを参照する: ユーザー定義アグリゲーターを用意すると、GROUP BY 句を使用してユーザー定義集計ロジックを U-SQL の集計処理に組み込むことができます。
  • ユーザー定義演算子を C# アセンブリに記述して U-SQL スクリプトでその演算子を参照する: ユーザー定義演算子 (UDO) は、独自にコーディングした U-SQL の行セット演算子です。これは C# で記述し、行セットを生成、処理、および利用する機能を提供します。

ユーザー定義の関数、アグリゲーター、および演算子の場合、C# アセンブリは CREATE ASSEMBLY (U-SQL) を使用して U-SQL メタデータ カタログに読み込み、REFERENCE ASSEMBLY を使用してスクリプトから参照しなければなりません。Azure Data Lake Tools for Visual Studio では、登録プロセスが簡単になります。また、特定のスクリプトにアタッチする特別な C# ファイルにコードを記述するだけで、送信時にすべてのプラミングがツールによって処理されるという、いわゆる分離コードも提供されます。

図 4 は、先ほど説明した、集計用に拡張したクエリです。SELECT ステートメントと C# LINQ インライン式を併用して、各ツイートから "メンション" を ARRAY (8 ~ 10 行目) に抽出しています。これで、@m (8 行目) には ARRAY の行セットが含まれます。14 行目で EXPLODE 関数を使用して、各配列を、1 つの配列項目につき 1 行を含む行セットに変換します。この EXPLODE は CROSS APPLY の一部として実行します。つまり、行セット @m の各行に EXPLODE が適用されます。その結果の新しい行セット (12 行目) には、1 行につき 1 つの "メンション" が含まれます。同名の @m を再利用していることに注意してください。既存の著者の値と揃えるためには、冒頭の @ 記号を削除する必要があります。@ の削除は、別の C# 式で行います。12 行目の開始位置に 1 を指定した Substring がそれです。最後に、著者とメンションを結合 (16 ~ 21 行目) し、COUNT 集計を拡張して、大文字小文字の区別がある Twitter のハンドル名とカテゴリでグループ化 (23 ~ 27 行目) したら、ツイート数の降順に結果を並び替えて出力します (29 ~ 31 行目)。

図 4 C# のメソッドを使用したツイート操作

    1 @t = EXTRACT date string
    2            , time string
    3            , author string
    4            , tweet string
    5      FROM "/input/MyTwitterHistory.csv"
    6      USING Extractors.Csv();
    7  
    8 @m = SELECT new SQL.ARRAY<string>(
    9                 tweet.Split(' ').Where(x => x.StartsWith("@"))) AS refs
    10      FROM @t;
    11
    12 @m = SELECT r.Substring(1) AS r
    13           , "referenced" AS category
    14      FROM @m CROSS APPLY EXPLODE(refs) AS t(r);
    15
    16 @t = SELECT author, "authored" AS category
    17      FROM @t
    18      UNION ALL
    19      SELECT *
    20      FROM @m
    21      WHERE r != null && r != "";
    22
    23 @res = SELECT author.ToLowerInvariant() AS author
    24             , category
    25             , COUNT( * ) AS tweetcount
    26        FROM @t
    27        GROUP BY author.ToLowerInvariant(), category;
    28
    29 OUTPUT @res TO "/output/MyTwitterAnalysis.csv"
    30 ORDER BY tweetcount DESC
    31 USING Outputters.Csv();

このコードをさらに詳しく確認して、U-SQL に密接に統合された C# の能力を見てみましょう。

図 4 のスクリプト部分は、U-SQL が C# 式を想定して受け取る部分の一部です。EXTRACT USING 句と OUPUT USING 句、SELECT 句と WHERE 句、GROUP BY 句、ORDER BY 句、および EXPLODE 関数で C# 式を使用しています。なお、この例では最後の 2 つだけが列名を参照しています。

この統合で重要な点は、クエリ式内のスカラー値が C# 型のため、C# 式を使用することで、この値にシームレスな方法で完全にアクセスできることです。たとえば、9 行目の列 tweet、12 行目と 21 行目の r、23 行目と 27 行目の author はすべて、追加のラッパー構文を使用することなく C# 式にシームレスに統合されます。

6 行目の EXTRACT USING 句と 31 行目の OUPUT USING 句は C# 式を受け取り、ユーザー定義演算子のインスタンスを返します。2 つの組み込み式は、抽出演算子と出力演算子のインスタンスをそれぞれ返すファクトリ メソッドへの呼び出しです。

8 ~ 9 行目の C# 式をもう少し詳しく見てみましょう。

new SQL.ARRAY<string>(tweet.Split(' ').Where(x => x.StartsWith("@")))

これは C# の使用を示す優れた例です。U-SQL の組み込み型 SQL.ARRAY<T> は実際は C# オブジェクト型で、既存の C# Array 型の更新関数に副作用を及ぼすことなく、必要な SQL/Hive 機能を提供します。開発者は C# の new 演算子を使用して新しいインスタンスを作成するだけです。このインスタンスは、数多くある文字列操作のうちの 1 つ、単語に区切る操作を、文字列型で定義された列 tweet に当てはめるために作成されます。普通の SQL 言語のような特定の文字列型の機能を利用する場所を考えることはありません。いつでも CLR の能力を最大限利用できます。

それだけではありません。Split メソッドは IEnumerable<string> を返します。そのため、ツイートの単語をフィルター処理して "メンション" を取得するなど、処理をさらに行う場合は、LINQ 式を使用したり、ラムダ式を述語として使用するなどして実行できます。通常お使いの SQL 言語で試してみてください。

21 行目の WHERE 句も見てみましょう。ここでも、行セットの列を参照する C# 式を記述しています。このコンテキストの式は、bool 型の値を返します。SQL の論理体系は 3 値論理ですが、C# は 2 値論理です。そのため、r != null の比較は、r が null でない場合には true を、r が null の場合には false を返します。C# の論理演算子 && を使用することで、C# の実行順序が保持されること、さらに重要なことには、最初の比較が false と評価された場合に 2 つ目の比較を実行しないショートカットが保証されます。U-SQL では、SQL ベースの AND や OR による結合もサポートしています。これらを使用する場合、ショートカットは起こりませんが、述語を並べ替えてパフォーマンスを向上できます。これらのことから、開発者には、より効率的に実行したり、セマンティック上の予防措置を取ったりするなどの選択肢が与えられます。

U-SQL、Visual Studio の分離コード機能、アセンブリ

次に、Azure Data Lake Tools for Visual Studio を使用し、このツールの分離コード機能 (図 5 参照) によって C# コードを C# 関数にリファクタリングします。その後スクリプトを送信するときに、関連する .cs ファイルのコードが、自動的にツールによってサービスに配置されます。U-SQL でメソッド、型、および関数を参照できるようにするためには、クラスを public として定義し、オブジェクトを static public として定義しなければなりません。

Visual Studio の分離コード
図 5 Visual Studio の分離コード

このツールは、次の 3 つの手順に従います。

  1. .cs ファイルがアセンブリ ファイルにコンパイルされます。
  2. ユーザーの U-SQL スクリプトに、CREATE ASSEMBLY ステートメントを追加するヘッダーが追加されます。CREATE ASSEMBLY ステートメントは、U-SQL メタデータ カタログにアセンブリ ファイルのバイナリ コンテンツを作成します。
  3. 登録されたアセンブリを DROP ASSEMBLY ステートメントによって削除するクリーンアップがスクリプトの最後に追加されます。

U-SQL メタデータ カタログにコードをアセンブリとして自身で明示的に配置、登録することもできます。このようにすることで、自身や他の開発者がこのコードを将来スクリプトで利用できるようになります。これは、他のコンテキスト (XML、JSON ライブラリなど) で作成した既存のコードや外部実行ファイルへの呼び出しに含めるため、個別に管理する必要のある複雑なコードがある場合に、ユーザー定義の関数、アグリゲーター、演算子などを管理するうえでもお勧めの方法です。

SQL Server のようなリレーショナル データベースと同様、U-SQL にはメタデータ カタログが用意されています。また、U-SQL では、データベース、スキーマ、テーブルなどの標準データベース オブジェクトをサポートします。そのオブジェクトの 1 つが、アセンブリ メタデータ オブジェクトです。CREATE ASSEMBLY ステートメントを使用して、アセンブリをデータベースに登録します。アセンブリは、データベース限定のオブジェクトです。アセンブリ DLL ファイルは、プライマリ Azure Data Lake ストレージ アカウントのカタログ フォルダー内にある関連するデータベース フォルダーのアセンブリ フォルダーに配置されます。

アセンブリの格納の他にも、アセンブリと一緒に格納するファイルや、アセンブリを参照するときにインクルードするファイルを追加で指定することもできます。CREATE ASSEMBLY ステートメント構文の文法は次のようになります (詳細については、bit.ly/1HWw0cc (英語) で U-SQL 言語のリファレンス ドキュメントを参照してください)。

    Create_Assembly_Statement :=
      'CREATE' 'ASSEMBLY' ['IF' 'NOT' 'EXISTS'] Assembly_Name
      'FROM' Assembly_Source
      ['WITH' 'ADDITIONAL_FILES' '='
        '(' Assembly_Additional_File_List ')'].
    Assembly_Name := Quoted_or_Unquoted_Identifier.
    Assembly_Source :=
      Static_String_Expression | lexical_binary_value.

アセンブリの参照について言うと、U-SQL には、System や System.Linq など、事前に読み込まれる少数の System アセンブリと名前空間があります。これらは、コンパイル時間とジョブのリソース利用率を少なくするために、少数に抑えられています。別のシステム アセンブリを参照する場合は、それをステートメント内に含めるだけです。以下は、System.Xml を追加するステートメントです。

    REFERENCE SYSTEM ASSEMBLY [System.Xml];

ツイート分析関数を含むアセンブリを TweetAnalysis という名前で登録したら、図 6 のように参照して使用することができます。@ 記号を削除するだけでなく、さらにメンションに対してクリーンアップを行う必要があります。アセンブリには、@ 記号の削除以外の処理を行う cleanup_mentions 関数も含まれています。

図 6 U-SQL でのアセンブリ参照

    1 REFERENCE ASSEMBLY TweetAnalysis;
    2
    3 @t = EXTRACT date string
    4            , time string
    5            , author string
    6            , tweet string
    7      FROM "/input/MyTwitterHistory.csv"
    8      USING Extractors.Csv();
    9
    10 @m = SELECT Tweets.Udfs.get_mentions(tweet) AS refs
    11      FROM @t;
    12
    13 @t = SELECT author, "authored" AS category
    14      FROM @t
    15      UNION ALL
    16      SELECT Tweets.Udfs.cleanup_mentions(r) AS r, "mentioned" AS category
    17      FROM @m CROSS APPLY EXPLODE(refs) AS Refs(r);
    18
    19 @res = SELECT author.ToLowerInvariant() AS author
    20             , category
    21             , COUNT(*) AS tweetcount
    22        FROM @t
    23        GROUP BY author.ToLowerInvariant(), category;
    24
    25 OUTPUT @res
    26 TO "/output/MyTwitterAnalysis.csv"
    27 ORDER BY tweetcount DESC
    28 USING Outputters.Csv();

U-SQL による構造化データと非構造化データの統合

ここまで見てきたように、U-SQL では EXTRACT 式を使用して、ファイルの読み取り時のスキーマ化を非常に簡単にしています。ただし、スキーマがわかる段階までデータの準備が進んでいれば、EXTRACT をビューにラップするか、複数ステートメントのパラメーター化されたビューを提供するテーブル値関数にラップする方が適切です。

図 7 に新しいコードを示します。2 行目の CREATE FUNCTION ステートメントは、パラメーターとして既定値が指定された @file (4 行目) を含む U-SQL テーブル値関数 Tweet_Authors_Mentions を作成します。戻り値はテーブル型の行セット @res で、author、category、tweetcount という 3 つの列を持ちます (6 ~ 11 行目)。パラメーターは 20 行目で参照され、34 行目の結果 @res への最後の代入を返します。

図 7 パラメータ化されたテーブル値関数

    1 DROP FUNCTION IF EXISTS Tweet_Authors_Mentions;
    2 CREATE FUNCTION Tweet_Authors_Mentions
    3 (
    4   @file string = "/Samples/Data/MyTwitterHistory.csv"
    5 )
    6 RETURNS @res TABLE
    7 (
    8    author string
    9 ,  category string
    10 ,  tweetcount long?
    11 )
    12 AS BEGIN
    13 REFERENCE ASSEMBLY TweetAnalysis;
    14
    15 @t =
    16   EXTRACT date string
    17         , time string
    18         , author string
    19         , tweet string
    20   FROM @file
    21   USING Extractors.Csv();
    22
    23 @m =
    24   SELECT AzureConDemo.Udfs.get_ref(tweet) AS refs
    25   FROM @t;
    26
    27 @t =
    28   SELECT author, "authored" AS category
    29   FROM @t
    30   UNION ALL
    31   SELECT AzureConDemo.Udfs.cleanup(r) AS r, "referenced" AS category
    32   FROM @m CROSS APPLY EXPLODE(refs) AS t(r);
    33
    34 @res =
    35   SELECT author.ToLowerInvariant() AS author
    36        , category
    37        , COUNT( * ) AS tweetcount
    38   FROM @t
    39   GROUP BY author.ToLowerInvariant(), category;
    40 END;

U-SQL テーブル値関数は常にクエリ スクリプトにインライン化されるため、U-SQL オプティマイザーはすべてのステートメントを判断して最適化できます。この関数は、たとえば、次のように呼び出します。

    1 OUTPUT Tweet_Authors_Mentions(DEFAULT)
    2 TO "/Samples/Data/Output/MyTwitterAnalysis.csv"
    3 ORDER BY tweetcount DESC
    4 USING Outputters.Csv();

ただし、多くの場合、準備されたデータは構造化データとして U-SQL テーブルに格納されます。このテーブルは、クラスター化インデックスや、データのパーティション分割機能など、追加のストレージ最適化を提供します。次のステートメントを見ると、U-SQL では CREATE TABLE AS クエリ ステートメントを使用してテーブルを簡単に作成できることがわかります。

    1 DROP TABLE IF EXISTS TweetAuthorsAndMentions;
    2 CREATE TABLE TweetAuthorsAndMentions(INDEX idx
    3   CLUSTERED(author ASC)
    4   PARTITIONED BY HASH(author) INTO 5
    5 )
    6 AS Tweet_Authors_Mentions(DEFAULT);

3 行目はテーブルのインデックスを author 列によって昇順でクラスター化することを表し、4 行目はauthor の値のハッシュを使用して内部表現を 5 つのパーティションに水平分割することを表します。このステートメントを実行すると、Tweet_Authors_Mentions function 関数の出力がこれらの特性を持つ新しいテーブルとして保存されます。U-SQL は、水平方向のパーティション分割方式に関しては、ラウンド ロビンや範囲パーティション分割もサポートします。また、個別にパーティションをマージできる垂直方向のパーティション分割についても同様です。

これで、他のユーザーがテーブルを使用して、データのクエリや追加の分析を実行できるようになります。次に示す 図 8 のクエリでは、U-SQL に組み込みの順位付け関数をウィンドウ式と一緒に使用して、著者とカテゴリごとのツイート数の中央値を計算します。また、ツイート数が 50 以上の著者とカテゴリについては、相対順位と絶対順位も計算します。

図 8 U-SQL ウィンドウ式による分析

    1 @res =
    2  SELECT DISTINCT
    3         author, category, tweetcount
    4       , PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY tweetcount ASC)
    5         OVER (PARTITION BY category) AS median_tweetcount_perhandle_category
    6       , PERCENT_RANK() OVER
    7         (PARTITION BY category ORDER BY tweetcount ASC) AS relative_rank
    8       , ROW_NUMBER() OVER
    9         (PARTITION BY category ORDER BY tweetcount DESC) AS absolute_rank
    10 FROM TweetAuthorsAndMentions
    11 WHERE tweetcount > 50;
    12
    13 OUTPUT @res
    14 TO "/Output/Demo/tweeter_ranking.csv"
    15 ORDER BY absolute_rank, category ASC
    16 USING Outputters.Csv();

SQL ベースのウィンドウ式に対する理解を深めるために、4 ~ 9 行目の式をよく見てみましょう。OVER 式によって、OVER の左側の 2 つの分析関数 PERCENTILE_DISC と PERCENT_RANK および順位付け関数 ROW_NUMBER が、PARITION BY 句によって指定された行セット (ウィンドウ) のパーティション分割にそれぞれ適用されます (3 つの関数のいずれも、カテゴリに基づく同じパーティション分割です)。順位を計算する 2 つの関数には、値を配置する場所を示す各ウィンドウ内に、データの順序付けも必要です。PERCENT_RANK は、ウィンドウ式で指定された行のグループ内における行の相対順位を計算します。ROW_NUMBER は、行のグループ内における行の位置を計算します。PERCENTILE_DISC 関数は、列の値の離散分布に基づいて、指定されたウィンドウに含まれる並べ替え済みの値の具体的な百分位を計算します。PERCENTILE_DISC(0.5) は、ツイート数が昇順に並べられた各ウィンドウ内の第 50 百分位値 (中央値) を計算します。

U-SQL をお勧めする理由

U-SQL によってビッグ データのクエリと処理が簡単になることや、この言語の背景となる考え方をご理解いただけましたらさいわいです。U-SQL には、他にも次のような多くの機能があります。

  • 特定パターンを持つファイル セットの操作
  • 垂直にパーティション分割されたテーブルの使用
  • Azure SQL DB、SQL Data Warehouse、および Azure VM でホストされる SQL Server に対するフェデレーション クエリ
  • ビューやプロシージャよる U-SQL コードのカプセル化
  • 多数の SQL ウィンドウ関数
  • C# のユーザー定義演算子を使用したプログラミング (ユーザー定義抽出演算子、プロセッサ)
  • 多数の複合型 (MAP や ARRAY)

詳細については、U-SQL のリファレンス ドキュメント (msdn.microsoft.com/library/azure/mt591959(Azure.100).aspx) を参照してください。

ここまでの説明をまとめると、U-SQL を使用することでビッグ データの処理が容易になるのは、以下の理由からです。

  • 宣言型クエリと、ユーザー コードの表現力の統合
  • 構造化データと非構造化データのクエリの統合
  • ローカル クエリとリモート クエリの統合
  • 最初から生産性とアジリティを向上

まとめ

U-SQL は、あらゆる規模の分析の作成、デバッグ、最適化にとって、Azure Data Lake サービスを最も生産的な環境にするためにマイクロソフトが取り組んでいる方法の 1 つにすぎません。Azure Data Lake サービスには、Hive ジョブを作成および監視するための手厚いサポート、リアルタイムのストリーミングを行う Storm (storm.apache.org、英語) ジョブを構築するための C# ベースの作成モデル、ジョブ ライフサイクルにおける開発から運用までの各段階のサポートが用意されており、開発者は分散インフラストラクチャのデバッグに時間をかけるよりも、答えが必要な問題に専念することができます。目標は、ビッグ データ テクノロジをシンプルにし、できる限り多くのビッグ データ専門家、エンジニア、データ科学者、アナリスト、アプリケーション開発者にとって利用しやすいものにすることです。


Michael Rys は、マイクロソフトの主任プログラム マネージャーです。彼は、1980 年代から、データ処理とクエリ言語に携わっています。XQuery および SQL 設計委員会におけるマイクロソフトの代表を務めており、XML、地理空間、およびセマンティック検索によって、SQL Server をリレーショナルを超えた製品に進化させました。現在は、家族とダイビングや自動車レースをするとき以外は、SCOPE や U-SQL などのビッグ データ クエリ言語に取り組んでいます。彼には Twitter (@MikeDoesBigData、英語) から連絡できます。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの Omid Afnan および Ed Triou に心より感謝いたします。