AngularJS を使用し、Databricks のデータで動的なWeb ページを構築

古川えりか
古川えりか
コンテンツスペシャリスト
Databricks に接続できるシングルページアプリケーションを作成します。



AngularJS (Angular) は、動的なWeb アプリの構造フレームワークです。CData API Server であるAngular およびADO.NET Provider for Databricks (または250+ その他のADO.NET Providers) のCData API Server を使用して、Databricks からリアルタイムデータにアクセスできるシングルページアプリケーション(SPAs) を構築できます。 この記事では、CData API Server の設定と、Databricks へのライブアクセスを持つ単純なSPA の作成について説明します。 SPA はHTML テーブルを動的に作成して入力します。

Databricks データ連携について

CData を使用すれば、Databricks のライブデータへのアクセスと統合がこれまでになく簡単になります。お客様は CData の接続機能を以下の目的で利用しています:

  • Runtime バージョン 9.1 - 13.X から Pro および Classic Databricks SQL バージョンまで、すべてのバージョンの Databricks にアクセスできます。
  • あらゆるホスティングソリューションとの互換性により、お好みの環境で Databricks を使用し続けることができます。
  • パーソナルアクセストークン、Azure サービスプリンシパル、Azure AD など、さまざまな方法で安全に認証できます。
  • Databricks ファイルシステム、Azure Blob ストレージ、AWS S3 ストレージを使用して Databricks にデータをアップロードできます。

多くのお客様が、さまざまなシステムから Databricks データレイクハウスにデータを移行するために CData のソリューションを使用していますが、ライブ接続ソリューションを使用して、データベースと Databricks 間の接続をフェデレートしているお客様も多数います。これらのお客様は、SQL Server リンクサーバーまたは Polybase を使用して、既存の RDBMS 内から Databricks へのライブアクセスを実現しています。

一般的な Databricks のユースケースと CData のソリューションがデータの問題解決にどのように役立つかについては、ブログをご覧ください:What is Databricks Used For? 6 Use Cases


はじめに


API Server の設定

以下のリンクからAPI Server の無償トライアルをスタートしたら、セキュアなDatabricks OData サービスを作成していきましょう。

Databricks への接続

Angular からDatabricks のデータを操作するには、まずDatabricks への接続を作成・設定します。

  1. API Server にログインして、「Connections」をクリック、さらに「接続を追加」をクリックします。 接続を追加
  2. 「接続を追加」をクリックして、データソースがAPI Server に事前にインストールされている場合は、一覧から「Databricks」を選択します。
  3. 事前にインストールされていない場合は、コネクタを追加していきます。コネクタ追加の手順は以下の記事にまとめてありますので、ご確認ください。
    CData コネクタの追加方法はこちら >>
  4. それでは、Databricks への接続設定を行っていきましょう! 接続設定
  5. Databricks 接続プロパティの取得・設定方法

    Databricks クラスターに接続するには、以下のプロパティを設定します。

    • Database:Databricks データベース名。
    • Server:Databricks クラスターのサーバーのホスト名
    • HTTPPath:Databricks クラスターのHTTP パス。
    • Token:個人用アクセストークン。この値は、Databricks インスタンスのユーザー設定ページに移動してアクセストークンタブを選択することで取得できます。
    Databricks インスタンスで必要な値は、クラスターに移動して目的のクラスターを選択し、Advanced Options の下にあるJDBC/ODBC タブを選択することで見つけることができます。

    Databricks への認証

    CData は、次の認証スキームをサポートしています。

    • 個人用アクセストークン
    • Microsoft Entra ID(Azure AD)
    • Azure サービスプリンシパル
    • OAuthU2M
    • OAuthM2M

    個人用アクセストークン

    認証するには、次を設定します。

    • AuthSchemePersonalAccessToken
    • Token:Databricks サーバーへの接続に使用するトークン。Databricks インスタンスのユーザー設定ページに移動してアクセストークンタブを選択することで取得できます。

    その他の認証方法については、ヘルプドキュメント の「はじめに」セクションを参照してください。

  6. 接続情報の入力が完了したら、「保存およびテスト」をクリックします。

Databricks 接続プロパティの取得・設定方法

Databricks クラスターに接続するには、以下のプロパティを設定します。

  • Database:Databricks データベース名。
  • Server:Databricks クラスターのサーバーのホスト名
  • HTTPPath:Databricks クラスターのHTTP パス。
  • Token:個人用アクセストークン。この値は、Databricks インスタンスのユーザー設定ページに移動してアクセストークンタブを選択することで取得できます。
Databricks インスタンスで必要な値は、クラスターに移動して目的のクラスターを選択し、Advanced Options の下にあるJDBC/ODBC タブを選択することで見つけることができます。

Databricks への認証

CData は、次の認証スキームをサポートしています。

  • 個人用アクセストークン
  • Microsoft Entra ID(Azure AD)
  • Azure サービスプリンシパル
  • OAuthU2M
  • OAuthM2M

個人用アクセストークン

認証するには、次を設定します。

  • AuthSchemePersonalAccessToken
  • Token:Databricks サーバーへの接続に使用するトークン。Databricks インスタンスのユーザー設定ページに移動してアクセストークンタブを選択することで取得できます。

その他の認証方法については、ヘルプドキュメント の「はじめに」セクションを参照してください。

API Server のユーザー設定

次に、API Server 経由でDatabricks にアクセスするユーザーを作成します。「Users」ページでユーザーを追加・設定できます。やってみましょう。

  1. 「Users」ページで ユーザーを追加をクリックすると、「ユーザーを追加」ポップアップが開きます。
  2. 次に、「ロール」、「ユーザー名」、「権限」プロパティを設定し、「ユーザーを追加」をクリックします。
  3. その後、ユーザーの認証トークンが生成されます。各ユーザーの認証トークンとその他の情報は「Users」ページで確認できます。

Databricks 用のAPI エンドポイントの作成

ユーザーを作成したら、Databricks のデータ用のAPI エンドポイントを作成していきます。

  1. まず、「API」ページに移動し、 「 テーブルを追加」をクリックします。
  2. アクセスしたい接続を選択し、次へをクリックします。
  3. 接続を選択した状態で、各テーブルを選択して確認をクリックすることでエンドポイントを作成します。

OData のエンドポイントを取得

以上でDatabricks への接続を設定してユーザーを作成し、API Server でDatabricks データのAPI を追加しました。これで、OData 形式のDatabricks データをREST API で利用できます。API Server の「API」ページから、API のエンドポイントを表示およびコピーできます。

CORS を有効にする

AngularJS では、サーバーでCORS (Cross-origin resource sharing) を有効にする必要があります。API Server の[SETTINGS Server]タブに移動すると、CORS を有効にできます。 以下の設定を調整する必要があります。

  • チェックボックスをクリックして「Enable cross-origin resource sharing (CORS)]をクリックします。
  • チェックボックスをクリックして[Allow all domains without '*']を選択するか、Access-Control-Allow-Origin で接続を許可するドメインを指定します。
  • Access-Control-Allow-Methods を[GET,PUT,POST,OPTIONS]に設定します。
  • Access-Control-Allow-Headers を[authorization]に設定します。
  • [Save Changes]をクリックします。

OData フィードのサンプルURL

Databricks への接続を構成し、ユーザーを作成してAPI Server にテーブルを追加すれば、それらのテーブルのOData フィードにアクセスできます。 以下は、テーブルにアクセスするためのURL とテーブルのリストです。テーブルへのアクセスについては、([API Server Web]ページの右上にあるAPI リンクをクリックして)API Server のAPI ページに移動できます。 URL には、API Server のアドレスポートが必要です。 Angular を使用しているため、デフォルトではJSON データを返さないURL の末尾に@json パラメータを追加します。

Table         URL
Entity (table) List http://address:port/api.rsc/
Metadata for table Customers http://address:port/api.rsc/Customers/$metadata?@json
Account http://address:port/api.rsc/Customers

返されるフィールドを制限する場合には、標準のOData フィードと同様に、$select パラメータを$filter、$orderby、$skip、$top などの他の標準のOData URL パラメータとともにクエリに追加できます。 サポートされているOData クエリの詳細については、ヘルプドキュメントを参照してください。

シングルページアプリケーションの構築

API Server のセットアップが完了したら、SPA を構築する準備が整います。これは単純なデモンストレーションなので、すべてのCSS、スクリプト、およびAngular コントローラーを1 つのファイルに含め、AngularJS サービス、ファクトリ、およびカスタムディレクティブによって提供される機能を意図的に使用しないようにします。

CSS 定義とAngularJS ライブラリのインポート

まずCSS ルールセットをいくつか作成し、table、th、td、tr 要素を変更してデータのテーブルをフォーマットします。また、SPA で使用するためにAngularJS ライブラリをインポートする必要があります。


  <style>
  table, th, td {
    border:1px solid grey;
    border-collapse: collapse;
    padding:5px;
  }
  table tr:nth-child(odd) {
    background-color: #f1f1f1;
  }
  table tr:nth-child(even) {
    background-color: #ffffff;
  }
  </style>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>

Angular アプリとコントローラーオブジェクトの作成と参照

次に、HTML の[body]タグにng-app ディレクティブとng-controller ディレクティブを追加します。これは、本体がAngular を使用す唯一の場所であるために必要な操作です。 そして、HTML 本文の最後にAngular アプリとコントローラーを作成及び定義するスクリプトタグを作成します。


<body ng-app="DataApp" ng-controller="SimpleController">
...
<script>
var app = angular.module('DataApp', []);
app.controller('SimpleController', function($scope, $http) {
    //we will add code here
    });
</script>
</body>

コントローラーの定義

ここでのコントローラーはAngular オブジェクトを初期化してSPA を設定するinit、選択したテーブルのカラムを取得するgetTableColumns、選択したカラムから選択したフィールドのデータを取得するgetTableData の3つの関数で構成されます。 コントローラを作成するときの最初のアクションとして、init 関数を呼び出します。 他のすべての関数は必要に応じて呼び出され、これらの関数呼び出しでDatabricks のデータを取得するために、API Server に対して必要なHTTP GET 呼び出しを行います。


init();

/*
 * Initialize the data object, which will be used with Angular to
 * build the different parts of our SPA and to retrieve data from
 * the API Server.
 */
function init() {
  $scope.data = {
  availableTables: [],
                 availableColumns: [],
                 selectedTable: {},
                 tableData: []
  };

  /*
   * Call to the API Server to get the list of Tables, select the
   * first table by default, and retrieve the available columns.
   *
   * The call to the API Server returns standard OData, so the
   * data we need is in the value object in the JSON returned.
   */
  $http.get("http://server:port/api.rsc",{headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
    .then(function (response) {
        $scope.data.availableTables = response.data.value;
        $scope.data.selectedTable = $scope.data.availableTables[0];
        $scope.getTableColumns();
        });
}

/*
 * Call to the API Server to get the list of columns for the
 * selected table.
 *
 * The data returned here is not standard OData, so we drill
 * down into the response to extract exactly the data we need
 * (an array of column names).
 *
 * With the column names retrieved, we will transform the array
 * of column names into an array of objects with a name and Id
 * field, to be used when we build an HTML select.
 */
$scope.getTableColumns = function () {
  $scope.data.tableData = [];
  $scope.data.selectedColumns = [];
  table = $scope.data.selectedTable.url;
  if (table != "") {
    $http.get("http://server:port/api.rsc/" + table + "/$metadata?@json", {headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
      .then(function (response) {
          $scope.data.availableColumns = response.data.items[0]["odata:cname"];
          for (i = 0; i < $scope.data.availableColumns.length; i++) {
            $scope.data.availableColumns[i] = { id: i, name: $scope.data.availableColumns[i] };
          }
          });
  }
}

/*
 * Call to the API Server to get the requested data.We get the data
 * based on the table selected in the associated HTML select.
 * Then we create a comma-separated string of the selected columns.
 *
 * With the table and columns known, we can make the appropriate call
 * to the API Server.Because the driver returns standard OData, the
 * table data is found in the value field of the response.
 */
$scope.getTableData = function () {
  table = $scope.data.selectedTable.url;
  columnsArray = $scope.data.selectedColumns;
  columnString = "";
  for (i = 0; i < columnsArray.length; i++) {
    if (columnString != "") {
      columnString += ",";
    }
    columnString += columnsArray[i].name;
  }

  if (table != "") {
    $http.get("http://server:port/api.rsc/" + table + "?$select=" + columnString, {headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
      .then(function (response) { $scope.data.tableData = response.data.value; });
  } else {
    $scope.data.tableData = [];
  }
}

Web ページの構成

コントローラを定義したら、Angular を使用してWeb ページを構築する準備が整います。単純なページには、テーブルを選択するための選択ボックス、カラムを選択するための選択(複数)ボックス、データを取得するためのボタン、およびデータを表示するためのテーブルの4つの主要部分があります。 これら4つの部分の1つずつを通して、Angular の使用方法について説明します。

テーブルを選択

最初のselect 要素では、ng-options ディレクティブを使用し、使用可能なテーブル(前述のinit 関数から取得) を反復処理し、select 要素にデータを入力します。 ng-model ディレクティブを使用して、選択したオプションの値をdata.selectedTable フィールドに割り当てます。 選択したテーブルが変更された場合は、getTableColumns 関数を呼び出して使用可能なカラムを再設定します。


  <label>Select a Table</label>
  <br />
  <select name="tableDropDown" id="tableDropDown"
          ng-options="table.name for table in data.availableTables track by table.url"
          ng-model="data.selectedTable"
          ng-change="getTableColumns()">
  </select>

カラムを選択

2番目のselect 要素では、再びng-options ディレクティブを使用しますが、今回は、(getTableColumns 関数によって取得された)使用可能なカラムを反復処理します。 使いやすさのために、select 要素に入力する前にカラムを名前でソートします。 この選択には複数 の属性が含まれているため、複数のカラムを選択できます。 選択した各列がdata.selectedColumns 配列に追加されます。カラムを選択すると、各列のテーブルヘッダーが作成されます(以下のデータテーブルのセクションを参照)。


  <label>Select Columns</label>
  <br />
  <select name="columnMultiple" id="columnMultiple"
          ng-options="column.name for column in data.availableColumns | orderBy:'name' track by column.id"
          ng-model="data.selectedColumns"
          multiple>
  </select>

テーブルデータを取得

このボタンでは、ボタンがクリックされるたびにgetTableData 関数を呼び出します。ユーザーがカラムを選択していない場合に、ng-disabled ディレクティブを使用してボタンを無効にしていることに注意してください。 また、選択したテーブルの名前でボタンのテキストを動的に更新します。


  <button name="getTableData" id="btnGetTableData"
          ng-click="getTableData()"
          ng-disabled="data.selectedColumns.length == 0">
  Get {{data.selectedTable.name}} Data
  </button>

テーブルデータを表示

このセクションは、選択したテーブルのデータを表示するというSPA の最終目標を満たしています。そのために、いくつかのng-repeat ディレクティブを使用します。1つは選択したカラムを反復処理してテーブルヘッダーを作成し、もう一つは返されたデータの行を反復処理して対応するデータを特定の行に表示します。

Angular を使用することで、表示するカラムを動的に決定できます。データがクリックされる「前」に選択されたカラムのみにデータが含まれることに注意してください。 使用可能なすべてのカラムを選択し、ボタンをクリックしてテーブルデータを取得してから、戻って別のカラムを選択または選択解除し、表示されるデータを変更することは簡単にできます。 選択したテーブルを変更すると、すべてのデータがクリアされます。


  <table>
    <tr>
      <th ng-repeat="column in data.selectedColumns | orderBy:'name'">{{column.name}}</th>
    </tr>
    <tr ng-repeat="row in data.tableData">
      <td ng-repeat="column in data.selectedColumns">{{ row[column.name] }}</td>
    </tr>
  </table>

アプリの完成

<!DOCTYPE html>

<html>
<style>
table, th, td {
border:1px solid grey;
        border-collapse: collapse;
padding:5px;
}
table tr:nth-child(odd) {
  background-color: #f1f1f1;
}
table tr:nth-child(even) {
  background-color: #ffffff;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="DataApp" ng-controller="SimpleController">
<label>Select a Table</label>
<br>
<select name="tableDropDown" id="tableDropDown"
ng-options="table.name for table in data.availableTables track by table.url"
ng-model="data.selectedTable"
ng-change="getTableColumns()">
</select>
<label>Select Columns</label>
<br />
<select name="columnMultiple" id="columnMultiple"
ng-options="column.name for column in data.availableColumns | orderBy:'name' track by column.id"
ng-model="data.selectedColumns"
multiple>
</select>
<button name="getTableData" id="btnGetTableData"
ng-click="getTableData()"
ng-disabled="data.selectedColumns.length == 0">
Get {{data.selectedTable.name}} Data
</button>
<br />
<br />

<table>
<tr>
<th ng-repeat="column in data.selectedColumns | orderBy:'name'">{{column.name}}</th>
</tr>
<tr ng-repeat="row in data.tableData">
<td ng-repeat="column in data.selectedColumns">{{ row[column.name] }}</td>
</tr>
</table>
<script>
var app = angular.module('DataApp', []);
app.controller('SimpleController', function($scope, $http) {
    init();

    /*
     * Initialize the data object, which will be used with Angular to
     * build the different parts of our SPA and to retrieve data from
     * the API Server.
     */
    function init() {
    $scope.data = {
    availableTables: [],
    availableColumns: [],
    selectedTable: {},
    tableData: []
};

/*
 * Call to the API Server to get the list of tables, select the
 * first table by default, and retrieve the available columns.
 *
 * The call to the API Server returns standard OData, so the
 * data we need is in the value object in the JSON returned.
 */
$http.get("http://server:port/api.rsc",{headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
.then(function (response) {
    $scope.data.availableTables = response.data.value;
    $scope.data.selectedTable = $scope.data.availableTables[0];
    $scope.getTableColumns();
    });
}

/*
 * Call to the API Server to get the list of columns for the
 * selected table.
 *
 * The data returned here is not standard OData, so we drill
 * down into the response to extract exactly the data we need
 * (an array of column names).
 *
 * With the column names retrieved, we will transform the array
 * of column names into an array of objects with a name and Id
 * field, to be used when we build an HTML select.
 */
$scope.getTableColumns = function () {
  $scope.data.tableData = [];
  $scope.data.selectedColumns = [];
  table = $scope.data.selectedTable.url;
  if (table != "") {
    $http.get("http://server:port/api.rsc/" + table + "/$metadata?@json", {headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
      .then(function (response) {
          $scope.data.availableColumns = response.data.items[0]["odata:cname"];
          for (i = 0; i < $scope.data.availableColumns.length; i++) {
          $scope.data.availableColumns[i] = { id: i, name: $scope.data.availableColumns[i] };
          }
          });
  }
}

/*
 * Call to the API Server to get the requested data.We get the data
 * based on the table selected in the associated HTML select.
 * Then we create a comma-separated string of the selected columns.
 *
 * With the table and columns known, we can make the appropriate call
 * to the API Server.Because the driver returns standard OData, the
 * table data is found in the value field of the response.
 */
$scope.getTableData = function () {
  table = $scope.data.selectedTable.url;
  columnsArray = $scope.data.selectedColumns;
  columnString = "";
  for (i = 0; i < columnsArray.length; i++) {
    if (columnString != "") {
      columnString += ",";
    }
    columnString += columnsArray[i].name;
  }

  if (table != "") {
    $http.get("http://server:port/api.rsc/" + table + "?$select=" + columnString, {headers: {"Authorization":"Basic "  + btoa("MyUser:MyAuthtoken")}})
      .then(function (response) { $scope.data.tableData = response.data.value; });
  } else {
    $scope.data.tableData = [];
  }
}
});
</script>
</body>
</html>

無料トライアルと詳細

Angular で構築されたWeb アプリケーションからDatabricks (またはサポートされている他のデータソースからのデータ)に接続したい場合は、今すぐAPI Server の30日間無料トライアルダウンロードしてください。 API のより一般的な情報およびサポートされている他のデータソースについてはAPI Server ページを参照してください。

はじめる準備はできましたか?

詳細はこちら、または無料トライアルにお申し込みください:

CData API Server お問い合わせ