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.

1 thought on “Errors and Solutions for Cassandra with Astyanax

Comments are closed.