【问题标题】:Cassandra: time series with dynamic columns/sourcesCassandra:具有动态列/源的时间序列
【发布时间】:2016-11-08 09:04:03
【问题描述】:

关于使用 cassandra 存储时间序列有很多问题,但没有人适合我们的问题,因为它们都假设一个固定的数据源和已知的列名。

关于我们的问题: 我们正在开发一个流数据引擎,它可以连接到不同的数据源,引擎以连续流的形式接收数据。 因此,例如,我们有两个数据源,分别称为 energyweather。每个传入流(或数据源)都有自己的唯一键,通常还有自己的架构,例如:

ID 1 和架构 energy 可能有这个流:

timestamp | volts | amps | watts | state
1467795743173 | 210.4 | 2.3 | 290  | "up"
1467795744173 | 212.1 | 2.1 | 287  | "up"
1467795745173 | 213.1 | 2.2 | 242  | "up"
...

ID 2 和架构 weather 可能有这个流:

ts | condition | temp
1467795740632 | "cloudy" | 33.1
1467795741381 | "cloudy" | 33.4
...

现在我们希望能够将流存储到 cassandra 中,以便以后可以使用它们来“重播”记录的流、获取历史结果(例如用于分析)以及丰富/加入具有特定存储的数据值(例如,显示/比较当前能量值与一周前记录的能量值)。总之,我们基本上需要这些东西:

  • 按顺序读取某个特定的源 ID
  • 获取某个源 ID 的范围(例如,从 2016 年 7 月 6 日 10:00 到 11:00 之间从设备 ID 2 获取所有内容)
  • 保存任意列(除了固定的时间戳列),因为我们事先不知道架构。

由于我们是 cassandra 的新手,我们目前不知道对表和列建模的最佳方法是什么。

类似问题的大多数答案都不会面临未知架构的可能性(他们都假设存在时间戳、deviceId 和双精度值),而只会面临主键/分区键的问题。

我们了解到两种选择:

  1. 我们是否应该只有一个表,例如datapoints,包含所有以source-ID+day 作为分区键的数据?但是我们如何处理这里的动态列呢?我们是否必须将整个元组序列化为单个公共列,例如将能源数据和天气数据放在一个名为value 的列中。

所以我们有这张表:

CREATE TABLE datapoints (
 sourceid bigint,
 date text, 
 time timestamp, 
 value text,
  PRIMARY KEY ((sourceid, date), time)
 )

显然,我们不能对原始值(例如瓦特、安培或温度)使用聚合或其他函数。

另一种可能性是为每个数据源创建一个表,例如使用日期作为分区键:

CREATE TABLE energy_1 (   
 date text, 
 time timestamp, 
 volts double,
 amps double,
 watts double,
 state text,
  PRIMARY KEY (date, time)
 )

CREATE TABLE weather_2 (
 date text, 
 time timestamp, 
 condition text,
 temp double,
  PRIMARY KEY (date, time)
 )

由于数据将使用日期进行分区,是否可以获取例如一个星期还是不可能的?尽管可能存在多个具有相同模式的数据源(例如两个能源数据源),但我们并不知道,而且这种情况很少见。所以使用 device-id 作为分区键是没有意义的,因为每个模式大多只有一个设备键。

但是第二种解决方案看起来也不是很合适。

希望有人也解决过类似的问题,给点建议?!

备注:我们不想使用其他时间序列数据库:)

【问题讨论】:

    标签: cassandra cql database nosql


    【解决方案1】:

    考虑为您的数据值使用地图:

    CREATE TABLE datapoints (
      sourceid bigint,
      date text, 
      time timestamp, 
      values map<text, text>,
      PRIMARY KEY ((sourceid, date), time)
     )
    

    您还可以将地图用于不同的数据类型:

    CREATE TABLE datapoints (
      sourceid bigint,
      date text, 
      time timestamp, 
      strvalues map<text, text>,
      intvalues map<text, int>,
      decvalues map<text, decimal>,
      PRIMARY KEY ((sourceid, date), time)
     )
    

    【讨论】:

      【解决方案2】:

      也许您可以混合使用这两种解决方案:

      您可以创建一个包含所有信息的表格,例如:

      CREATE TABLE datapoints (
          sourceid bigint,
          date text, 
          time timestamp, 
          value text,
          volts double,
          amps double,
          watts double,
          state text,
          condition text,
          temp double,
          PRIMARY KEY ((sourceid, date), time)
      );
      

      插入数据时,可能未指定许多列。但无论如何,cassandra 不会在磁盘上存储 NULL 值。因此,此表的列 conditionstemp 指定为在您的示例中与表 weather_2 一样。

      如果你使用 cassandra >= 3.0,yopu 可以创建materialized 视图来创建特定的表(如energy_1weather_2)或创建其他读取数据的方式(例如重新指定分区键)。

      希望对你有帮助。

      【讨论】:

      • 嗨,谢谢。但问题是:我事先不知道列(名称、列数及其数据类型)。只有在传感器连接到流引擎后,引擎才知道有例如名为伏特或温度(或其他)的列。所以创建这样的表是不可能的……
      • 好的,我忘记了这个东西。连接新传感器时可以更改表吗?因此,在初始状态下,您的表仅包含 sourceid、日期、时间(带有分区键规范)。并且您使用 alter 动态添加列。在 cassandra 中,即使表已经包含数据,它也不需要任何时间(cassandra 不存储 NULL,因此它不需要为每个现有行创建一个额外的列)。
      猜你喜欢
      • 1970-01-01
      • 2017-06-23
      • 2017-04-13
      • 2011-01-13
      • 2014-12-11
      • 2017-11-12
      • 2021-03-16
      • 2020-05-28
      相关资源
      最近更新 更多