はじめに
本連載ではこれまでAzureの提供するデータストアサービスとして、Azure StorageやSQLデータベースを紹介してきました。今回は、NoSQLデータベースサービスであるCosmos DBについて紹介していきます。
Azure Cosmos DBとは
Cosmos DBはAzureのデータベースサービスのうち、NoSQLデータベースを扱うサービスです。NoSQLは主にビッグデータを取り扱う際に使用される傾向にあります。ビッグデータを扱う際は3つの「V」、「Volume(膨大なデータ量)」、「Velocity(高速な処理)」、「Variety(多様なデータ形式)」に対応する必要があると言われていますが、これらを従来のRDB(SQL)を使用して処理しようすると、性能やコスト、スキーマ変更への柔軟な対応といった面への対応に多大な労力が必要となってしまいます。
NoSQLはビッグデータをいかに効率的に処理するかに主眼を置いて開発されたデータベースのため、高速なデータアクセスや高いスケーラビリティ、スキーマレスなデータ構造などの機能を有しています。また、NoSQLは「Not Only SQL」の略であることから、SQLと補完的な立場であるとも言われています。前述の通りビッグデータ対応に特化している反面、SQLが持つテーブル間のリレーションやトランザクション処理におけるACID特性などの概念や機能が存在しないNoSQLデータベース製品が多く、SQLとNoSQLとでユースケースによって住み分けをすべきだと考えられています。以下の表はRDB(SQL)とNoSQLの長短所についてまとめたものです。
RDBとNoSQLの比較
データベース | 長所 | 短所 |
---|---|---|
RDB | 豊富な機能、データ整合性の担保(ACID特性) | ビッグデータ対応 |
NoSQL | 高速な読み書き、スケーラブル、スキーマレス | 限定的な機能、緩い整合性(結果整合性) |
Cosmos DBも同様にNoSQLデータベースとしての特徴を持っています。また、他のNoSQLデータベースにはないCosmos DBならではの特徴も存在します。
Cosmos DBの特徴
Cosmos DBの大きな特徴には「グローバル分散」と「マルチモデルのデータベース」の2つが挙げられます。 まず「グローバル分散」ですが、これはAzureが世界中に展開するリージョン(データセンター)へのデータのレプリケーションをサポートし、データを世界中に分散して保持することを可能としています。世界中に分散してデータを保持することでアプリケーションのユーザは自身の現在地と地理的に近いリージョンのCosmos DBからデータを取得できるようになり、ネットワーク遅延による待機時間も削減できます。またデータの複製を保存するため高可用性も保証されます。Cosmos DBはグローバル分散を念頭に置いて開発されたデータベースのため、容易にデータベースをグローバル分散させることが可能となっています。
次に「マルチモデルのデータベース」についてですが、Cosmos DBでは複数のデータモデルの中から選択してデータベースを作成することができるようになっています。データモデルにはそれぞれ対応するAPIが存在し、Cosmos DBのSDKによって複数の言語から利用することができるようになっています。
Cosmos DBがサポートするデータモデル
データモデル | 説明 | 対応するAPI |
---|---|---|
ドキュメント型 | JSON形式のドキュメントを保存できるデータモデル | SQL API、MongoDB API |
グラフ型 | データとデータの繋がりをグラフ構造で保持するデータモデル | Graph(Gremlin) API |
テーブル型 | スキーマレスなテーブル構造でデータを保持するデータモデル | Table (キー・バリュー) API |
列ファミリ型 | Apache Cassandraベースのデータモデル | Cassandra API |
上の表は執筆時点でCosmos DBがサポートしているデータモデルと対応するAPIの表です。
クイックスタートアプリを使ってCosmos DBにアクセスするアプリを作ろう
ここからはCosmos DB上のデータにアクセスするアプリケーションを作成してCosmos DB SDKの使い方を確認していきましょう。 今回はドキュメント型のデータモデルのデータベースにSQL APIでアクセスするアプリケーションを作成します。
Cosmos DBを使い始める
Cosmos DBは他のAzureサービスと同様にAzureのWebポータル上から利用を開始することができます。それ以外にも、開発用途としてWindows PC上で動作させることのできるCosmos DB Emulatorを使うことで料金を気にせずにCosmos DBの機能を確かめることもできます。 また、最近ではAzure上のCosmos DBを7日間無料で使用することができるようになりました。今回はこの7日間無料使用版を使って説明を進めていきます。
Azure Cosmos DBのウェブサイトへアクセスして、トップ画面の「Azure Cosmos DBを無料で試す」ボタンをクリックします。下のページに移動します。
7日間無料使用版のWebページ下部の「SQL」部分の作成ボタンを選択します。Microsoftのアカウントでのログイン画面が表示されるので、Microsoftアカウントでログインして下さい。ログインするとデータベースの作成が開始され、そのまましばらく待つとデータベースの作成が完了しAzureポータル画面へと移動できるようになります。「Azure Portalで開く」を選択します。
Azureポータルに遷移すると、Cosmos DBの「クイックスタート」画面が表示されます。この画面では、サンプル用のコレクションの作成と、Cosmos DBにアクセスする言語別のサンプルコードをダウンロードをすることができます。
ここでは、Node.jsを使ったアプリケーションを選択します。このサンプルを実行すると、ToDo(タスク)管理アプリが表示されます。このアプリではタスクの名前やそのカテゴリー、作成日付とタスクの完了フラグを管理するために、Cosmos DBを使用しています。
実際に手元でこのアプリケーションを動かしながら、Cosmos DBの使い方について確認していきましょう。
コレクションの作成とアプリケーションコードのダウンロード
Node.jsのタブを選択し、手順に従い「1 コレクションの追加」から「'item'コレクションの作成」を行います。しばらくすると「Items」という名称のコレクションが作成されます。
ここで一度、コレクションやデータベースといったCosmos DBのデータベース構成の用語について整理します。以下の図はドキュメント型データモデルの場合のCosmos DBのデータベースの構成を表したものです。
「データベースアカウント」は複数の「データベース」をまとめて管理する概念です。データベースアカウントの作成時にドキュメント型、グラフ型といったデータモデルと、リージョンを決定します。「データベース」にはさらに複数の「コレクション」が含まれています。コレクション配下のリソースへのアクセスを制御するために、データベースでは「ユーザー」と「アクセス権限」も管理します。「コレクション」はデータの実体である「ドキュメント」や、ユーザーが自由に設定できる「ストアドプロシージャ」、「トリガー」、「ユーザ定義関数」をJSON形式で保持します。「ドキュメント」は通常のJSONドキュメントの他に、「添付ファイル」と呼ばれる形式で画像やビデオ等のメディアファイルへの参照情報をJSONで保持することもできます。
RDBのイメージに照らし合わせて、データベースアカウントはデータベースサーバーやインスタンスに、データベースはデータベースに、コレクションはテーブルに、ドキュメントはレコードに置き換えて考えると分かりやすいかもしれません。
コレクションの作成が完了すると「2 Node.jsアプリをダウンロードして実行する」でダウンロードボタンが有効になるので、選択してアプリケーションコードをダウンロードします。
ダウンロードしたZIPファイル(DocumentDB-Quickstart-Node.zip)を任意のディレクトリに移して展開し、以下のリストの手順でアプリケーションの起動まで行います。ここから先は、Node.jsがインストールされていることが前提となっています。まだインストールしていない人は、Node.jsをインストールしておきましょう。
Node.jsアプリケーションの実行
# ダウンロードし、展開したアプリケーションのディレクトリに移動する
$ cd DocumentDB-Quickstart-Node
# 依存ライブラリのダウンロード
$ npm install
・・・中略
# アプリケーションの起動
$ npm start
Node.jsアプリケーションの起動が完了したら、ブラウザから「http://localhost:3000」にアクセスしてみましょう。「My ToDo List」というタイトルのToDo管理アプリが表示されるかと思います。
画面下部の「Item Name」と「Item Category」にそれぞれToDoとそのカテゴリを入力し、「Add item」ボタンでデータを登録する仕組みです。データの保存先が先ほど作成したCosmos DBのitemコレクションになります。試しに1件データを登録してみます。
登録が完了すると画面上部のToDoリストが更新され、登録したデータが表示されます。ここでCosmos DBのコレクションにドキュメントが保存されているかも確認してみましょう。Azurポータルのクイックスタート画面で「3 データの操作」の「データエクスプローラーを開く」からデータエクスプローラーを開きます。
データエクスプローラーではデータベース(ToDoList)、コレクション(items)の順に辿り、ドキュメント(アプリケーションから登録したデータ)を確認することができます。以下の図では先ほどアプリケーションから登録したデータを表示しています。JSON形式でデータが登録されていることが分かるかと思います。「name」や「category」はアプリケーションの画面上で入力した内容です。他にも登録日時(date)やToDoの実施済みフラグ(completed)などの項目もあります。「_rid」や「_ts」などのアンダーバーから始まるフィールドは、Comsmos DBが自動で付与するメタデータで、どのドキュメントにも必ず付与されます。
クイックスタート用アプリケーションの構造を理解する
ここからはクイックスタートで使用しているアプリケーションの実装を見ながら、Cosmos DBへのデータアクセス方法を確認していきましょう。まずはダウンロードしたNode.jsアプリケーションのディレクトリ構成から確認していきます。
/DocumentDB-Quickstart-Node
┣ /bin
┃ ┗ www ・・・アプリケーションの起動用スクリプト
┣ /models
┃ ┣ docdbUtils.js ・・・Cosmos DBのデータベースとコレクション用のユーティリティクラス
┃ ┗ taskDao.js ・・・Itemsコレクションにデータアクセスするクラス
┣ /routes
┃ ┗ taskList.js ・・・画面とtaskDaoをつなぐコントローラークラス
┣ /views
┃ ┗ index.jade ・・・ToDoリストの表示・登録画面
┣ app.js ・・・アプリケーション全体のセットアップを行うファイル
┣ config.js ・・・Cosmos DBの接続情報についてまとめたファイル
┗ package.json ・・・依存するライブラリの情報を記載したファイル
このうちCosmos DBのデータアクセスに関わる「app.js」、「taskDao.js」、「docdbUtils.js」のコードを中心に説明をしていきます。
アプリケーションとCosmos DBクライアントの初期化
まずはapp.jsから見ていきます。app.jsにはWebアプリケーションとして必要となるセットアップ処理がいくつか記述されています。その中で、Cosmos DBに関わる初期化処理も行っています。以下のリストはCosmos DBに関わる部分を抜粋したものです。
Cosmos DBクライアントの初期化(app.js)
// クライアントの初期化 ・・・①
var docDbClient = new DocumentDBClient(config.host, {
masterKey: config.authKey
});
// taskDaoのインスタンス化 ・・・②
var taskDao = new TaskDao(docDbClient, config.databaseId, config.collectionId);
// taskListのインスタンス化 ・・・③
var taskList = new TaskList(taskDao);
// taskDaoの初期化 ・・・④
taskDao.init();
①ではCosmos DBにSQL APIでアクセスすることのできるクライアントインスタンスを生成しています。クライアントは、Microsoftより提供される「documentdb」というnpmパッケージ内のDocumentDBClientクラスをインスタンス化することで使用することができます。引数には接続先となるCosmos DBのURLと認証用のキー情報をconfig.jsから参照して設定します。 なお、ここで登場する「DocumentDB」という名前ですが、これはSQL APIの前身となるAPIの名称で、現在でも互換性維持のためにライブラリ等でにこの旧名称が使われています。
クライアントの初期化後、Cosmos DBのItemsコレクションにデータアクセスするTaskDaoクラスをインスタンス化します(②)。引数にはクライアントとデータベース名、コレクション名を渡しています。さらにこのTaskDaoのインスタンス引数にTaskListをインスタンス化しています(③)。TaskListには画面で起こるアクション(ToDoの参照、登録、更新)に対応したメソッドが用意されており、それぞれのメソッドが対応するTaskDaoのメソッドを呼び出すようになっています。
最後にインスタンス化したTaskDaoのinitメソッドを呼び出しています(④)。このメソッドではCosmos DBのデータベースとコレクションに対する初期化処理を実行しています。
Cosmos DBのデータベースとコレクションの初期化処理
TaskDaoクラスのinitメソッドを詳しく見ていきましょう。
initメソッド(taskDao.js)
init: function (callback) {
var self = this;
docdbUtils.getOrCreateDatabase(self.client, self.databaseId, function (err, db) {
if (err) {
callback(err);
} else {
self.database = db;
docdbUtils.getOrCreateCollection(self.client, self.database._self, self.collectionId, function (err, coll) {
if (err) {
callback(err);
} else {
self.collection = coll;
}
});
}
});
},
initメソッドでは「docdbUtils」の「getOrCreateDatabase」メソッドと「getOrCreateCollection」メソッドを呼び出しています。名前の通り、データベース・コレクションの取得または作成を行うメソッドであることが分かります。それではさらにdocdbUtilsを確認していきます。
getOrCreateDatabaseメソッド(docdbUtils.js)
getOrCreateDatabase: function (client, databaseId, callback) {
// 検索クエリの構築 ・・・①
var querySpec = {
query: 'SELECT * FROM root r WHERE r.id= @id',
parameters: [{
name: '@id',
value: databaseId
}]
};
// SQL APIによるデータベースへのアクセス ・・・②
client.queryDatabases(querySpec).toArray(function (err, results) {
if (err) {
callback(err);
} else {
// データベースが存在しなかった場合
if (results.length === 0) {
var databaseSpec = {
id: databaseId
};
// データベースの新規作成 ・・・③
client.createDatabase(databaseSpec, function (err, created) {
// 作成したデータベースオブジェクトを返却
callback(null, created);
});
} else {
// データベースオブジェクトの返却 ・・・④
callback(null, results[0]);
}
}
});
},
docdbUtilsのgetOrCreateDatabaseメソッドでは、SQL APIを使用してCosmos DBからデータベースに対する操作を行っています。このメソッドでは、まずデータベースがCosmos DB上に存在するかを確認し、存在しなければデータベースを新規作成、存在すればデータベースの情報を返す流れになっています。データベースがCosmos DBに存在するかの確認にはSQLを使用します(①)。ここではデータベースの名前(databaseId)を検索条件としたSQL文を含む検索用オブジェクト(querySpec)を構築し、クライアントインスタンスのqueryDatabasesメソッドの引数に設定して検索を実行しています(②)。queryDatabasesメソッドの戻り値から検索結果のリスト(results)が取得し、リストが空であればcreateDatabaseメソッドを使いデータベースを新規作成します(③)。リストにデータが存在する場合は、リストの先頭に含まれるデータを返却します(④)。
getOrCreateCollectionメソッドについても、使用するクライアントインスタンスのメソッドが「queryDatabases」や「createDatabse」ではなく「queryCollections」や「createCollection」を使用しているという違いはありますが、同様の流れでコレクションの検索と作成を行っています。 このようにCosmos DBへのSQL APIでのアクセス方法の基本形は、SQL文を含む検索用オブジェクトを適切なクライアントインスタンスのメソッドに渡すことで実現しているのです。
ドキュメントの操作
ここまでデータベースとコレクションを例にSQL APIの使用方法を説明してきましたが、ドキュメントに関してもほぼ同様の方法で操作することができます。
例えば未完了のToDo一覧を取得する場合は、「SELECT * FROM root r WHERE r.completed=@completed」というSQL文を含むquerySpecオブジェクトをtaskListのshowTasksメソッドで生成し、taskDaoのfindメソッドに渡して検索しています。
findメソッド(taskDao.js)
find: function (querySpec, callback) {
var self = this;
// コレクション内のドキュメントを検索する
self.client.queryDocuments(self.collection._self, querySpec).toArray(function (err, results) {
if (err) {
callback(err);
} else {
// 取得したドキュメントのリストを返却する
callback(null, results);
}
});
},
クライアントインスタンスの「queryDocuments」メソッドを使用してドキュメントを検索しています。データベースやコレクションの場合と比較して、実装方法に大きな違いが無いことが分かるかと思います。
まとめ
駆け足でしたがCosmos DBの概要について説明し、ドキュメント型データモデルでの実装方法についてクイックスタートアプリを題材に確認してきました。Cosmos DBには複数のデータモデルとそれらに対応するAPIが用意されており、使い方も多岐に渡るので本稿のように無料利用枠やEmulator等を使ってCosmos DBを触りながら機能を確かめていくことをお薦めします。次回はCosmos DBとも連携可能な検索サービスであるAzure Searchについて紹介する予定です。
WINGSプロジェクト 秋葉龍一 著/山田祥寛監修
<WINGSプロジェクトについて>テクニカル執筆プロジェクト(代表山田祥寛)。海外記事の翻訳から、主にWeb開発分野の書籍・雑誌/Web記事の執筆、講演等を幅広く手がける。一緒に執筆をできる有志を募集中