Cassandra错误 - 无法限制聚类列(前一列受非EQ关系限制)

时间:2015-12-22 18:47:54

标签: cassandra cql datastax-enterprise cql3

我们正在使用Cassandra作为我们车队管理解决方案的数据历史记录。我们在Cassandra有一张桌子,用于存储车辆行驶的详细信息。表结构如下所示

CREATE TABLE  journeydetails(
bucketid text,
vehicleid text,
starttime timestamp,
stoptime timestamp,
travelduration bigint,
PRIMARY KEY (bucketid,vehicleid,starttime,travelduration)
);

其中:

  1. bucketid: - 分区键,是月份和年份的组合
  2. vehicleid:车辆的唯一身份
  3. starttime: - 旅程的开始时间
  4. endtime: - 旅程的结束时间
  5. travelduration: - 以毫秒为单位的旅行持续时间
  6. 我们希望运行以下查询 - 获取车辆的所有行程 - 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)
    

    是否有人建议如何解决此问题?

2 个答案:

答案 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分区,然后按vehicleidstarttimetravelduration在磁盘上排序。因为您已在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)

我遇到了同样的问题。无需使用集群键和主键,您只需将索引添加到所需的列即可。这样,您就摆脱了这些陷阱,可以在查询中使用所需的任何列。