database - 在 Cassandra 中获取每个组的最新条目

标签 database cassandra

根据 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/

相关文章:

database - 如何使用 VBScript 和 UFT 连接到 oracle 数据库?

android - 如何将解析的 JSON 保存到 SQLite Android

json - 使用 NoSQL 数据库对 JSON 数据进行高效且可扩展的存储

java - Cassandra - 无法删除节点

cassandra - Cassandra中如何保证不同表上的数据一致性?

mysql - 是否可以获取 mysql 数据库中的列长度?

MySql 加入多选

sql-server - 我的任务是维护 ITEMS 库存

cassandra - 为什么我在启动时从删除的键空间中收到 Cassandra 准备好的语句重新创建错误?

java - Titan Cassandra 多线程事务锁定