我们正在使用Cassandra作为我们车队管理解决方案的数据历史记录。我们在Cassandra有一张桌子,用于存储车辆行驶的详细信息。表结构如下所示
CREATE TABLE journeydetails(
bucketid text,
vehicleid text,
starttime timestamp,
stoptime timestamp,
travelduration bigint,
PRIMARY KEY (bucketid,vehicleid,starttime,travelduration)
);
其中:
我们希望运行以下查询 - 获取车辆的所有行程 - 2015-12-1和2015-12-3之间的1234567,其行程持续时间大于30分钟
当我运行此查询时:
select * from journeydetails where bucketid in('2015-12') and vehicleid in('1234567')
and starttime > '2015-12-1 00:00:00' and starttime < '2015-12-3 23:59:59'
and travelduration > 1800000;
我得到了这个结果:
InvalidRequest: code=2200 [Invalid query] message="Clustering column "travelduration"
cannot be restricted (preceding column "starttime" is restricted by a non-EQ relation)
是否有人建议如何解决此问题?
答案 0 :(得分:22)
select * from journeydetails where bucketid in('2015-12') and vehicleid in('1234567')
and starttime > '2015-12-1 00:00:00' and starttime < '2015-12-3 23:59:59'
and travelduration > 1800000;
那不行。原因可以追溯到Cassandra如何在磁盘上存储数据。 Cassandra的想法是,使用精确的密钥返回单行,或者从磁盘返回连续的行范围非常有效。
您的行按bucketid
分区,然后按vehicleid
,starttime
和travelduration
在磁盘上排序。因为您已在starttime
上执行范围查询(非EQ关系),所以不能限制后面的密钥。这是因为travelduration
限制可能会取消您的范围条件中的某些行的资格。这将导致低效,不连续的读取。 Cassandra旨在保护您免于编写可能具有不可预测性能的查询(如此)。
以下是两种选择:
1-如果您可以限制travelduration
之前的所有关键列(使用等于关系),那么您可以应用大于条件:
select * from journeydetails where bucketid='2015-12' and vehicleid='1234567'
and starttime='2015-12-1 00:00:00' and travelduration > 1800000;
当然,限制精确的starttime
可能不是非常有用。
2-另一种方法是完全省略travelduration
,然后你的原始查询就可以了。
select * from journeydetails where bucketid='2015-12' and vehicleid='1234567'
and starttime > '2015-12-1 00:00:00' and starttime < '2015-12-3 23:59:59';
不幸的是,Cassandra没有提供很大程度的查询灵活性。许多人使用Spark(与Cassandra一起)等解决方案取得了成功,以实现此级别的报告。
只是旁注,但除非必须,否则不要使用IN
。使用IN
查询类似于使用辅助索引,因为Cassandra必须与多个节点通信以满足您的查询。用一个项目调用它可能不是太大的交易。但是IN
是那些旧的RDBMS习惯之一,你在进入Cassandra之前应该真正打破这些习惯。
答案 1 :(得分:-1)
我遇到了同样的问题。无需使用集群键和主键,您只需将索引添加到所需的列即可。这样,您就摆脱了这些陷阱,可以在查询中使用所需的任何列。