国内最大のCouchbaseイベント、「Couchbase Live Tokyo」が開催されます!
サーバとモバイルの各トラックでそれぞれホットな話題の提供、欧州航空会社大手Ryanairの事例紹介、また今回スポンサーを頂きました各企業様より他ソリューションとの連携など、魅力的なセッションを多数用意しております。
イベントの詳細およびお申込みはこちらよりご参照ください。
ハンズオンの内容でご不明な点や、Couchbaseに関するご質問は、FacebookのJapan Couchbase User Group、もしくは、couchbasejp@couchbase.comへメールでお問い合わせください。
エクササイズ 1: Gitプロジェクトのクローン
本ハンズオンでは、2015年6月に米国で開催された「Couchbase Connect 2015」カンファレンスで行われたワークショップのGitプロジェクトを利用します。
ちなみに、同カンファレンスの各セッション内容はスライドとビデオで公開されています。Couchbaseユーザ企業による事例の発表や、Couchbase Server 4.0の技術的な内容を詳細に解説するセッション、Couchbaseモバイルソリューションに関するものなど、様々なセッションが閲覧できます。また、日本国内版として、2015年8月31日に「Couchbase Live Tokyo」が開催されます。参加登録はこちらからお気軽にどうぞ!
以下のコマンドでワークショップのGitプロジェクトをクローンしましょう:
git clone git@github.com:couchbaselabs/Workshop.git
クローンしたWorkshopの中には、mobileとserverのディレクトリがあります。本連載ではserverのワークショップを実践していきます。Workshop/serverディレクトリの中には以下のディレクトリがあります:
- code.net: .NET用
- code.node: Node.js用
- code: Java用
- presentations: スライド資料
本記事でスライド資料の内容を解説しながら進めていきます。Java、.NET、Node.js用のプロジェクトがそれぞれあります。本記事中では、Javaについて記載しますが、お好きなプログラミング言語を選択してください。
エクササイズ 2: Couchbase Serverへの接続
まずは、お使いのIDEを起動し、プロジェクトをインポートしましょう。Javaの場合は、Mavenプロジェクトとしてインポートしてください。プロジェクト名の末尾が_initialのプロジェクトが、エクササイズの開始時点、_finishedがエクササイズの完了時点となります。_finishedは模範解答として必要に応じて参照してください。
このエクササイズでは、sdk_intro_initialプロジェクトを利用します。
これから、Couchbase Serverへ接続するクライアントのコードを記述していくわけですが、ここで用語の整理をしておきましょう:
-
ノード(node):
Couchbase Serverをインストールし、を実行しているサーバノードです。 -
クラスタ(cluster):
1つ以上のノードで構成される、Couchbase Serverノードの集合です。Couchbaseのクライアントライブラリを利用すると、クラスタ内のいずれかのノードに接続できれば、その後のアクセスはクライアントライブラリの内部で自動的に適切なノードへと振り分けてくれます。クラスタ内のノード数を増やせば、データベースの性能、容量をリニアにスケールアウトできるのがCouchbaseの特徴ですね。 -
バケット(bucket):
クラスタ内に保存するデータの入れ物です。1クラスタにはN個のバケットを持つことができます。 -
ドキュメント(document):
バケット内に保存するデータの単位です。各ドキュメントはバケット内でユニークとなるキーを持っています。
com.couchbase.workshopパッケージにある、DatabaseConfig.javaを開くと、以下のプロパティが定義されています:
@Value("${hostname:127.0.0.1}") private String hostname; @Value("${bucketName:travel-sample}") private String bucketName; @Value("${password:}") private String password;
連載の第一回ではローカル環境にCouchbase Serverをインストールしました。他のサーバにインストールしたCouchbase Serverへ接続する場合は、hostnameのIPアドレスを変更してください。インストールの途中にロードしたtravel-sampleバケットに接続します。passwordはバケットのパスワードで、travel-sampleバケットにはパスワードを設定していないため、空白のままで大丈夫です。
それでは、コーディングを始めましょう! DatabaseConfig.javaのcouchbaseEnvironmentメソッドの中身を実装します。
CouchbaseEnvironment couchbaseEnvironment() { return null; // TODO fix me }
このメソッドでは、CouchbaseEnvironmentのインスタンスを返すように実装します。CouchbaseEnvironmentはkey/valueのアクセスや、クエリなど、各オペレーションのタイムアウト設定を提供するインタフェースです。デフォルトの設定を実装した、DefaultCouchbaseEnvironmentというクラスが用意されているので、こちらを利用しましょう。
デフォルトの設定で良ければ、
return DefaultCouchbaseEnvironment.create();
とするだけで良いですし、クエリのタイムアウト値を変更したい場合は、builderを利用すると良いでしょう:
return DefaultCouchbaseEnvironment.builder().queryTimeout(300).build();
続いて、同クラスのclusterとbucketメソッドも実装しましょう。
clusterメソッドでは、Clusterのインスタンスを返します。CouchbaseClusterクラスのcreateメソッドに、couchbaseEnvironmentメソッドの実行結果と、hostnameを渡して実行し、生成したClusterのインスタンスを返します。
bucketメソッドでは、clusterメソッドを実行して取得したClusterのインスタンスを利用します。ClusterインスタンスのopenBucketメソッドにbucketnameとpasswordを渡して、Bucketのインスタンスを取得します。
これで、Couchbase Serverへの接続部分の実装は完成です! 実装例は、sdk_intro_finishedも参考にしてください。
Application.javaを実行し、確認してみましょう。本アプリケーションはSpring Bootを利用していて、Application.javaを実行すると、8080ポートでリスンするWebアプリが起動します。まだCouchbase Serverクラスタに接続しただけですが、実行すると、ログで以下のメッセージが確認できます(記事用に一部省略しています):
[ main] CouchbaseCore : CouchbaseEnvironment: {sslEnabled=false, sslKeystoreFile='null', ..., dnsSrvEnabled=false} [ cb-io-1-1] Node : Connected to Node localhost [-computations-5] ConfigurationProvider : Opened bucket travel-sample
CouchbaseEnvironmentの設定内容がログに出力されているので、現在の接続設定や、どのような設定項目があるのかを確認するのに便利です。また、main、cb-io-1-1、computations-5など、複数のスレッドで実行されていることが分かります。CouchbaseのJava SDKでは、RxJavaを利用し、リアクティブな非同期のプログラミングをサポートしています。正しくライブラリを理解し、実装することで、マルチスレッドの恩恵を最大限に活かしたクライアントアプリケーションが開発できます。
非同期プログラミングを活かしたクライアントアプリケーションの開発について、より深く学習したい方には、「Couchbase公式開発者向けトレーニング CD220」をお勧めします! 次回開催は10月14日から16日までの3日間です。こちらよりお申し込みお待ちしております。
エクササイズ 3: ドキュメントのInsertとGet
Couchbase Serverクラスタへの接続が完了したので、JSONドキュメントの保存と取得を実装してみましょう!
SimpleController.javaを開くと、insertというメソッドがあります。このメソッドは@RequestMapping("/hello")で修飾されていて、WebアプリのURL、/helloにマッピングされています。Webブラウザなどから、http://localhost:8080/helloにアクセスすると、このメソッドが実行されるわけです。
そして、このクラスには、Bucket型のbucketというインスタンス変数があり、コンストラクタでこの変数を設定しています。コンストラクタには@Autowiredアノテーションが付いているので、Springフレームワークにより、自動的にbucketのインスタンスが渡されます。先のエクササイズで実装したDatabaseConfig.javaのbucketメソッドには@Beanアノテーションが付いていて、このメソッドで生成したBucketクラスのインスタンスが、SimpleControllerのコンストラクタに渡されるということになります。
では、insertメソッドの中で、新規JSONドキュメントの保存、保存したJSONドキュメントの参照を実装していきましょう。
JSONドキュメントのInsert
Couchbase Serverへのデータアクセスは全てBucketのインスタンスが提供しています。bucket.insert(document)で新規JSONドキュメントが実行できます。このメソッドを呼び出すためには、Document型のインスタンスでJSONドキュメントを作成する必要があります。
Documentインタフェースにはid、content、cas、expiryの値を返すメソッドが定義されています。IDはバケット内でユニークとなるドキュメントのID、contentはJSONデータとなります。CouchbaseではJSON以外のデータもcontentに設定して保存することができ、Documentインタフェースの実装クラスを見ると、JsonDocumentの他にBinaryDocumentや、SerializableDocumentなども用意されています。
ここでは、JSONドキュメントとして保存したいので、ずばりJsonDocumentを利用しましょう。クラスメソッドのJsonDocument.create(id, content)を呼び出すと、JsonDocumentのインスタンスを生成できます。ここで二つの引数が必要になります。
まず、idですが、今回はUUIDを利用して生成しましょう。Couchbaseでは、一つのバケット内にユーザや、商品など、複数のオブジェクトを保存するのが一般的です。このため、以下の様にIDの先頭にデータ種別を表す接頭語をつけることがよくあります。
String id = "user::" + UUID.randomUUID().toString();
続いて、contentとなるJsonObjectのインスタンスを生成しましょう。こちらもcreateクラスメソッドを呼び出し、続けてJSONドキュメント内の各プロパティを追加していきます。IDの接頭語に加えて、JSON内にtypeという属性でデータ型を管理することもよくあります。
JsonObject content = JsonObject .create() .put("hello", "world") .put("nanotime", System.nanoTime()) .put("type", "user");
IDとcontentが用意できたので、JsonDocumentのインスタンスを生成し、バケットに保存しましょう:
JsonDocument document = JsonDocument.create(id, content); bucket.insert(document);
JSONドキュメントのGet
SimpleController.javaの同じinsertメソッド内で、ドキュメントのinsertに続けて、保存したドキュメントを取得し、その中身をMap<String, Object>で返すコードを追記しましょう。
データアクセスはBucketのインスタンスが提供しているのでしたね。ドキュメントの取得にはbucket.get(id)を利用します。insertの際に利用したidを指定して、保存されたドキュメントを取得しましょう。そして、ドキュメントの中身をreturnします。
JsonDocument loaded = bucket.get(id); return loaded.content().toMap();
再びApplication.javaを実行して、http://localhost:8080/helloにアクセスしてみましょう。JSONドキュメントが保存され、保存したJSONがブラウザの画面に表示されるはずです。
また、http://localhost:8091/にアクセスし、Couchbase Server管理コンソールから、Data Bucketsタブのtravel-sampleを選択し、リアルタイムの統計情報を閲覧しながら実装したWebアプリにアクセスすると、Couchbase Serverに対してJSONドキュメントのアクセスを行っていることが確認できます。
エクササイズ 4:簡単なクエリの実行
ドキュメントのIDが分かっていれば、そのIDでgetメソッドを実行するのが一番高速にドキュメントを取得できる方法です。しかし、対象ドキュメントのIDが分からず、ドキュメント内の項目で検索したり、複数ドキュメントにわたる集計を行う必要がある場合があります。そこでN1QLの登場です!
SimpleController.javaにあるもう一つのメソッドreadでtypeがuserのドキュメント件数をカウントする、簡単なN1QLクエリを実装してみましょう。
QueryResult result = bucket.query(Query.simple( select(count("*").as("count")) .from(i(bucket.name())) .where(x("type").eq(s("user"))) )); return result.allRows().get(0).value().getInt("count");
Couchbaseのライブラリが提供するクエリDSLを利用すると、スムースに読みやすいN1QLが記述できます。
連載第一回でtravel-sampleバケットをロード後、プライマリインデックスの作成を行いました。N1QLクエリの実行にはプライマリインデックスが必要なので、未実施の方は、前回の記事をご参照ください。
再びApplication.javaを実行して、http://localhost:8080/worldにアクセスしてみましょう。N1QLで集計したドキュメント数が表示されるはずです。再度http://localhost:8080/helloにアクセスして新規のuserドキュメントを追加すると、集計結果も変わりますね。
保存されたJSONドキュメントのIDも、N1QLを使えば簡単に検索できます。cbqツールを利用して、次のクエリを実行してみましょう:
select meta(travel).id from `travel-sample` as travel where type = 'user';
"user::465c1307-2e08-4492-9d11-25d620486dcd"など、UUIDで生成したIDの一覧が取得できます。
まとめ
今回は、Javaのクライアントアプリケーションコードを中心に、Couchbase Serverへの接続方法、ドキュメントの保存、取得方法、N1QLの実行方法をご紹介しました。データベース側で事前にスキーマ定義をすることなく、ドキュメントの保存が可能で、さらにJSONドキュメント内の項目で検索を行う様子を体験いただけたかと思います。
次回はSQLには存在しない、N1QLならではの配列の操作や、JSONドキュメント同士のJOINなどを扱う予定です。それでは次回をお楽しみに!