我试图模仿这样的事情:
给出一个表test
:
CREATE TABLE myspace.test (
item_id text,
sub_id text,
quantity bigint,
status text,
PRIMARY KEY (item_id, sub_id)
在SQL中,我们可以这样做:
select * from (select item_id, sum(quantity) as quan
from test where status <> 'somevalue') sub
where sub.quan >= 10;
即。按item_id
分组,然后用少于10的结果筛选出结果。
虽然我可以使用user-defined aggregate functions来模仿group by
,但Cassandra不是为这类东西而设计的:
CREATE FUNCTION group_sum_state
(state map<text, bigint>, item_id text, val bigint)
CALLED ON NULL INPUT
RETURNS map<text, bigint>
LANGUAGE java
AS $$Long current = (Long)state.get(item_id);
if(current == null) current = 0l;
state.put(item_id, current + val); return state;$$;
CREATE AGGREGATE group_sum(text, bigint)
SFUNC group_sum_state
STYPE map<text, bigint>
INITCOND { }
并将其用作group by
(可能这会有非常糟糕的表现,但仍然如此):
cqlsh:myspace> select group_sum(item_id, quantity) from test;
mysales_data.group_sum(item_id, quantity)
-------------------------------------------
{'123': 33, '456': 14, '789': 15}
但似乎不可能通过映射值进行过滤,既不是聚合的最终函数也不是单独的函数。我可以定义一个这样的函数:
CREATE FUNCTION myspace.filter_group_sum
(group map<text, bigint>, vallimit bigint)
CALLED ON NULL INPUT
RETURNS map<text, bigint>
LANGUAGE java
AS $$
java.util.Iterator<java.util.Map.Entry<String, Long>> entries =
group.entrySet().iterator();
while(entries.hasNext()) {
Long val = entries.next().getValue();
if (val < vallimit)
entries.remove();
};
return group;$$;
但是没有办法调用它并传递一个常量:
select filter_group_sum(group_sum(item_id, quantity), 15) from test;
SyntaxException: <ErrorMessage code=2000 [Syntax error in CQL query]
message="line 1:54 no viable alternative at input '15'
(...(group_sum(item_id, quantity), [15]...)">
它抱怨常数15
。
很抱歉这篇长篇文章,我需要提供所有细节来解释我的需求。 所以我的问题是:
quantity
大于给定限制的所有项目?这些表格非常大,就像10亿条记录一样。 答案 0 :(得分:3)
Vanilla Cassandra对于即席查询来说是一个糟糕的选择。 DataStax Enterprise通过与Spark和Solr的集成添加了一些此功能。 Spark集成也是开源的,但您不希望为低延迟查询执行此操作。如果您需要实时查询,则必须在Cassandra之外进行聚合(例如,在Spark或Storm中),然后回写您的应用程序要使用的聚合。您还可以查看Stratio的Lucene integration,它可能会帮助您解决一些问题。