根据 Gunwant 的要求,我想提供有关我的问题的更多信息。
我有一个包含 >10^7 行的数据库。每行是具有许多不同属性(列)的产品,例如标题、描述、价格、重量、颜色、体积、仓库位置等等。然而,所有这些属性都可能发生变化 - 价格可能上涨或下跌,描述可能会改变,它可能会移动到仓库中的另一个位置等。所有数据都存储在历史中,例如:
description | date | price | warehouse_location | color
Cucumber | 2017-01-14 | 50 | 23A | green
Cucumber | 2017-01-16 | 55 | 23A | green
Cucumber | 2017-01-19 | 52 | 14B | green
Pineapple | 2017-01-12 | 80 | 23A | yellow
Pineapple | 2017-01-17 | 75 | 23A | yellow
Pineapple | 2017-01-22 | 80 | 23A | yellow
Lemon | 2017-01-18 | 60 | 9C | yellow
Lemon | 2017-01-19 | 70 | 33E | yellow
Lemon | 2017-01-20 | 80 | 9A | yellow
我现在想创建任意报告,我需要能够过滤每一列。
例如:从 2017-01-12 到 2017-01-18 所有 warehouse_location 23A 对象的价格。如果同一对象对给定查询有多个匹配项,则只应返回该时间跨度内的最新条目。在这种情况下,“ cucumber ”应返回“55”,菠萝应返回“75”。
我需要能够一次过滤多个列。另一个例子是“价格 > 60 且价格 < 90 且日期 > 2017-01-11 且日期 < 2017-01-22 的所有对象的颜色”,它应该返回 { yellow;黄色}用于上述数据集。
原始问题:
我想将历史数据存储在 Cassandra 数据库中:
objectid | date | price | foo
1 | 2017-01-18 | 200 | A
1 | 2017-01-19 | 300 | A
1 | 2017-01-20 | 400 | B
2 | 2017-01-18 | 100 | C
2 | 2017-01-19 | 150 | C
2 | 2017-01-20 | 200 | D
3 | 2017-01-18 | 400 | E
3 | 2017-01-19 | 350 | E
3 | 2017-01-20 | 300 | F
我现在想为每个满足条件的对象的“foo”列选择最新的条目。例如,对于300到500之间的查询价格,我想得到如下信息:
objectid | date | price | foo
1 | 2017-01-20 | 400 | B
3 | 2017-01-18 | 400 | E
在 Cassandra 中可以进行这样的查询吗?
编辑: 感谢大家的努力。如果您只想获得 foo 的唯一值,Marko Švaljek 的回答似乎有效。在我的用例中,我有几十个不同的“foo 列”和 >10^7 行。我显然必须创建数百个不同的“报告”表以允许任意过滤——我不确定 Cassandra 是否是该用例的正确解决方案。
最佳答案
与 cassandra 一样,您需要对其进行反规范化。我会假设 您的基表如下所示:
create table base (
objectid int,
date timestamp,
price int,
foo text,
primary key (objectid, date)
);
请小心使用此创建语句,因为 历史数据通常增长超过 100 000 秒
然后我创建了以下插入语句:
insert into base (objectid, date, price, foo) values (1, '2017-01-18', 200, 'A');
insert into base (objectid, date, price, foo) values (1, '2017-01-19', 300, 'A');
insert into base (objectid, date, price, foo) values (1, '2017-01-20', 400, 'B');
insert into base (objectid, date, price, foo) values (2, '2017-01-18', 100, 'C');
insert into base (objectid, date, price, foo) values (2, '2017-01-19', 150, 'C');
insert into base (objectid, date, price, foo) values (2, '2017-01-20', 200, 'D');
insert into base (objectid, date, price, foo) values (3, '2017-01-18', 400, 'E');
insert into base (objectid, date, price, foo) values (3, '2017-01-19', 350, 'E');
insert into base (objectid, date, price, foo) values (3, '2017-01-20', 300, 'F');
不可能立即获得您想要的查询。但你可以去 围绕着它。
您需要创建另一个表:
create table report (
report text,
price int,
objectid int,
date timestamp,
foo text,
primary key (report, price, foo)
);
-- in cassandra if you want to search for something it has to go into clustering columns
-- and price is your first goal ... foo is there just for uniqueness
-- now you do inserts with data that you have above
-- perfectly o.k. to create multiple inserts in cassandra
insert into report (report, objectid, date, price, foo) values ('latest', 1, '2017-01-18', 200, 'A');
insert into report (report, objectid, date, price, foo) values ('latest', 1, '2017-01-19', 300, 'A');
insert into report (report, objectid, date, price, foo) values ('latest', 1, '2017-01-20', 400, 'B');
insert into report (report, objectid, date, price, foo) values ('latest', 2, '2017-01-18', 100, 'C');
insert into report (report, objectid, date, price, foo) values ('latest', 2, '2017-01-19', 150, 'C');
insert into report (report, objectid, date, price, foo) values ('latest', 2, '2017-01-20', 200, 'D');
insert into report (report, objectid, date, price, foo) values ('latest', 3, '2017-01-18', 400, 'E');
insert into report (report, objectid, date, price, foo) values ('latest', 3, '2017-01-19', 350, 'E');
insert into report (report, objectid, date, price, foo) values ('latest', 3, '2017-01-20', 300, 'F');
这会返回给你:
select objectid, date, price, foo from report where report='latest' and price > 300 and price < 500;
objectid | date | price | foo
----------+---------------------------------+-------+-----
3 | 2017-01-18 23:00:00.000000+0000 | 350 | E
1 | 2017-01-19 23:00:00.000000+0000 | 400 | B
3 | 2017-01-17 23:00:00.000000+0000 | 400 | E
这不是你想要的。您现在有几个选择。
基本上,如果您从主键中排除价格,您将得到:
create table report2 (
report text,
price int,
objectid int,
date timestamp,
foo text,
primary key (report, foo)
);
insert into report2 (report, objectid, date, price, foo) values ('latest', 1, '2017-01-18', 200, 'A');
insert into report2 (report, objectid, date, price, foo) values ('latest', 1, '2017-01-19', 300, 'A');
insert into report2 (report, objectid, date, price, foo) values ('latest', 1, '2017-01-20', 400, 'B');
insert into report2 (report, objectid, date, price, foo) values ('latest', 2, '2017-01-18', 100, 'C');
insert into report2 (report, objectid, date, price, foo) values ('latest', 2, '2017-01-19', 150, 'C');
insert into report2 (report, objectid, date, price, foo) values ('latest', 2, '2017-01-20', 200, 'D');
insert into report2 (report, objectid, date, price, foo) values ('latest', 3, '2017-01-18', 400, 'E');
insert into report2 (report, objectid, date, price, foo) values ('latest', 3, '2017-01-19', 350, 'E');
insert into report2 (report, objectid, date, price, foo) values ('latest', 3, '2017-01-20', 300, 'F');
select objectid, date, price, foo from report2 where report='latest';
objectid | date | price | foo
----------+---------------------------------+-------+-----
1 | 2017-01-18 23:00:00.000000+0000 | 300 | A
1 | 2017-01-19 23:00:00.000000+0000 | 400 | B
2 | 2017-01-18 23:00:00.000000+0000 | 150 | C
2 | 2017-01-19 23:00:00.000000+0000 | 200 | D
3 | 2017-01-18 23:00:00.000000+0000 | 350 | E
3 | 2017-01-19 23:00:00.000000+0000 | 300 | F
如果你没有太多的 foo,你可以通过在客户端过滤它来逃避它,但大多数 这在当时是一种反模式。
你也可以通过查询来实现:
select objectid, date, price, foo from report2 where report='latest' and price > 300 and price < 500 allow filtering;
objectid | date | price | foo
----------+---------------------------------+-------+-----
1 | 2017-01-19 23:00:00.000000+0000 | 400 | B
3 | 2017-01-18 23:00:00.000000+0000 | 350 | E
这并不理想,但它有点管用。
我最近创建分区的原因是分区保留在同一主机上。取决于 根据您的工作量,这可能会成为您的热门话题。
这或多或少是故事的关系方面......
如果您真正使用 cassandra,则必须预先准备好 View 。所以你会报告 2 但是会为您想要退出的每个统计组插入数据,即
insert into report2 (report, objectid, date, price, foo) values ('300-500', 1, '2017-01-19', 300, 'A');
... and so on
然后你会做:
select objectid, date, price, foo from report2 where report='300-500'
但我猜您想动态设置范围,所以这不是您想要的。这或多或少是基本的 cassandra 所做的。
然后总是有物化 View (目前它们有一些问题)我个人不会将它们用于一些非常重要的报告。
如果访问模式未知,总是有 apache spark 或一些脚本解决方案来检查数据并创建您需要的 View 。
关于database - 在 Cassandra 中获取每个组的最新条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41768069/