-
Notifications
You must be signed in to change notification settings - Fork 1
Getting Started
All configuration options are encapsulated in a single ConnectionPoolConfiguration interface. As with many Astyanax components you can implement your own configuration logic (for example, one that binds with properties or beans). A simple configuration is provided in ConnectionPoolConfigurationImpl. Many defaults are provided out of the box but you must specify at least on seed in the format of comma delimited list of “host:port” pairs.
’’’java
ConnectionPoolConfigurationImpl config =
new ConnectionPoolConfigurationImpl(“ClusterName”, “KeyspaceName”);
config.setSeeds(“127.0.0.1:9160”);
Keyspace keyspace = new ThriftKeyspaceImpl(config);
keyspace.start();
‘’’
Cassandra internally stores all keys, columns and values as byte arrays. Astyanax makes use of serializers to convert to and from various primitives and more complex data types. To avoid having to specify serializers for every call you must first set up the column family definition. This definition will most likely be a static final in your DAO or other higher level wrapper. Notice that the definition is at the column family and not the keyspace level. This allows you to have different key types for column families within the same keyspace.
’’’java
ColumnFamily<String, String> CF_USER_INFO =
new ColumnFamily<String, String>(
“Standard1”, // Column Family Name
StringSerializer.get(), // Key Serializer
StringSerializer.get()); // Column Serializer
‘’’
Data may be inserted either one column at a time or in batches.
’’’java
// Inserting data
MutationBatch m = keyspace.prepareMutationBatch();
m.withRow(CF_USER_INFO, “acct1234”)
.putColumn(“firstname”, “john”, null)
.putColumn(“lastname”, “smith”, null)
.putColumn(“address”, “555 Elm St”, null)
.putColumn(“age”, 30, null);
m.withRow(CF_USER_STATS, “acct1234”)
.incrementCounterColumn(“loginCount”, 1);
try {
OperationResult result = m.execute();
} catch (ConnectionException e) {
}
‘’’
The Astyanax queries begin with a single interface and guide you through the possible query options in a natural flow starting with different key queries (single, slice, range) followed by column level qualifiers. Once the query is complete you many call several different execute() methods which provide different internal implementations for parallelizing the query execution on the client. Each query will return the proper level of information (Rows, Row, ColumnList, Column, Count) with the appropriate types derived from the ColumnFamily definition object.
’’’java
OperationResult<ColumnList> result =
ks.prepareQuery(CF_USER_INFO, keyName)
.getKey(“Key1”).
.execute();
ColumnList columns = result.getResult();
// Lookup columns in response by name
int age = columns.getColumnByName(“age”).getIntegerValue();
long counter = columns.getColumnByName(“loginCount”).getLongValue();
String address = columns.getColumnByName(“address”).getStringValue();
// Or, iterate through the columns
for (Column c : result.getResult()) {
System.out.println(c.getName());
}
‘’’
’’’java
OperationResult<Rows<String, String>> result =
ks.prepareQuery(CF_STANDARD1)
.getKeySlice(“Key1”, “Key2”, “Key3”)
.execute();
// Iterate rows and their columns
for (Row<String, String> row : result.getResult()) {
System.out.println(row.getKey());
for (Column column : row.getColumns()) {
System.out.println(column.getName());
}
}
‘’’
Astyanax provides a simple annotation based definition for composite columns. The ordinal annotation attribute is necessary to guarantee the order in which the composite components are serialized.
’’’java
// Annotated composite class
Class SessionEvent{
@Component(ordinal=0) String sessiondId;
@Component(ordinal=1) TimeUUID timestamp;
}
static AnnotatedCompositeSerializer eventSerializer
= new AnnotatedCompositeSerializer(SessionEvent.class);
static ColumnFamily<String, SessionEvent> CF_SESSION_EVENTS
= new ColumnFamily<String, SessionEvent>(”SessionEvents",
StringSerializer.get(), eventSerializer);
// Querying cassandra for all columns of row key “SomeSessionId” starting with
keyspace.prepareQuery(CF_SESSION_EVENTS)
.getKey(”SomeUserName")
.withColumnRange(
eventSerializer.makeEndpoint(“sessionid1", Equality.EQUAL).toBytes(),
eventSerializer.makeEndpoint(“sessionid1”, Equality.LESS_THAN_EQUAL).toBytes(),
false, 100)
.execute();
‘’’
Pagination is done transparently by calling setIsPaginating() where appropriate. It is possible to paginate key ranges (all using the same non paginating column slice), index queries and columns of a single row. Astyanax handles all of the internal details of how to determine the next rowkey or column name without returning duplicates to the caller.
’’’java
String column = "";
ColumnList columns;
try {
RowQuery<String, String> query = keyspace
.prepareQuery(CF_STANDARD1)
.getKey(“TheRowKey”)
.setIsPaginating()
.withColumnRange(new RangeBuilder().setStart(column).setMaxSize(10).build());
} catch (ConnectionException e) {
}
‘’’
This is arguably a very bad use case of cassandra but one that is very useful for column families that store a small number of rows. Astyanax provides to methods for executing this query. The first wraps the iterator interface and transparently queries cassandra when .next() is called. The second queries each token range from a separate thread and returns the rows via a callback interface.
’’’java
try {
OperationResult<Rows<String, String>> rows = keyspace.prepareQuery(CF_STANDARD1)
.getAllRows()
.setRowLimit(100) // This is the page size
.withColumnRange(new RangeBuilder().setMaxSize(10).build())
.setExceptionCallback(new ExceptionCallback() {
@Override
public boolean onException(ConnectionException e) {
Assert.fail(e.getMessage());
return true;
}
})
.execute();
for (Row<String, String> row : rows.getResult()) {
LOG.info("ROW: " + row.getKey() + " " + row.getColumns().size());
}
} catch (ConnectionException e) {
Assert.fail();
}
‘’’
The ExceptionCallback is necessary since the Iterator cannot throw checked exception. The callback gives the caller the opportunity to force Astyanax to retry the query.
’’’java
keyspace.prepareQuery(CF_STANDARD1)
.getAllRows()
.setRowLimit(100) // This is the page size
.setRepeatLastToken(false)
.withColumnRange(new RangeBuilder().setMaxSize(2).build())
.executeWithCallback(new RowCallback<String, String>() {
@Override
public void success(Rows<String, String> rows) {
for (Row<String, String> row : rows) {
System.out.println("ROW: " + row.getKey() + " " + row.getColumns().size());
}
}
@Override
public boolean failure(ConnectionException e) {
return false;
}
});
‘’’
The range builder simplifies specifying the start and end columns for a column range query.
A Netflix Original Production
Tech Blog | Twitter @NetflixOSS | Jobs