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
EDIT1
这是一个可以解释问题的案例。正如rs-atl所指出的那样,它可能是一个数据模型问题。假设我在stackoverflow上保留了所有用户的列族。对于每个用户,我保留了一批统计信息(Reputation,NumOfAnswers,NumOfVotes ......所有这些都是int)。我想查询这些统计信息以获取相关用户。
CREATE TABLE UserStats(
UserID int,
Reputation int,
NumOfAnswers int,
.
.
.
A lot of stats...
.
.
.
NumOfVotes int,
PRIMARY KEY (UserID)
);
现在我有兴趣根据这些统计信息切片UserID。我希望所有用户信誉超过10K,我希望所有用户少于5个答案等等。
我希望有所帮助。再次感谢。
答案 0 :(得分:10)
在CQL中,一旦为它们创建索引(即二级索引),就可以在所有列上应用WHERE
子句。否则,您将收到以下错误:
Bad Request: No indexed columns present in by-columns clause with Equal operator
不幸的是,即使使用辅助索引,由于performance issue,WHERE子句也需要通过CQL在辅助索引上至少有一个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
答案 1 :(得分:1)
在Cassandra中处理这种情况的最灵活的方法可能是为每个统计数据设置一个单独的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写为值,因为这会阻止两个用户具有相同的计数。
答案 2 :(得分:0)
PRIMARY KEY(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