Composite columns

opuneet edited this page Apr 28, 2014 · 4 revisions
Clone this wiki locally

The following example shows how a composite column is used to store session events for a user.  The row key is the user id and the column name is a composite of a session id and a timestamp.  Using the composite columns we can search for all events for a specific session id sorted by event timestamp.

// Annotated composite class
public class SessionEvent{
  @Component(ordinal=0) String   sessiondId;
  @Component(ordinal=1) UUID timestamp;
  // Must have public default constructor
  public SessionEvent() {
  }
}

static AnnotatedCompositeSerializer<SessionEvent> eventSerializer
      = new AnnotatedCompositeSerializer<SessionEvent>(SessionEvent.class);
static ColumnFamily<String, SessionEvent> CF_SESSION_EVENTS
      = new ColumnFamily<String, SessionEvent>("SessionEvents",
            StringSerializer.get(), eventSerializer);

// Querying cassandra for an entire row
OperationResult<ColumnList<SessionEvent>> result = keyspace.prepareQuery(CF_SESSION_EVENTS)
    .getKey("UserId1")
    .withColumnRange(eventSerializer.buildRange()
        .withPrefix("SessionId1")
	.greaterThanEquals(TimeUUIDUtils.getMicrosTimeUUID(startTime))
	.lessThanEquals(TimeUUIDUtils.getMicrosTimeUUID(endTime)))
).execute();

Note that the last predicate in the composite column search must be a range search. Hence even if you want to just search for everything with 'SessionId1' your query will need to be as follows

OperationResult<ColumnList<SessionEvent>> result = keyspace.prepareQuery(CF_SESSION_EVENTS)
    .getKey("UserId1")
    .withColumnRange(eventSerializer.buildRange()
	.greaterThanEquals("SessionId1")
	.lessThanEquals("SessionId1"))
).execute();

How to use the PrefixedSerializer (but you really should use Composite columns)

The PrefixedSerializer is useful when you want to store keys or column names from different data domains in the same column family but need to avoid collisions.

The following example shows how to store keys from different domains in the same column family.  To do this you actually need to create a separate ColumnFamily definition for each prefix.  Note that prefixes must all have the same data type but that the other serializer may be different.  This is not the case with column names since column names are sorted.  Using different c.  For column names it is better to use the CompositeSerializer (coming soon to Astyanax).

ColumnFamily<String, String> cfPrefix1 = new ColumnFamily<String, String>("Standard1",
    new PrefixedSerializer<String, String>("Prefix1_", StringSerializer.get(), StringSerializer.get()),
    StringSerializer.get(),
    ColumnType.STANDARD);
ColumnFamily<String, String> cfPrefix2 = new ColumnFamily<String, String>("Standard1",
    new PrefixedSerializer<String, String>("Prefix2_", StringSerializer.get(), StringSerializer.get()),
    StringSerializer.get(),
    ColumnType.STANDARD);
MutationBatch m = keyspace.prepareMutationBatch();
  m.withRow(cfPrefix1, "A")	// This key is actually "Prefix1_A"
    .putColumn("Column1", "Value1", null);
  m.withRow(cfPrefix2, "A")	// This key is actually "Prefix2_A"
    .putColumn("Column1", "Value2", null);