日期:2014-05-16  浏览次数:20490 次

Cassandra1.1.1建立复合主键后,如何再建立二级索引?

最近在使用Cassandra,版本为1.1.1, CQL版本为3.0.0。遇到如下问题。

目标:利用复合主键进行查询和排序,并想利用二级索引进行多条件查询。

首先CQL建表,用到复合主键(instigator, startedAt):

?

    CREATE TABLE altercations ( instigator text, startedAt text, shipsDestroyed text, energyUsed text,allianceInvolvement text, PRIMARY KEY (instigator, startedAt) );

然后建立二级索引:

CREATE INDEX ON altercations (shipsDestroyed);

执行CREATE INDEX 操作后,Cassandra报错:

    java.lang.IllegalArgumentException
    at java.nio.Buffer.limit(Buffer.java:249)
    at org.apache.cassandra.db.marshal.AbstractCompositeType.getBytes(AbstractCompositeType.java:51)
    at org.apache.cassandra.db.marshal.AbstractCompositeType.getWithShortLength(AbstractCompositeType.java:60)
    at org.apache.cassandra.db.marshal.AbstractCompositeType.getString(AbstractCompositeType.java:140)
    at org.apache.cassandra.config.CFMetaData.getDefaultIndexName(CFMetaData.java:875)
    at org.apache.cassandra.config.CFMetaData.addDefaultIndexNames(CFMetaData.java:863)
    at org.apache.cassandra.cql3.statements.CreateIndexStatement.announceMigration(CreateIndexStatement.java:90)
    at org.apache.cassandra.cql3.statements.SchemaAlteringStatement.execute(SchemaAlteringStatement.java:99)
    at org.apache.cassandra.cql3.QueryProcessor.processStatement(QueryProcessor.java:108)
    at org.apache.cassandra.cql3.QueryProcessor.process(QueryProcessor.java:121)
    at org.apache.cassandra.thrift.CassandraServer.execute_cql_query(CassandraServer.java:1237)
    at org.apache.cassandra.thrift.Cassandra$Processor$execute_cql_query.getResult(Cassandra.java:3542)
    at org.apache.cassandra.thrift.Cassandra$Processor$execute_cql_query.getResult(Cassandra.java:3530)
    at org.apache.thrift.ProcessFunction.process(ProcessFunction.java:32)
    at org.apache.thrift.TBaseProcessor.process(TBaseProcessor.java:34)
    at org.apache.cassandra.thrift.CustomTThreadPoolServer$WorkerProcess.run(CustomTThreadPoolServer.java:186)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:619)

?但是,把复合主键改为单一主键的话,这个错误是没有的。

?

?

经过一天的思考,发现确实不能建立二级索引了。
本人对二级索引建立的内部原理不是很清楚,但参考Apache Cassandra 1.1 Documentation,发现确实只能用主键查询(就是多建几个主键),而且多条件查询时(除最后一个外)必须用“=”表达式。
比如像这样:
建表:

CREATE TABLE altercations ( instigator text, startedAt text, shipsDestroyed text, energyUsed text, allianceInvolvement text, PRIMARY KEY (instigator, startedAt, shipsDestroyed) );

?
查询:

SELECT * FROM altercations WHERE instigator='Jayne Cobb' AND startedAt = '7943-06-23' AND shipsDestroyed>'3' ORDER BY startedAt DESC;

?

.===============分隔符============================

问题:

?

后来,有添加了一个复合主键, 建表语句为:

CREATE TABLE altercations ( instigator text, startedAt text, shipsDestroyed text, energyUsed text, allianceInvolvement text, PRIMARY KEY (instigator, startedAt, shipsDestroyed, energyUsed) );

?查询语句:

SELECT * FROM altercations WHERE instigator='Jayne Cobb' AND startedAt = '7943-06-23' AND shipsDestroyed='3' AND energyUsed>'4.6' ORDER BY startedAt DESC;

?发现搜索出的结果完全混乱了,根本不是按条件查询出来的,如下:

?

instigator : Jayne Cobb; ?startedat : 7943-06-24; ?shipsdestroyed : 7; ?energyused : 4.6; ?allianceinvolvement : false; ?gender : null; ?
instigator : Jayne Cobb; ?startedat : 7943-06-24; ?shipsdestroyed : 6; ?energyused : 4.6; ?allianceinvolvement : false; ?gender : null; ?
instigator : Jayne Cobb; ?startedat : 7943-06-24; ?shipsdestroyed : 5; ?energyused : 4.6; ?allianceinvolvement : false; ?gender : null; ?
instigator : Jayne Cobb; ?startedat : 7943-06-