javacassandrahector

Hector - Insert row with composite key


Hi I want to insert into this kind of column family row with composite key:

CREATE TABLE my_items (
user_id uuid,
item_id uuid,
description varchar,
 PRIMARY KEY (user_id, item_id));

So I try this:

StringSerializer stringSerializer = StringSerializer.get();
    UUIDSerializer uuidSerializer = UUIDSerializer.get();
    CompositeSerializer compositeSerializer = CompositeSerializer.get();

    HColumn<String, UUID> hColumnObj_userID = HFactory.createColumn("user_id", userID, stringSerializer, uuidSerializer);
    HColumn<String, UUID> hColumnObj_itemID= HFactory.createColumn("item_id", itemID, stringSerializer, uuidSerializer);

    Mutator<Composite> mutator = HFactory.createMutator(
            repository.getKeyspace(),
            compositeSerializer);
    Composite colKey = new Composite();
    colKey.addComponent(userID, uuidSerializer);
    colKey.addComponent(itemID, uuidSerializer);

    mutator.addInsertion(colKey,
            "my_items", hColumnObj_userID);
    mutator.addInsertion(colKey,
            "my_items", hColumnObj_itemID);

    mutator.execute();

What's wrong with code above? I keep getting this error: "InvalidRequestException(why:UUIDs must be exactly 16 bytes)". And how can I insert data into column family that I describe above.

Cheers


Solution

  • It looks like Hector was expecting a Composite containing a UUID and a String and found only a string.

    Before writing the Hector code you have to translate the create DDL into the actual storage pattern CQL uses. In this case, even though you have two primary keys, only the first, user_id, is used as the row key. That's always the case. Any other primary keys (item_id in this case) are used to form composite column names for every column except the first primary key. That means that when using Hector for your my_items column family you'll have to write two columns, one for item_ID and one for description.

    The column name for the item_id value is a composite consisting of the values of primary keys 2...n (item_id in this example) and a constant string name of the value ("item_id").

    The column name for the description value is also a composite of the item_id value and the name of the value ("description").

    If you wrote 3 CQL table rows, each with the same user_id but having different item_id values then you'd end up with a single column family row whose row key is the common user_id value and which has 6 columns, an item_id column and a description column for each of the 3 CQL table rows.

    The code should look like this:

    import java.util.UUID;
    
    import me.prettyprint.cassandra.serializers.CompositeSerializer;
    import me.prettyprint.cassandra.serializers.IntegerSerializer;
    import me.prettyprint.cassandra.serializers.StringSerializer;
    import me.prettyprint.cassandra.serializers.UUIDSerializer;
    import me.prettyprint.hector.api.Keyspace;
    import me.prettyprint.hector.api.beans.Composite;
    import me.prettyprint.hector.api.beans.HColumn;
    import me.prettyprint.hector.api.beans.AbstractComposite.ComponentEquality;
    import me.prettyprint.hector.api.factory.HFactory;
    import me.prettyprint.hector.api.mutation.Mutator;
    
        // put this here to make it compile cleanly
    
        Keyspace keyspace = null;
        UUID userID = null;
        UUID itemID = null;
        String description = null;
    
                // Row key is user_id of type UUID
    
        Mutator<UUID> mutator = HFactory.createMutator(
                keyspace,
                UUIDSerializer.get());
    
            // write column for itemID.  
            // Column name is composite of itemID value and constant "item_id"
            // Row key is value of userID
    
        Composite itemIdColumnName = new Composite();
        itemIdColumnName.addComponent(itemID    , UUIDSerializer.get());
        itemIdColumnName.addComponent("item_id" , StringSerializer.get());
            // HFactory.createColumn takes args: column name, column value, serializer for column name, serializer for column value
        HColumn<Composite, UUID> hColumnObj_itemID = HFactory.createColumn(itemIdColumnName, userID, new CompositeSerializer(), UUIDSerializer.get());
        mutator.addInsertion(userID, "my_items", hColumnObj_itemID);
    
        // write column for description.  
        // Column name is composite of itemID value and constant "description"
        // Row key is value of userID
    
        Composite descriptionColumnName = new Composite();
        itemIdColumnName.addComponent(itemID    , UUIDSerializer.get());
        itemIdColumnName.addComponent("description" , StringSerializer.get());
        HColumn<Composite, String> hColumnObj_description = HFactory.createColumn(descriptionColumnName, description , new CompositeSerializer(), StringSerializer.get());
        mutator.addInsertion(userID, "my_items", hColumnObj_description);
    
        mutator.execute();