📝 BLOG.IK.AM

@making's memo
(🗃 Categories 🏷 Tags)

Cassandra0.7.0のSecondary indexesを試す

🗃 {Middleware/NoSQL/Cassandra}

🗓 Updated at 2011-01-11T15:35:44+09:00 by Toshiaki Maki  🗓 Created at 2010-12-22T17:22:23+09:00 by Toshiaki Maki  {✒️️ Edit  ⏰ History}


💣 Danger: This content is obsolete. You should avoid reading. If you really want to read, please click .

動作確認バージョンはサーバ/クライアントともに0.7.0。(2010/01/12更新)

Raptanoの記事の写経ですが。

普通のインデックスはカラムのRowキーに対するもので、全てのカラムが持つ。セカンダリインデックスは、カラムの値に対して作られるもの。値での検索がしやすくなる(これまでは転置インデックスのようなものが必要だった)。

セカンダリインデックス作成

カラムファミリを作成する際にメタデータとしてカラム名を設定でき、その時にIndex Typeも指定できる模様。メタデータに設定する値は以下。


キー設定値
column_nameカラム名
validation_typeカラム値の型(制限する場合)
index_typeインデックスの種類

(他にあれば後で追加する)

この例では、full_nameカラムにはインデックスを作らず、birth_dateカラムにはインデックスを作成している。

[default@unknown] create keyspace demo;
62c689d4-0df2-11e0-b3ea-e700f669bcfc
[default@unknown] use demo;
Authenticated to keyspace: demo
[default@demo] create column family users with comparator=UTF8Type and column_metadata=[{column_name:full_name, validation_class:UTF8Type},{column_name:birth_date, validation_class:LongType, index_type:KEYS}];
b21a9d05-0df2-11e0-b3ea-e700f669bcfc
[default@demo] describe keyspace demo;
Keyspace: demo:
  Replication Strategy: org.apache.cassandra.locator.SimpleStrategy
    Replication Factor: 1
  Column Families:
    ColumnFamily: users
      Columns sorted by: org.apache.cassandra.db.marshal.UTF8Type
      Row cache size / save period: 0.0/0
      Key cache size / save period: 200000.0/3600
      Memtable thresholds: 0.2953125/63/60
      GC grace seconds: 864000
      Compaction min/max thresholds: 4/32
      Read repair chance: 1.0
      Column Metadata:
        Column Name: full_name (full_name)
          Validation Class: org.apache.cassandra.db.marshal.UTF8Type
        Column Name: birth_date (birth_date)
          Validation Class: org.apache.cassandra.db.marshal.LongType
          Index Type: KEYS

インデックスの種類は0.7.0の段階ではKEYSしかサポートされていない。ハッシュのキーみたいなものらしい。
bitmapインデックスが0.7.1からサポートされるとのこと。

何やらそれらしきログが出力されている。

 INFO [Create index users.62697274685f64617465] 2010-12-22 23:11:24,344 ColumnFamilyStore.java (line 325) Creating index org.apache.cassandra.db.Table@6239da8a.users.62697274685f64617465
 INFO [CompactionExecutor:1] 2010-12-22 23:11:24,383 CompactionManager.java (line 341) Compacted to C:\var\lib\cassandra\data\system\Schema-tmp-e-5-Data.db.  15,751 to 11,562 (~73% of original) bytes for 4 keys.  Time: 48ms.
 INFO [Create index users.62697274685f64617465] 2010-12-22 23:11:24,384 ColumnFamilyStore.java (line 339) Index users.62697274685f64617465 complete
 INFO [Create index users.62697274685f64617465] 2010-12-22 23:11:24,385 ColumnFamilyStore.java (line 639) switching in a fresh Memtable for IndexInfo at CommitLogContext(file='/var/lib/cassandra/commitlog\CommitLog-1293039030618.log', position=24885)
 INFO [Create index users.62697274685f64617465] 2010-12-22 23:11:24,386 ColumnFamilyStore.java (line 943) Enqueuing flush of Memtable-IndexInfo@1162212835(41 bytes, 1 operations)
 INFO [FlushWriter:1] 2010-12-22 23:11:24,387 Memtable.java (line 155) Writing Memtable-IndexInfo@1162212835(41 bytes, 1 operations)
 INFO [FlushWriter:1] 2010-12-22 23:11:24,423 Memtable.java (line 162) Completed flushing \var\lib\cassandra\data\system\IndexInfo-e-1-Data.db (164 bytes)

where句をつけてクエリ実行

セカンダリインデックスを付けたカラムに対してはSQLのようなwhere句をつけて値を検索できる。
入っているデータは以下

[default@demo] list users;
Using default limit of 100
-------------------
RowKey: nobunaga
=> (column=birth_date, value=1534, timestamp=1293042940549000)
=> (column=blood, value=A, timestamp=1293042957506000)
=> (column=full_name, value=Nobunaga Oda, timestamp=1293042893235000)
-------------------
RowKey: making
=> (column=birth_date, value=1984, timestamp=1293042776114000)
=> (column=blood, value=B, timestamp=1293042734033000)
=> (column=full_name, value=Toshiaki Maki, timestamp=1293042756442000)
-------------------
RowKey: hideyoshi
=> (column=birth_date, value=1537, timestamp=1293042846014000)
=> (column=blood, value=A, timestamp=1293042867208000)
=> (column=full_name, value=Hideyoshi Toyotomi, timestamp=1293042812951000)

検索するのにRowキーではなく、where句が使える。

[default@demo] get users where birth_date = 1984;
-------------------
RowKey: making
=> (column=birth_date, value=1984, timestamp=1293042776114000)
=> (column=blood, value=B, timestamp=1293042734033000)
=> (column=full_name, value=Toshiaki Maki, timestamp=1293042756442000)

1 Row Returned.

単体での範囲検索まだサポートされていない模様。多分KEYSインデックスではサポートされない。

[default@demo] get users where birth_date > 1500;
No indexed columns present in index clause with operator EQ

動的にセカンダリインデックス追加

bloodにはインデックスが作られていないので、

[default@demo] get users where blood = 'A';
No indexed columns present in index clause with operator EQ

怒られる。

後からインデックスを追加したい場合はupdate文でスキーマ更新。

[default@demo] update column family users with comparator=UTF8Type and column_metadata=[{column_name:full_name, validation_class:UTF8Type},{column_name:birth_date, validation_class:LongType, index_type:KEYS},{column_name:blood, validation_class:UTF8Type, index_type:KEYS}];
9225fc2b-0dfb-11e0-b3ea-e700f669bcfc

ちゃんと更新された。

[default@demo] describe keyspace demo;
Keyspace: demo:
  Replication Strategy: org.apache.cassandra.locator.SimpleStrategy
    Replication Factor: 1
  Column Families:
    ColumnFamily: users
      Columns sorted by: org.apache.cassandra.db.marshal.UTF8Type
      Row cache size / save period: 0.0/0
      Key cache size / save period: 200000.0/3600
      Memtable thresholds: 0.2953125/63/60
      GC grace seconds: 864000
      Compaction min/max thresholds: 4/32
      Read repair chance: 1.0
      Column Metadata:
        Column Name: full_name (full_name)
          Validation Class: org.apache.cassandra.db.marshal.UTF8Type
        Column Name: blood (blood)
          Validation Class: org.apache.cassandra.db.marshal.UTF8Type
          Index Type: KEYS
        Column Name: birth_date (birth_date)
          Validation Class: org.apache.cassandra.db.marshal.LongType
          Index Type: KEYS

これでbloodでも検索できる。

[default@demo] get users where blood = 'A';
-------------------
RowKey: nobunaga
=> (column=birth_date, value=1534, timestamp=1293042940549000)
=> (column=blood, value=A, timestamp=1293042957506000)
=> (column=full_name, value=Nobunaga Oda, timestamp=1293042893235000)
-------------------
RowKey: hideyoshi
=> (column=birth_date, value=1537, timestamp=1293042846014000)
=> (column=blood, value=A, timestamp=1293042867208000)
=> (column=full_name, value=Hideyoshi Toyotomi, timestamp=1293042812951000)

2 Rows Returned.

あるカラムに対して=検索が入っていれば他のカラムの範囲検索が使える。

[default@demo] get users where birth_date > 1535 and blood = 'A';
-------------------
RowKey: hideyoshi
=> (column=birth_date, value=1537, timestamp=1293042846014000)
=> (column=blood, value=A, timestamp=1293042867208000)
=> (column=full_name, value=Hideyoshi Toyotomi, timestamp=1293042812951000)

1 Row Returned.

ただし、KEYSインデックスはハッシュのキーみたいなものであり、btreeではないため、パフォーマンスは多分良くない。

Cassandra: The Definitive Guide
Eben Hewitt
Oreilly & Associates Inc
売り上げランキング: 20382