Question

How do I create table with composite keys using astyanax client. For now I've created it with cqlsh -3, and this is how it looks like in cli:

[default@KS] describe my_cf;
    ColumnFamily: my_cf
      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.CompositeType(org.apache.cassandra.db.marshal.TimeUUIDType,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
      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

This is how I would expect it to be in cqlsh:

 CREATE TABLE my_cf (
                   ... key text,
                   ... timeid timeuuid,
                   ...   flag boolean,
                   ...   data text,
                   ... PRIMARY KEY (key, timeid));

I got it working with composite key stored as a blob which is a problem.

my code

public class MyKey {
    @Component(ordinal=0)
    private String key;
    @Component(ordinal=1)
    private UUID timeid;
 //...
}

CF

public static ColumnFamily<MyKey, String> MY_CF = ColumnFamily
        .newColumnFamily("my_cf",
                new AnnotatedCompositeSerializer<MyKey>(MyKey.class),
                StringSerializer.get());

KS

                ksDef = cluster.makeKeyspaceDefinition();

                ksDef.setName(keyspaceName)
                        .setStrategyOptions(keyspaceOptions)
                        .setStrategyClass("SimpleStrategy")
                        .addColumnFamily(
                                cluster.makeColumnFamilyDefinition()
                                        .setName(MY_CF.getName())
                                        .setComparatorType("UTF8Type")
                                        .setDefaultValidationClass("UTF8Type")
// blob if no key validation class specified
// and something looking as a string if I use this:     .setKeyValidationClass("CompositeType(UTF8Type, TimeUUIDType)")
// anyway there's a single column per composite key

                                        .addColumnDefinition(
                                                cluster.makeColumnDefinition()
                                                        .setName("flag")
                                                        .setValidationClass(
                                                                "BooleanType"))
                                        .addColumnDefinition(
                                                cluster.makeColumnDefinition()
                                                        .setName("data")
                                                        .setValidationClass(
                                                                "UTF8Type")));
                cluster.addKeyspace(ksDef);

mutation

            MutationBatch m = ks.prepareMutationBatch();

            for (char keyName = 'A'; keyName <= 'C'; keyName++) {
                MyKey myKey = new MyKey("THEKEY_" + keyName, TimeUUIDUtils.getUniqueTimeUUIDinMillis());
                ColumnListMutation<String> cfm = m.withRow(MY_CF, myKey);
                cfm.putColumn("flag", true, null);
                cfm.putColumn("data", "DATA_" + keyName, null);
            }
            m.execute();

cqlsh:KS>describe columnfamily my_cf;

CREATE TABLE my_cf (
  KEY blob PRIMARY KEY,
  flag boolean,
  data text
) WITH ...

cqlsh:KS>select * from my_cf;

  key                                                      | flag | data
----------------------------------------------------------+--------+---------
 00064953494e5f420000109f4513d0e3ac11e19c400022191ad62b00 | True   | DATA_B

cqlsh:KS> select * from my_cf where key = 'THEKEY_B' order by timeid desc;

Bad Request: Order by on unknown column timeid

doesnt' it look right in cassandra-cli below? why it doesn't work in cqlsh?

cassandra-cli] list my_cf;

RowKey: THEKEY_B:09f29941-e3c2-11e1-a7ef-0022191ad62b
=> (column=active, value=true, timestamp=1344695832788000)
=> (column=data, value=DATA_B, timestamp=1344695832788000)

What am I doing wrong? (astyanax 1.0.6, cassandra 1.1.2) cqlsh>[cqlsh 2.2.0 | Cassandra 1.1.2 | CQL spec 3.0.0 | Thrift protocol 19.32.0]

Was it helpful?

Solution

From what I've been able to figure out, composite primary keys represent a major divergence in the protocol and interface to cassandra and the protocol you use controls the features you have access to.

For instance, astyanax and hector are primarily thrift protocol clients, while CQL, more than just a language, is (or will be?) a binary protocol.

The two protocols are not equivalent and CQL3 with composite primary keys makes things very different.

The thing to understand about "TABLES" with composite primary keys is that they essentially translate into wide rows with composite column names. The first part of the primary key is the row key and the remaining parts are used as a prefix along with the TABLE-column name as the column name in the wide row.

In your instance, the row key is "key" and the column prefix is "timeid", so the flag field of what you are inserting is actually a column named :flag and data is :data and so on.

In order for this to work, the CQL protocol interface to cassandra is converting "TABLES" into wide rows and transparently handling all of that column naming.

The thrift interface doesn't take care of this stuff and and when you do a mutation, it just writes columns like it is used to, without the virtual addressing.

So, in fact, the results do not look right in your cassandra-cli. If you do an insert from cqlsh -3, here is what it should look like from the cassandra-cli point of view (with a simple text date):

[default@testapp] list my_cf;
RowKey: mykey
=> (column=20120827:data, value=some data, timestamp=1346090889361000)
=> (column=20120827:flag, value=, timestamp=1346090889361001)

CQL3 and tables look really attractive, but there are some trade-offs to be made and there doesn't seem to be solid java client support yet.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top