Java Cassandra中的范围查询

Java Cassandra中的范围查询,java,cassandra,datastax-java-driver,Java,Cassandra,Datastax Java Driver,我正在使用Cassandra2.1.2和相应的DataStax Java驱动程序以及DataStax提供的对象映射 下表定义: CREATE TABLE IF NOT EXISTS ses.tim (id text PRIMARY KEY, start bigint, cid int); 映射: @Table(keyspace = "ses", name = "tim") class MyObj { @PartitionKey private String id; pr

我正在使用Cassandra2.1.2和相应的DataStax Java驱动程序以及DataStax提供的对象映射

下表定义:

CREATE TABLE IF NOT EXISTS ses.tim (id text PRIMARY KEY, start bigint, cid int);
映射:

@Table(keyspace = "ses", name = "tim")
class MyObj {
    @PartitionKey
    private String id;
    private Long start;
    private int cid;
}
访问者

@Accessor
interface MyAccessor {
    @Query("SELECT * FROM ses.tim WHERE id = :iid")
    MyObj get(@Param("iid") String id);

    @Query(SELECT * FROM ses.tim WHERE start <= :sstart")
    Result<MyObj> get(@Param("sstart") long start);
}
这似乎不起作用(我读了很多解释,为什么它决定不支持这一点,但我仍然不明白为什么有人会给出这样的限制,无论如何……)

所以,据我所知,WHERE子句中必须至少有一个等式

@Query(SELECT * FROM ses.tim WHERE cid = :ccid AND start <= :sstart")

CREATE INDEX IF NOT EXISTS myindex2 ON ses.tim (cid);
然后我试着

id text, start bigint, cid int, PRIMARY KEY (id, start, cid)

但还是没有运气

此外,我尝试将“start”设置为PartitionKey,但只能再次使用Equals进行查询

我错过了什么?如何获得此类查询的结果

编辑:版本更新为正确版本

我用的是卡桑德拉2.1.3

我不认为2.1.3已经发布。当前显示2.1.2为最高版本

从我所看到的情况来看,这里的主要问题是分区键
id
要么是唯一的,要么基数太高,对您没有用处。目前,您正在采用RDBMS风格的方法(通过唯一ID)存储数据。使用Cassandra,您希望以查询数据的方式存储数据。第一步是选择一个好的键来对数据进行分区

因此,我尝试创建一个二级索引

在这里您不想做的另一件事是使用二级索引。我看得出你很想这么做,你应该马上把这个想法忘掉。二级索引是为了方便而创建的。它们不是为了性能而创建的,也不是为了在数据模型上采用快捷方式而创建的

Cannot execute this query as it might involve data filtering and thus
may have unpredictable performance.
说到临时性,当看到此消息时,您可能会考虑尝试向查询中添加
ALLOW FILTERING
。绝对不要那样做。它直截了当地警告您这样做不会有好的表现,您应该注意这个警告

如果这能起作用,我必须知道cid的所有可能值,并分别查询它们,然后在客户机上执行其余的操作

cid的唯一性如何?如果必须获取并迭代所有的<代码> CID s太繁琐,那么您应该考虑选择/创建一个不太独特的值来进行分区。但是,假设
cid
将起作用,表定义应该是这样的:

CREATE TABLE IF NOT EXISTS ses.tim 
(cid int,
 start bigint,
 id text,
 PRIMARY KEY ((cid),start);

@Table(keyspace = "ses", name = "tim")
class MyObj {
    @PartitionKey
    private int cid;
    @ClusteringColumn(0)
    private Long start;
    private String id;
}
有了这个基础表定义,这个查询现在应该可以工作了

@Query("SELECT * FROM ses.tim WHERE cid = :ccid AND start <= :sstart")

<代码> >查询(从SESS.TIME中选择SED,CID=:CCID和Stest

)如果您对同一组数据有不同的查询能力需求,您可以考虑对数据进行反规范化。根据您的问题,听起来您想要如下:

  • id
  • 通过
    start
第一个查询工作正常,正如您在当前架构中所指出的。但是,如果没有二级索引,第二个查询将无法正常工作,因为您已经调查过了(我总是针对二级索引)

您表示不想在
cid
上分区,因为您需要知道
cid
的所有可能值

我能想到三个想法:

  • 使用伪主键创建一个单独的表,以便将所有数据存储在同一分区中。但是,如果有多个条目创建超宽分区,并且在任何节点上保留该数据的热点,则可能会出现问题。您计划拥有多少个

    create table if not exists tim (
        dummy int, 
        start bigint, 
        id text, 
        cid int, 
        primary key (dummy, start)
    );
    
    然后可以进行如下查询:

    select * from tim where dummy=0 and start <= 10;
    

    从tim中选择*,其中dummy=0,并开始查看此工具以可视化数据模型(仍在开发中)。第三个选项卡将为您的表定义提供可能的查询:谢谢,我同意您的第一个建议,使虚拟PK具有一定的范围以避免hotspotting@divadpoc你可能误解了Andy的观点。他说用虚拟PK存储数据是“有问题的”,因为它会超宽分区和任何节点上的热点都保存该数据。“使用虚拟PK,您将遇到热点…更不用说无限行增长的问题了。@BryceAtNetwork23感谢您指出这一点。我没有误读它。我想看看它在有一个范围(而不仅仅是一个值)时的性能如何。”可能扩大范围…写“避免”热点是我的错…我只是想看看它是如何执行的,如果热点太糟糕,我们必须考虑其他的想法在这里指出。
    
    @Query("SELECT * FROM ses.tim WHERE cid = :ccid AND start <= :sstart")
    
    create table if not exists tim (
        dummy int, 
        start bigint, 
        id text, 
        cid int, 
        primary key (dummy, start)
    );
    
    select * from tim where dummy=0 and start <= 10;
    
    select * from tim where start <= 10 ALLOW FILTERING;