Question

I can't figure out how to make all the range queries i need using Astyanax. I've tried what's explained here but it does not seem to work.

FYI I'm coming from the Hector world where i got this all working nicely and for reasons i won't explain, we decided to switch to Astyanax.

I have a column family described as follow. Note the "ReversedType" that allows us to have the latest TimeUUID first. It shouldn't impact the rest, at leat it never did with Hector:

ColumnFamily: mycf
      Key Validation Class: org.apache.cassandra.db.marshal.CompositeType(org.apache.cassandra.db.marshal.UTF8Type,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.UTF8Type,org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.TimeUUIDType))

And here's it's definition as an Astyanax CF:

public static final CF = new ColumnFamily<Rowkey, Column>(
    NAME,
    new AnnotatedCompositeSerializer<Rowkey>(Rowkey.class),
    new AnnotatedCompositeSerializer<Column>(Column.class),
    StringSerializer.get()
);

public static class Column {
    @Component(ordinal = 0)
    public String    colname        = null;
    @Component(ordinal = 1)
    public UUID        timeUUID    = null;
}

public static class Rowkey {
    @Component(ordinal = 0)
    public String    aid;
    @Component(ordinal = 1)
    public String    cid;
}

I use to be able to do a query using partial composites as described here. What i really need is to be able to do the following range queries:

# Range 1
# Should get the 10 first elements of the rowkey
colstart: null
colend: null
limit: 10

# Range 2
# Should get the 10 first elements of the rowkey
# that has as first part of the composite the string "mycol"
colstart: Column("mycol", null)
colend: Column("mycol", null)
limit: 10

# Range 3
# Should get the 10 first elements of the rowkey
# that has as first part of the composite the string "mycol"
# and with a timeuuid created with a timstamp between 'timestampStart' and 'timestampEnd'
colstart: Column("mycol", TimeUUID(timestampStart))
colend: Column("mycol", TimeUUID(timestampEnd))
limit: 10

# Range 4, not actually a range
# Should get the 1 column composed of "mycol" and existingTimeUUID
colstart: Column("mycol", existingTimeUUID)
colend: Column("mycol", existingTimeUUID)
limit: 10

Here's the 3 ways i've tried:

# Code 1
keyspace.prepareQuery(columnFamily)
    .getKey(rowkey)
    .withColumnRange(columnStart, columnEnd, false, 10)
    .execute()
    .getResult();

# Code 2
RangeBuilder rangeBuilder = new RangeBuilder()
    .setStart(columnStart, CF.getColumnSerializer())
    .setEnd(columnEnd, CF.getColumnSerializer())
    .setReversed(false)
    .setLimit(10);
keyspace.prepareQuery(columnFamily)
    .getKey(rowkey)
    .withColumnRange(rangeBuilder.build())
    .execute()
    .getResult();

# Code 3
CompositeRangeBuilder rangeBuilder = ((AnnotatedCompositeSerializer<Column>) colSerializer)
    .buildRange()
    .withPrefix(columnStart.colname)
    .greaterThanEquals(columnStart.timeUUID)
    .lessThanEquals(columnEnd.timeUUID)
    .limit(10);
keyspace.prepareQuery(columnFamily)
    .getKey(rowkey)
    .withColumnRange(rangeBuilder.build())
    .execute()
    .getResult();

Based on my Hector background, the composite i give (Annotated Classes) miss the EQUALITY parameter. Code 3 wouldn't do exactly what i need as the prefix applies to both start and end and those may be different if i wanted, for intance, to range query from (col1, timUUID1) to (col2, TimeUUID2).

I managed to make Range 4 work with all three codes easely.

I managed to make Range 1 work with all three codes by doing so:

  • In Code 1 i gave null as param for start and end
  • In Code 2 i avoided calling setStart and setEnd
  • In Code 3 i avoided calling withPrefix or any equality methode.

I managed to make Range 2 work only with Code 3:

  • I provided either greaterThanEquals(columnStart.colname) or lessThanEquals(columnStart.colname) and no other equality/prefix method

I did not manage to make Range 3 at all.

Clearely, i would like to use only Code 1 as I actually don't know the column family i will be querying. Here i'm just using an example with a composite column but it may not be composite or have more than 2 fields.

In hector it's really as easy as this and i would like some equivalent:

MultigetSliceQuery<K, C, V> q = HFactory.createMultigetSliceQuery(connection.getKeyspace(), this.getRowKeySerializer(), this.getColumnNameSerializer(), this.getColumnValueSerializer());
q.setColumnFamily(this.getCfName());
q.setKeys(keys)
q.setRange(colStart, colEnd, reversed, count);
q.execute();

With colStart and colEnd beeing of any type and if composite, allowing partial composites with an Equality defined on each component.

Thanks for your help.

Was it helpful?

Solution

I wasn't able to do all i wanted using the above methods but i found a 4th one that even though it doesn't please me, works.

I'm using the ByteBuffer version of withColumnRange in Code 1. The start and end buffer are built using the actual Composite class as follows:

public static <T> ByteBuffer toRangeStart(List<Object> list, boolean reversed) {
    return toRangeValue(list, reversed ? ComponentEquality.GREATER_THAN_EQUAL : ComponentEquality.EQUAL);
}

public static <T> ByteBuffer toRangeEnd(List<Object> list, boolean reversed) {
    return toRangeValue(list, reversed ? ComponentEquality.EQUAL : ComponentEquality.GREATER_THAN_EQUAL);
}

public static <T> ByteBuffer toRangeValue(List<Object> list, ComponentEquality eq) {
    // We use a real composite as we didn't find any other way to build those ranges
    Composite c = new Composite();

    int i;
    for (i = 0; i < list.size() - 1; i++) {
        c.addComponent(list.get(i), SerializerTypeInferer.getSerializer(list.get(i)), ComponentEquality.EQUAL);
    }
    c.addComponent(list.get(i), SerializerTypeInferer.getSerializer(list.get(i)), eq);

    return c.serialize();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top