Cassandra:具有动态 columns/sources 的时间序列
Cassandra: time series with dynamic columns/sources
有很多关于用 cassandra 存储时间序列的问题,但没有一个适合我们的问题,因为它们都假定一个固定的数据源和已知的列名。
关于我们的问题:
我们正在开发一个流数据引擎,它可以连接到不同的数据源,引擎以连续流的形式接收数据。
因此,我们有两个数据源,例如 energy
和 weather
。每个传入流(或数据源)都有自己唯一的键,通常也有自己的模式,例如:
源 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 中的可能性,以便稍后可以将它们用于 "replay" 记录的流,获取历史结果(例如用于分析)和 enrich/join 具有特定存储数据值的传入流(例如 show/compare 当前能量值与一周前记录的能量值)。总之,我们基本上需要这些东西:
- 按顺序读取特定来源 ID
- 获取特定源 ID 的范围(例如,从 2016 年 7 月 6 日的 10:00 到 11:00 之间的设备 ID 2 中获取所有范围)
- 保存任意列(除了固定的时间戳列),因为我们事先不知道架构。
由于我们是 cassandra 的新手,我们目前不知道什么是对 table 和列建模的最佳方法。
大多数类似问题的答案都不会面临未知模式的可能性(他们都假设有时间戳、deviceId 和双精度值),只会面临 primary/partion 键的问题。
我们读到了两个选项:
- 我们要不要单曲table,例如
datapoints
,其中包含所有以source-ID+day作为分区键的数据?但是我们如何处理这里的动态列呢?我们是否必须将整个元组序列化为一个公共列,例如将能源数据和天气数据都放在一个名为 value
的列中。
所以我们有这个 table:
CREATE TABLE datapoints (
sourceid bigint,
date text,
time timestamp,
value text,
PRIMARY KEY ((sourceid, date), time)
)
显然,我们不能对原始值(例如瓦特、安培或温度)使用聚合或其他函数。
另一种可能性是为每个数据源创建一个 table,例如使用日期作为分区键:
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)
)
由于数据将使用日期进行分区,是否可以获取例如一周还是这不可能?尽管可能有不止一个数据源具有相同的模式(例如两个能源数据源),但我们并不知道这一点,而且这种情况很少见。所以使用设备 ID 作为分区键是没有意义的,因为大多数情况下每个模式只有一个设备键。
但是第二种方案看起来也不太合适table。
我们希望有人也解决了类似的问题并提供一些建议?!
备注:我们不想使用其他时间序列数据库:)
也许您可以混合使用这两种解决方案:
您可以创建一个包含所有信息的 table,例如:
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 值。因此,此 table 列 conditions
和 temp
指定为 mutch space as table weather_2
在你的例子中。
如果你使用 cassandra >= 3.0,yopu 可以创建 materialized 视图来创建特定的 tables(比如 energy_1
和 weather_2
)或者以其他方式创建读取数据(例如重新指定分区键)。
希望对您有所帮助。
考虑为您的数据值使用地图:
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)
)
有很多关于用 cassandra 存储时间序列的问题,但没有一个适合我们的问题,因为它们都假定一个固定的数据源和已知的列名。
关于我们的问题:
我们正在开发一个流数据引擎,它可以连接到不同的数据源,引擎以连续流的形式接收数据。
因此,我们有两个数据源,例如 energy
和 weather
。每个传入流(或数据源)都有自己唯一的键,通常也有自己的模式,例如:
源 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 中的可能性,以便稍后可以将它们用于 "replay" 记录的流,获取历史结果(例如用于分析)和 enrich/join 具有特定存储数据值的传入流(例如 show/compare 当前能量值与一周前记录的能量值)。总之,我们基本上需要这些东西:
- 按顺序读取特定来源 ID
- 获取特定源 ID 的范围(例如,从 2016 年 7 月 6 日的 10:00 到 11:00 之间的设备 ID 2 中获取所有范围)
- 保存任意列(除了固定的时间戳列),因为我们事先不知道架构。
由于我们是 cassandra 的新手,我们目前不知道什么是对 table 和列建模的最佳方法。
大多数类似问题的答案都不会面临未知模式的可能性(他们都假设有时间戳、deviceId 和双精度值),只会面临 primary/partion 键的问题。
我们读到了两个选项:
- 我们要不要单曲table,例如
datapoints
,其中包含所有以source-ID+day作为分区键的数据?但是我们如何处理这里的动态列呢?我们是否必须将整个元组序列化为一个公共列,例如将能源数据和天气数据都放在一个名为value
的列中。
所以我们有这个 table:
CREATE TABLE datapoints (
sourceid bigint,
date text,
time timestamp,
value text,
PRIMARY KEY ((sourceid, date), time)
)
显然,我们不能对原始值(例如瓦特、安培或温度)使用聚合或其他函数。
另一种可能性是为每个数据源创建一个 table,例如使用日期作为分区键:
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)
)
由于数据将使用日期进行分区,是否可以获取例如一周还是这不可能?尽管可能有不止一个数据源具有相同的模式(例如两个能源数据源),但我们并不知道这一点,而且这种情况很少见。所以使用设备 ID 作为分区键是没有意义的,因为大多数情况下每个模式只有一个设备键。
但是第二种方案看起来也不太合适table。
我们希望有人也解决了类似的问题并提供一些建议?!
备注:我们不想使用其他时间序列数据库:)
也许您可以混合使用这两种解决方案:
您可以创建一个包含所有信息的 table,例如:
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 值。因此,此 table 列 conditions
和 temp
指定为 mutch space as table weather_2
在你的例子中。
如果你使用 cassandra >= 3.0,yopu 可以创建 materialized 视图来创建特定的 tables(比如 energy_1
和 weather_2
)或者以其他方式创建读取数据(例如重新指定分区键)。
希望对您有所帮助。
考虑为您的数据值使用地图:
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)
)