Java 我应该如何在Cassandra中存储日期间隔?

Java 我应该如何在Cassandra中存储日期间隔?,java,nosql,cassandra,Java,Nosql,Cassandra,我正在开发一个存储传感器测量值的应用程序。有时,传感器会发送错误的测量值(例如,测量值超出范围)。我们不希望单独保留每个测量误差,但我们希望保留关于这些误差的统计信息,例如传感器id、第一个误差的日期、最后一个误差的日期,以及其他信息,如连续误差的数量,我将在这里省略这些信息 下面是“ErrorStatistic”类的简化版本: 我目前使用Hector将这些错误统计数据保存如下: private void persistErrorStatistic(ErrorStatistic errorSta

我正在开发一个存储传感器测量值的应用程序。有时,传感器会发送错误的测量值(例如,测量值超出范围)。我们不希望单独保留每个测量误差,但我们希望保留关于这些误差的统计信息,例如传感器id、第一个误差的日期、最后一个误差的日期,以及其他信息,如连续误差的数量,我将在这里省略这些信息

下面是“ErrorStatistic”类的简化版本:

我目前使用Hector将这些错误统计数据保存如下:

private void persistErrorStatistic(ErrorStatistic errorStatistic) {
    Mutator<String> mutator = HFactory.createMutator(keyspace, StringSerializer.get());

    String rowKey = errorStatistic.getSensorId();
    String columnName = errorStatistic.getStartDate().toString(YYYY_MM_DD_FORMATTER);
    byte[] value = serialize(errorStatistic);

    HColumn<String, byte[]> column = HFactory.createColumn(columnName, value, StringSerializer.get(), BytesArraySerializer.get());
    mutator.addInsertion(rowKey, COLUMN_FAMILY, column);

    mutator.execute();
}

private static final DateTimeFormatter YYYY_MM_DD_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd");
如果我向卡桑德拉询问日期:

  • 2012-08-04T10:00Z-->它应该返回第一个ErrorStatistic
  • 2012-09-04T00:00Z-->此时应返回没有错误
  • 2014-01-03T00:00Z-->它应该返回最后一个ErrorStatistic(因为它是开放式的)
我不确定应该如何存储和“索引”这些ErrorStatistic对象,以便有效地查询它们。我对卡桑德拉很陌生,我可能错过了一些明显的东西


编辑:添加以下内容是为了回应Joost的建议,即我应该关注我感兴趣的查询类型

我将有两种类型的查询:

  • 第一,正如您所猜测的,是列出给定传感器和时间范围的所有错误统计信息。这似乎相对容易。我唯一的问题是,当ErrorStatistics在我感兴趣的时间范围之前开始时(例如,我查询4月份的所有错误,我希望我的查询也返回ErrorStatistics[2012-03-29:2012-04-02])
  • 第二个问题似乎更难回答。我想查找给定传感器和日期的错误统计信息,其间隔包含给定日期,或其
    startDate
    位于给定日期之前,且带有空
    endDate
    (这意味着我们仍然收到此传感器的错误)。我不知道如何有效地做到这一点。我可以加载给定传感器的所有错误统计信息,然后用Java检查间隔。。。但如果可能的话,我想避免这种情况。我想我希望Cassandra从一个给定的日期开始,向后看,直到它找到第一个错误统计数据,并且在给定的日期(如果有的话)之前有一个
    startDate
    ,然后加载它并在Java中检查它的
    endDate
    是否为
    null
    或者在给定的日期之后。但我不知道这是否可能,以及效率有多高

你要问自己的问题是你对错误统计有什么问题。Cassandra模式设计通常从“每个查询一个表”的方法开始。不要从你拥有的数据(实体)开始,而是从你的问题/查询开始。这是一种不同于“传统”rdbms设计的思维方式,我发现需要一些时间来适应

例如,是否要查询每个传感器的统计信息?而具有复合键(传感器id、timeuuid)的表可能是一个解决方案。这样的表格允许根据传感器id进行快速查找,并根据时间对结果进行排序

如果希望仅基于时间查询传感器统计信息,则具有时间单位的(复合)键可能会更有帮助,可能还可以使用分片元素来更好地将负载分布到节点上。注意,这里有一个问题:使用Cassandra随机或杂音分割器对主键进行范围查询是不可行的。还有其他分区器,但它们很容易导致集群中的负载分布不均匀

简而言之,从你想要的答案开始,然后“向后”到你的桌子设计。有了正确的模式,您的代码将遵循


添加(2013-9-5):很高兴知道的是Cassandra在单个分区键的范围内对数据进行排序。这是非常有用的。例如,如果您将表格定义为:

create table SensorByDate
(
    sensor_id uuid,
    start_date datetime,
    end_date datetime,
    measurement int
    primary key (sensor_id, start_date)
)
with clustering order by (start_time DESC);
在本例中,sensor_id是分区键,并确定该行存储在哪个节点上。开始日期是组合键中的第二项,决定排序顺序

要获取此表中某个开始日期之后的第一个度量值,可以制定如下查询

select * from SensorByDate 
where sensor_id = ? and start_date < ? limit 1
从SensorByDate中选择*
其中传感器_id=?和开始日期<?限制1

我喜欢您使用“每查询一个表”方法设计模式的想法。作为一个新的Cassandra用户,需要一些时间来适应它。我将更新我的问题,以指定我感兴趣的两种查询类型。
create table SensorByDate
(
    sensor_id uuid,
    start_date datetime,
    end_date datetime,
    measurement int
    primary key (sensor_id, start_date)
)
with clustering order by (start_time DESC);
select * from SensorByDate 
where sensor_id = ? and start_date < ? limit 1