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.
That’s a skillful answer to a diilfcuft question