Cassandraも0.6系がついに0.6.4まで出てきて、stableなリリースとして十分に使えるところまで来ましたね。この連載のコードもすべて0.6系では動作するはずですので、ぜひ最新のものに入れ替えて試してみてください。
前回まででデータの投入、更新、削除までをご紹介しました。今回から複数回に分けて検索を重点的に見ていきましょう。
前準備としてデータを投入しておく
検索メソッドの確認の前準備として、まずデータの投入を行います。今回はシンプルな郵便番号のデータを利用します。以下のURLから東京都のデータを取得して、解凍後、データを投入してください。
- 郵便番号データのダウンロード:日本郵便
- URL:http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/13tokyo.lzh
データは説明のため簡易的なデータ構造とします。
- キーは郵便番号
- データは、郵便番号(postalCode)、あて先(address)、あて先読み方(addressYomi)の3つ
- スーパーカラムは使わない
データを投入するコードは以下のとおりです。
設定ファイル(storage-conf.xml)には以下のように指定します。場所はCassandraのデフォルト設定であるキースペースのKeyspace1以下になります。
実行してデータを投入します。以下のようになるはずです。
このデータをサンプルとして、検索メソッドを使ってみましょう。
単一カラムを取得するには
まずは1件検索してみましょう。Cassandraではgetメソッドを使います。getメソッドは以下のようなAPIになっています。
コードは以下のようになります。この例では郵便番号“1006528”の住所を検索しています。
結果は以下のようになります。
第5回でも説明したように、カラムファミリとカラムの位置はColumnPathで特定します。今回のサンプルでは、カラムファミリとカラムのケースなので、検索するカラム名を指定します。
今回のサンプルではありませんが、スーパーカラムの場合は上記に加えて、以下のようにしてスーパーカラム名を指定する必要があります。
また戻り値のColumnOrSuperColumnからデータをどのように取得するかは、カラムまたはスーパーカラムで取得方法が異なります。
- カラムの場合
- →ColumnOrSuperColumn#getColumn()でカラムを取得
- スーパーカラムの場合
- →ColumnOrSuperColumn#getSuperColumn()#getColumns()でスーパーカラム内のカラムを取得
複数カラムを取得するには
次に1つのキーから複数カラムを同時に取得してみましょう。この場合、get_sliceを使います。get_sliceのAPIは以下のようになっています。
実際のコードは以下のようになります。
結果は以下のとおりです。
ここでColumnParentとSlicePredicateという見慣れないクラスが2つ登場していますね。これらを説明します。
ColumnParent
ColumnParentはColumnPathと非常に似た概念のクラスですが、以下のような違いがあります。
- ColumnPath → 単一のカラムを見つけるためのクラス
- ColumnParent→ 複数のカラムを見つけるためのクラス
ColumnParentはディレクトリ構造で言うところの /../ にあたります。ある単一カラムを基点にしてディレクトリ構造をさかのぼり、複数カラムを探索するようなイメージです。
ColumnParentは以下の2とおりのどちらかをとります。
- カラムの場合 → カラムファミリのみを指定
- スーパーカラムの場合 → カラムファミリとスーパーカラムを指定
SlicePredicate
SlicePredicateは検索をフィルタするための指定を行うクラスです。フィルタリングにおもに以下の2つの設定ができます。
上記のサンプルコードでは、①のカラム名による指定で、3つあるカラム(postalCode, address, addressYomi)の中から、postalCodeとaddressの2つだけを指定して検索しました。しかし、結果をよく見てみると、サンプルコードで指定した順序になっていないですね。
第4回でかんたんに説明しましたが、Cassandraのカラムはstorage-conf.xmlに書いた順序でソートされています。クライアントコードで指定した順序ではありません。この点に注意してください。
今回は設定ファイルにCompareWithでUTF8を指定しているので、UTF8の順序でソートされています。そのため、address、postalCodeの順序で結果が取れます。詳細については第4回を参照してください。
検索対象のカラムを絞るには
②のカラム名の範囲によって検索対象のカラムを絞ることもできます。この場合はSliceRangeというクラスを使い、以下のようにして範囲を指定します。
- カラムの開始位置 →SliceRange#setStartで指定
- カラムの終了位置 →SliceRange#setEndで指定
SliceRangeが便利な局面としては、たとえばカラムファミリの中に大量の日付をキーとしたカラムが入っている場面などで便利です。
Cassandraでは日付などをキーとしてデータを入れたり、ある項目に対して修正や変更をつぶさに記録したりと、あるキー1つに対しても大量に書き込みが発生する可能性があります。そのため「大量にあるカラムの中から、ある範囲内だけ取り出したい」という状況下では、SliceRangeは有効活用できます。
注意点としては、先ほどもお伝えしたようにカラム順序はstorage-conf.xmlのCompareWith設定に沿って決まるということです。これに従って、startとendを決める必要があります。今回の場合だとUTF8のソート順序になりますので、address, addressYomi, postalCodeの順序にカラム名がソートされていることを意識してください。
たとえば、startをaddressYomiとして、endをpostalCodeとすれば問題ありません。しかし、カラムのソート順序に従わないケース、たとえば以下のようにすると、InvalidRequestExceptionが発生します。
- start → postalCode
- end → addressYomi
SliceRangeを使ったサンプルコードは以下のようになります。結果を比較しやすいように、SliceRangeでカラムを絞った場合と絞らなかった場合、両方を実装してみました。
結果は以下のようになります。
昇順・降順を制御するには
勘の良い方はお気づきかもしれませんが、このままだと昇順・降順のコントロールができないようにみえます。数値データや日付データをカラム名に付与した場合は、昇順・降順を制御したくなりますよね。
そこでSliceRangeにはSliceRange#setReversedというメソッドがついており、これで昇順・降順を制御することができます。
先ほどのコードで降順にしてみましょう。コードは以下のようになります。
結果は以下のようになります。
今回はgetとget_sliceについて説明しました。
Cassandraの検索系メソッドは非常に特徴的で、やや癖があります。ただきちんと見れば、そんなに難しいものでもありません。今回と次回で1つずつ覚えていきましょう。
次回は、get_range_slices、multiget_slice、get_countの3つを見てみます。特にget_range_slicesと順序の維持を中心に見ていく予定です。お楽しみに。
今回の記事で紹介したサンプルコード全体は以下からダウンロードできます。