8

EDIT1:在原始问题之后添加了一个案例来描述问题。

我希望查询不属于我的键的列。如果我理解正确,我需要在该列上定义一个二级索引。但是,我希望使用大于条件(不仅仅是相等条件),这似乎仍然不受支持。

我错过了什么吗?你会如何解决这个问题?

我想要的设置:

Cassandra 1.1.6
CQL3

CREATE TABLE Table1(
             KeyA int,
             KeyB int,
             ValueA int,
             PRIMARY KEY (KeyA, KeyB)
           );

CREATE INDEX ON Table1 (ValueA);

SELECT * FROM Table1 WHERE ValueA > 3000;

由于 Cassandra 1.1.6 仍然不支持使用复合键在 ColumnFamilies 上定义二级索引,因此我必须解决删除其中一个键的临时解决方案,但我仍然遇到不相等条件的相同问题。

有没有另一种方法来解决这个问题?

感谢您的时间。

相关来源: http ://cassandra.apache.org/doc/cql3/CQL.html#selectStmt http://www.datastax.com/docs/1.1/ddl/indexes


编辑1

这是一个可以解释问题的案例。正如 rs-atl 所指出的,这可能是一个数据模型问题。假设我在 stackoverflow 上保留了所有用户的列族。对于每个用户,我保留了一批统计数据(Reputation、NumOfAnswers、NumOfVotes ......它们都是整数)。我想查询这些统计信息以获取相关用户。

CREATE TABLE UserStats(
             UserID int,
             Reputation int,
             NumOfAnswers int,
             .
             .
             .
             A lot of stats...
             .
             .
             .
             NumOfVotes int,
             PRIMARY KEY (UserID)
           );

现在我有兴趣根据这些统计数据对 UserID 进行切片。我想要所有信誉超过 10K 的用户,我想要所有答案少于 5 个的用户,等等。

我希望这会有所帮助。再次感谢。

4

3 回答 3

10

在 CQL 中,WHERE一旦为所有列创建了索引(即二级索引),就可以在所有列上应用该子句。否则,您将收到以下错误:

Bad Request: No indexed columns present in by-columns clause with Equal operator

不幸的是,即使使用二级索引,由于性能问题,CQL 要求 WHERE 子句在二级索引上至少有一个 EQ 。

问:为什么二级指标上总是需要至少进行一次 EQ 比较?

答:二级索引的不等式总是在内存中完成,因此如果另一个二级索引上没有至少一个 EQ,您将加载数据库中的每一行,这对于庞大的数据库不是一个好主意。因此,通过在(辅助)索引上要求至少一个 EQ,您希望将需要读入内存的行集限制在可管理的大小。(虽然显然你仍然会遇到麻烦)。

因此,基本上,如果除了 EQ 比较之外还有任何其他内容,它会加载所有“否则匹配”查询的行,并检查它们是否匹配,一次一个。默认情况下不允许这样做,因为它“可能很慢”。(本质上,索引只索引“平等”而不是像关系数据库上索引的 < 和 > 之类的其他任何东西)。

需要注意的一件事是,如果您在二级索引上有多个非 EQ 条件,您还需要ALLOW FILTERING在查询中包含关键字,否则您将得到

Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING

一种简单的解决方法是将虚拟列附加到表中,其中所有行在该列上具有相同的值。因此,在这种情况下,您可以仅对所需列执行范围查询。请务必意识到 NoSQL 数据库上的此类查询可能会很慢/使系统陷入困境。


例子

cqlsh:demo> desc table table1;

CREATE TABLE table1 (
  keya int,
  keyb int,
  dummyvalue int,
  valuea int,
  PRIMARY KEY (keya, keyb)
) ....

cqlsh:demo> select * from Table1;

 keya | keyb | dummyvalue | valuea
------+------+------------+--------
    1 |    2 |          0 |      3
    4 |    5 |          0 |      6
    7 |    8 |          0 |      9

在 ValueA 和 DummyValue 上创建二级索引:

cqlsh:demo> create index table1_valuea on table1 (valuea);
cqlsh:demo> create index table1_valueb on table1 (dummyvalue);

ValueA使用执行范围查询DummyValue=0

cqlsh:demo> select * from table1 where dummyvalue = 0 and valuea > 5 allow filtering;

 keya | keyb | dummyvalue | valuea
------+------+------------+--------
    4 |    5 |          0 |      6
    7 |    8 |          0 |      9
于 2013-08-09T22:29:47.727 回答
1

在 Cassandra 中处理这种情况的最灵活的方法可能是为每个 stat 设置一个单独的 CF,将 sentinel 值作为键,将 stat 值作为列名,如下所示:

CF: StatName {
  Key: SomeSentinelValue {
    [Value]:[UserID] = ""
  }
}

因此,假设您的统计数据是 NumAnswers,而您的用户 ID 是字符串:

CF: NumAnswers {
  Key: 0 {
    150:Joe = ""
    200:Bob = ""
    500:Sue = ""
  }
  Key: 1000 {
    1020:George = ""
    1300:Ringo = ""
    1300:Mary = ""
  }
}

因此,您可以看到您的键本质上是值的桶,可以根据您的数据需要粗粒度或细粒度,并且您的列是值 + 用户 ID 的组合。您现在可以为您需要的粗略范围(相等性)向 Cassandra 提供一个已知键(或一组键),然后对列名的第一个组件进行范围查询。请注意,您不能将用户 ID 写为值,因为这会阻止两个用户具有相同的计数。

于 2012-11-27T17:30:49.280 回答
0

主键 (KeyA, KeyB) );

在 Table1 (ValueA) 上创建索引;

SELECT * FROM Table1 WHERE ValueA > 3000;

Cassandra way就是要有一些分区键并始终使用它,可能有一个集群列,ValueA然后PRIMARY KEY ((KeyA, KeyB), ValueA)使用如下:

select * from Table1 where KeyA='xx' and ValueA > 3000

于 2018-02-12T21:47:07.350 回答