Errors and Solutions for Cassandra with Astyanax

I’m building a DAO using Astyanax, Netflix’s Java client for Cassandra, and I’ve run into a couple issues.

Following their Getting Started guide, I was able to create my `keyspace` object through which I’ll be executing reads and writes. Retrieval by id (getKey()) and multiple ids (getKeySlice(Collection)) worked fine. I created a simple row mapper to create my objects from the `ColumnList` returned. So before getting into the errors, here are some instantiations:

# Cassandra table and keyspace constructed:
CREATE TABLE users (
  user_id text,
  username text,
  department int,
  PRIMARY KEY (user_id));
# Additional index for department
CREATE INDEX department_key ON users (department);
private final ColumnFamily<String, String> USERS = new ColumnFamily<String, String>(
   "users", // Column Family Name
   StringSerializer.get(), // Key Serializer
   StringSerializer.get()); // Column Serializer

Bad Request: No indexed columns present in by-columns clause with Equal operator

My first error came from the execution of this CQL query:

OperationResult<CqlResult<String, String>> result = keyspace
        .prepareQuery(USERS)
        .withCql("SELECT * FROM users WHERE user_id = 'abc123'")
        .execute();

// Also this fails:
OperationResult<CqlResult<String, String>> result = keyspace
        .prepareQuery(USERS)
        .withCql("SELECT * FROM users WHERE user_id = ?")
        .asPreparedStatement()
        .withStringValue(userId)
        .execute();

Another problem I saw was the connection would simply timeout.

Solution

Set the CQL version (.setCqlVersion("3.0.0")) and Cassandra version (.setTargetCassandraVersion("2.0.7")) on my keyspace:

public void init() {
    context = new AstyanaxContext.Builder()
            .forKeyspace(keyspaceName)
            .withAstyanaxConfiguration(
                    new AstyanaxConfigurationImpl()
                            .setTargetCassandraVersion("2.0.7")
                            .setCqlVersion("3.0.0")
                            .setDiscoveryType(NodeDiscoveryType.RING_DESCRIBE))
            .withConnectionPoolConfiguration(
                    new ConnectionPoolConfigurationImpl("MyConnectionPool").setPort(port)
                            .setMaxConnsPerHost(1).setSeeds(host + ":" + port))
            .withConnectionPoolMonitor(new CountingConnectionPoolMonitor())
            .buildKeyspace(ThriftFamilyFactory.getInstance());

    context.start();
    keyspace = context.getClient();
}

Not enough bytes to read value of component 0

Another problem is when trying to write to the table using a MutationBatch.

MutationBatch m = keyspace.prepareMutationBatch();

m.withRow(CF_USERS, u.getId())
   .putColumn("user_id", u.getId())
   .putColumn("username", u.getUsername())
   .putColumn("department", u.getDepartment());

m.execute();

But it works with the preparedQuery:

String INSERT_STATEMENT = "INSERT INTO users (user_id, username, department) VALUES (?, ?, ?);";

keyspace.prepareQuery(CF_CONTENT_URL).withCql(INSERT_STATEMENT).asPreparedStatement()
    .withIntegerValue(u.getId()).withStringValue(u.getUsername())
    .withIntegerValue(u.getDepartment()).execute();

Solution

Create the table with COMPACT STORAGE. This unfortunately demands recreating your table, but then the MutationBatch runs fine. There is a warning in the documentation that you cannot update data in tables created with compact storage, but my tests do not confirm that.

One thought on “Errors and Solutions for Cassandra with Astyanax

Comments are closed.