CLOVER🍀

That was when it all began.

Super Columnを使ってみる

Apache Cassandraで定義できるデータモデルとして、スーパーカラムなるものがあります。
http://wiki.apache.org/cassandra/DataModel

が、オライリー本でもさらっとしか触れられていませんし

Cassandra

Cassandra

この本に至っては、単語自体が出てきません。
Cassandra実用システムインテグレーション (NEXT-ONE)

Cassandra実用システムインテグレーション (NEXT-ONE)

Dynamoとは違う独自の概念で、面白いよみたいなことが書かれているものもありますが、最近のCassandraでは推奨しているものではないみたいですね。

DataStaxのドキュメントにも、使うなって書かれていますし

Super Columns

Do not use super columns. They are a legacy design from a pre-open source release. This design was structured for a specific use case and does not fit most use cases. Super columns read entire super columns and all its sub-columns into memory for each read request. This results in severe performance issues. Additionally, super columns are not supported in CQL 3.

Use composite columns instead. Composite columns provide most of the same benefits as super columns without the performance issues.

http://www.datastax.com/docs/1.1/ddl/column_family

IBMのドキュメントにも…。

スーパー・カラムと OrderPreservingPartitioner は推奨されません

マルチレベルのデータをモデル化する際には、Cassandra のスーパー・カラムが役に立つことがあります。その場合、階層にもう 1 つのレベルが追加されます。ただし、スーパー・カラムを使ってモデル化できるものは、カラムでもサポートすることが可能です。すなわち、スーパー・カラムならではの追加機能はありません。また、スーパー・カラムはセカンダリー・インデックスをサポートしていません。これらの理由から、Cassandra の開発者たちはスーパー・カラムの使用を推奨していません。サポートを中止する日程は確定されていないものの、今後のリリースではスーパー・カラムのサポートが中止されることになるはずです。

Apache Cassandra データベースについての検討

DataStaxのドキュメントでは、スーパーカラムはサブカラムを全部読んでしまうので、パフォーマンス上の問題を抱えているという話らしいです。CQL3ではスーパーカラムはサポートしていないし、同じようなことがやりたかったらComposite Columnを使えば?って感じみたいですね。
http://www.datastax.com/dev/blog/introduction-to-composite-columns-part-1

まあ、せっかくなので使ってみようかなと思い、今回試してみました。以後、触ることはないかもしれませんが…。

まずは、テスト用のキースペースを作成。

[default@unknown] create keyspace SuperColumnTest
...	with placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy'
...	and strategy_options = {replication_factor:1};
0e7b5c93-14a4-3443-8778-26ff2982ea04

[default@unknown] use SuperColumnTest;
Authenticated to keyspace: SuperColumnTest

スーパーカラムの作成を行います。名前は、「DataStoreSuper」で。

[default@SuperColumnTest] create column family DataStoreSuper
...	with column_type = 'Super'
...	and key_validation_class = 'UTF8Type'
...	and comparator = 'UTF8Type'
...	and subcomparator = 'UTF8Type'
...	and default_validation_class = 'UTF8Type';
ac877e2b-1f39-3e0c-a079-199f488d01b0

定義は、オライリー本とStack Overflowを見ながら…。

describe。

[default@SuperColumnTest] describe DataStoreSuper;

WARNING: CQL3 tables are intentionally omitted from 'describe' output.
See https://issues.apache.org/jira/browse/CASSANDRA-4377 for details.

    ColumnFamily: DataStoreSuper (Super)
      Key Validation Class: org.apache.cassandra.db.marshal.UTF8Type
      Default column value validator: org.apache.cassandra.db.marshal.UTF8Type
      Columns sorted by: org.apache.cassandra.db.marshal.UTF8Type/org.apache.cassandra.db.marshal.UTF8Type
      GC grace seconds: 864000
      Compaction min/max thresholds: 4/32
      Read repair chance: 0.1
      DC Local Read repair chance: 0.0
      Populate IO Cache on flush: false
      Replicate on write: true
      Caching: KEYS_ONLY
      Bloom Filter FP chance: default
      Built indexes: []
      Compaction Strategy: org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy
      Compression Options:
        sstable_compression: org.apache.cassandra.io.compress.SnappyCompressor

ColumnFamilyがSuperになって

    ColumnFamily: DataStoreSuper (Super)

Comparatorがサブカラムとで分かれています。

      Columns sorted by: org.apache.cassandra.db.marshal.UTF8Type/org.apache.cassandra.db.marshal.UTF8Type

DataStoreと名前を切ったので、なんとなくRDBMSとNoSQLをロウキーにして、データを入れていってみます。

[default@SuperColumnTest] set DataStoreSuper['RDBMS']['MySQL']['version'] = '5.6.11';
Value inserted.
Elapsed time: 95 msec(s).
[default@SuperColumnTest] set DataStoreSuper['RDBMS']['MySQL']['URL'] = 'http://dev.mysql.com/';
Value inserted.
Elapsed time: 4.79 msec(s).
[default@SuperColumnTest] set DataStoreSuper['RDBMS']['PostgreSQL']['version'] = '9.2.4';
Value inserted.
Elapsed time: 3.14 msec(s).
[default@SuperColumnTest] set DataStoreSuper['RDBMS']['PostgreSQL']['URL'] = 'http://www.postgresql.org/';
Value inserted.
Elapsed time: 3.61 msec(s).
[default@SuperColumnTest] set DataStoreSuper['NoSQL']['Infinispan']['type'] = 'In Memory Data Grid';
Value inserted.
Elapsed time: 43 msec(s).
[default@SuperColumnTest] set DataStoreSuper['NoSQL']['Infinispan']['version'] = '5.2.5.Final';
Value inserted.
Elapsed time: 36 msec(s).
[default@SuperColumnTest] set DataStoreSuper['NoSQL']['Infinispan']['URL'] = 'http://www.jboss.org/infinispan/';
Value inserted.
Elapsed time: 6.62 msec(s).
[default@SuperColumnTest] set DataStoreSuper['NoSQL']['Apache Cassandra']['type'] = 'Document Database';
Value inserted.
Elapsed time: 3.21 msec(s).
[default@SuperColumnTest] set DataStoreSuper['NoSQL']['Apache Cassandra']['version'] = '1.2.4';
Value inserted.
Elapsed time: 2.55 msec(s).
[default@SuperColumnTest] set DataStoreSuper['NoSQL']['Apache Cassandra']['URL'] = 'http://cassandra.apache.org/';
Value inserted.
Elapsed time: 3.52 msec(s).

listしてみます。

[default@SuperColumnTest] list DataStoreSuper;
Using default limit of 100
Using default column limit of 100
-------------------
RowKey: NoSQL
=> (super_column=Apache Cassandra,
     (column=URL, value=http://cassandra.apache.org/, timestamp=1367228147081000)
     (column=type, value=Document Database, timestamp=1367228119219000)
     (column=version, value=1.2.4, timestamp=1367228126639000))
=> (super_column=Infinispan,
     (column=URL, value=http://www.jboss.org/infinispan/, timestamp=1367228045150000)
     (column=type, value=In Memory Data Grid, timestamp=1367228000945000)
     (column=version, value=5.2.5.Final, timestamp=1367228022587000))
-------------------
RowKey: RDBMS
=> (super_column=MySQL,
     (column=URL, value=http://dev.mysql.com/, timestamp=1367227862881000)
     (column=version, value=5.6.11, timestamp=1367227838823000))
=> (super_column=PostgreSQL,
     (column=URL, value=http://www.postgresql.org/, timestamp=1367227930874000)
     (column=version, value=9.2.4, timestamp=1367227919607000))

2 Rows Returned.
Elapsed time: 71 msec(s).

ロウキーに続いて、super_columnが続いていますね。

データの取得を指定する時は、

get カラムファミリ[ロウキー][スーパーカラム名][カラム名];

といった感じで指定します。

例えば、ロウキーを指定するならこんな感じ。

[default@SuperColumnTest] get DataStoreSuper['RDBMS'];
=> (super_column=MySQL,
     (column=URL, value=http://dev.mysql.com/, timestamp=1367227862881000)
     (column=version, value=5.6.11, timestamp=1367227838823000))
=> (super_column=PostgreSQL,
     (column=URL, value=http://www.postgresql.org/, timestamp=1367227930874000)
     (column=version, value=9.2.4, timestamp=1367227919607000))
Returned 2 results.
Elapsed time: 8.58 msec(s).

[default@SuperColumnTest] get DataStoreSuper['NoSQL'];
=> (super_column=Apache Cassandra,
     (column=URL, value=http://cassandra.apache.org/, timestamp=1367228147081000)
     (column=type, value=Document Database, timestamp=1367228119219000)
     (column=version, value=1.2.4, timestamp=1367228126639000))
=> (super_column=Infinispan,
     (column=URL, value=http://www.jboss.org/infinispan/, timestamp=1367228045150000)
     (column=type, value=In Memory Data Grid, timestamp=1367228000945000)
     (column=version, value=5.2.5.Final, timestamp=1367228022587000))
Returned 2 results.
Elapsed time: 9.46 msec(s).

スーパーカラム名まで指定してみます。

[default@SuperColumnTest] get DataStoreSuper['RDBMS']['MySQL'];
=> (column=URL, value=http://dev.mysql.com/, timestamp=1367227862881000)
=> (column=version, value=5.6.11, timestamp=1367227838823000)
Returned 2 results.
Elapsed time: 8.75 msec(s).

最後は、カラム名まで。

[default@SuperColumnTest] get DataStoreSuper['RDBMS']['MySQL']['URL'];
=> (column=URL, value=http://dev.mysql.com/, timestamp=1367227862881000)
Elapsed time: 61 msec(s).

一応、普通のカラムファミリを作る場合と比べてみましょう。

先の例ではスーパーカラム名となっていたRDBMSとNoSQLを普通のカラムファミリとして作成します。

[default@SuperColumnTest] create column family RDBMS
...	with column_type = 'Standard'
...	and key_validation_class = 'UTF8Type'
...	and comparator = 'UTF8Type'
...	and default_validation_class = 'UTF8Type';
6e414327-74be-3b20-99e1-f1f317a44f01

[default@SuperColumnTest] create column family NoSQL
...	with column_type = 'Standard'
...	and key_validation_class = 'UTF8Type'
...	and comparator = 'UTF8Type'
...	and default_validation_class = 'UTF8Type';
606eec53-52c0-3bc4-8560-9d5a8a073eaa

column_typeは、デフォルトの「Standard」を明示的に指定。

RDBMSカラムファミリをdescribe。

[default@SuperColumnTest] describe RDBMS;

WARNING: CQL3 tables are intentionally omitted from 'describe' output.
See https://issues.apache.org/jira/browse/CASSANDRA-4377 for details.

    ColumnFamily: RDBMS
      Key Validation Class: org.apache.cassandra.db.marshal.UTF8Type
      Default column value validator: org.apache.cassandra.db.marshal.UTF8Type
      Columns sorted by: org.apache.cassandra.db.marshal.UTF8Type
      GC grace seconds: 864000
      Compaction min/max thresholds: 4/32
      Read repair chance: 0.1
      DC Local Read repair chance: 0.0
      Populate IO Cache on flush: false
      Replicate on write: true
      Caching: KEYS_ONLY
      Bloom Filter FP chance: default
      Built indexes: []
      Compaction Strategy: org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy
      Compression Options:
        sstable_compression: org.apache.cassandra.io.compress.SnappyCompressor

データを登録していってみます。

lt@SuperColumnTest] set RDBMS['MySQL']['version'] = '5.6.11';
Value inserted.
Elapsed time: 8.29 msec(s).
[default@SuperColumnTest] set RDBMS['MySQL']['URL'] = 'http://dev.mysql.com/';
Value inserted.
Elapsed time: 8.25 msec(s).
[default@SuperColumnTest] set RDBMS['PostgreSQL']['version'] = '9.2.4';
Value inserted.
Elapsed time: 3.0 msec(s).
[default@SuperColumnTest] set RDBMS['PostgreSQL']['URL'] = 'http://www.postgresql.org/';
Value inserted.
Elapsed time: 35 msec(s).

[default@SuperColumnTest] set NoSQL['Infinispan']['type'] = 'In Memory Data Grid';
Value inserted.
Elapsed time: 5.87 msec(s).
[default@SuperColumnTest] set NoSQL['Infinispan']['version'] = '5.2.5.Final';
Value inserted.
Elapsed time: 8.44 msec(s).
[default@SuperColumnTest] set NoSQL['Infinispan']['URL'] = 'http://www.jboss.org/infinispan/';
Value inserted.
Elapsed time: 7.25 msec(s).
[default@SuperColumnTest] set NoSQL['Apache Cassandra']['type'] = 'Document Database';
Value inserted.
Elapsed time: 3.4 msec(s).
[default@SuperColumnTest] set NoSQL['Apache Cassandra']['version'] = '1.2.4';
Value inserted.
Elapsed time: 2.72 msec(s).
[default@SuperColumnTest] set NoSQL['Apache Cassandra']['URL'] = 'http://cassandra.apache.org/';
Value inserted.
Elapsed time: 2.9 msec(s).

list。

[default@SuperColumnTest] list RDBMS;
Using default limit of 100
Using default column limit of 100
-------------------
RowKey: MySQL
=> (column=URL, value=http://dev.mysql.com/, timestamp=1367228934643000)
=> (column=version, value=5.6.11, timestamp=1367228920876000)
-------------------
RowKey: PostgreSQL
=> (column=URL, value=http://www.postgresql.org/, timestamp=1367229001008000)
=> (column=version, value=9.2.4, timestamp=1367228990537000)

2 Rows Returned.
Elapsed time: 17 msec(s).

[default@SuperColumnTest] list NoSQL;
Using default limit of 100
Using default column limit of 100
-------------------
RowKey: Apache Cassandra
=> (column=URL, value=http://cassandra.apache.org/, timestamp=1367229246005000)
=> (column=type, value=Document Database, timestamp=1367229228761000)
=> (column=version, value=1.2.4, timestamp=1367229235363000)
-------------------
RowKey: Infinispan
=> (column=URL, value=http://www.jboss.org/infinispan/, timestamp=1367229207248000)
=> (column=type, value=In Memory Data Grid, timestamp=1367229140183000)
=> (column=version, value=5.2.5.Final, timestamp=1367229156563000)

2 Rows Returned.
Elapsed time: 5.7 msec(s).

普通のカラムファミリの場合は、データの取得は

get カラムファミリ名[ロウキー][カラム名];

ですね。

というわけで、getしてみます。

[default@SuperColumnTest] get RDBMS['MySQL'];
=> (column=URL, value=http://dev.mysql.com/, timestamp=1367228934643000)
=> (column=version, value=5.6.11, timestamp=1367228920876000)
Returned 2 results.
Elapsed time: 3.84 msec(s).
[default@SuperColumnTest] get RDBMS['MySQL']['URL'];
=> (column=URL, value=http://dev.mysql.com/, timestamp=1367228934643000)
Elapsed time: 3.18 msec(s).

[default@SuperColumnTest] get NoSQL['Apache Cassandra'];
=> (column=URL, value=http://cassandra.apache.org/, timestamp=1367229246005000)
=> (column=type, value=Document Database, timestamp=1367229228761000)
=> (column=version, value=1.2.4, timestamp=1367229235363000)
Returned 3 results.
Elapsed time: 8.51 msec(s).
[default@SuperColumnTest] get NoSQL['Apache Cassandra']['URL'];
=> (column=URL, value=http://cassandra.apache.org/, timestamp=1367229246005000)
Elapsed time: 4.39 msec(s).