未知数据的Cassandra时间切片数据模型

未知数据的Cassandra时间切片数据模型,cassandra,Cassandra,我警告这个问题:我对NoSQL有点陌生,对Cassandra也很陌生,但它似乎很适合我要做的事情 假设我有一个以合理间隔提供输入的传感器列表。我建议的数据模型是根据传感器的名称、位置(区域)和日期(写为yyyyMMdd)进行分区,并根据实际发生读数的时间对当天的读数进行聚类。我们的想法是,“在日期B获取传感器A的所有读数”的查询应该非常快。到目前为止,我认为还不错。表/CF在CQL中如下所示: CREATE TABLE data ( area_id int, sensor var

我警告这个问题:我对NoSQL有点陌生,对Cassandra也很陌生,但它似乎很适合我要做的事情

假设我有一个以合理间隔提供输入的传感器列表。我建议的数据模型是根据传感器的名称、位置(区域)和日期(写为yyyyMMdd)进行分区,并根据实际发生读数的时间对当天的读数进行聚类。我们的想法是,“在日期B获取传感器A的所有读数”的查询应该非常快。到目前为止,我认为还不错。表/CF在CQL中如下所示:

CREATE TABLE data (
    area_id int,
    sensor varchar,
    date ascii,
    event_time timeuuid,
    PRIMARY KEY ((area_id, sensor, date), event_time)
) WITH CLUSTERING ORDER BY (event_time DESC);
然而,这实际上并不包括任何数据,我不知道如何将其添加到模型中。每次读取(来自同一个传感器)都可能有不同的任意数据集,我无法提前知道这是什么。例如,我可以得到温度数据,湿度数据,两者都可以,或者我可以得到我以前从未见过的东西。由实际记录数据的人决定他们想要提交什么(不是从自动传感器读取)

鉴于我想对这些数据(基本上是UGC)进行查询操作,我的选择是什么?查询通常包括对数据的计数(例如,在日期B上传感器A的计数读数,其中一些值X=C和一些值Y=D)。值得注意的是,将有比通常一次查询更多的数据点。一个读数可能有20个数据值,但可能只会查询2或3个数据值——只是不知道提前查询哪个数据值

目前我想到:

  • 将每个传感器读数的数据存储为地图类型。这当然会使模型变得简单,但我的理解是,查询将很困难?我想我需要为每个传感器读数把整个地图拉回来,然后检查数值,并在Storm/Hadoop/任何东西中的Cassandra之外进行计数
  • 将每个用户值存储为另一列(包含事件\时间uuid的复合列)。这意味着不使用CQL,因为它不支持在插入时添加任意新列。不过,Thrift API允许这样做。这意味着我可以让卡桑德拉自己数数

  • 也许我走错了方向?也许卡桑德拉甚至不是这类数据的最佳选择;博士,你不能同时选择速度和绝对灵活性;-)

    基于来自用户生成内容的数据的查询将非常复杂-您将无法生成一个一刀切的表定义,该表定义将允许快速响应基于UGC内容的查询。即使您选择使用Maps,Cassandra也必须对每个查询的整个数据结构进行反序列化,因此它实际上不是big Maps的选项,正如您在问题中所建议的那样

    另一种方法是以串行形式存储传感器数据,例如json。这将为存储内容提供最大的灵活性,但代价是无法进行复杂的查询。序列化/反序列化负担推送到客户机,所有数据通过线路发送。下面是一个简单的例子:

    表的创建(比您的示例稍微简单-我已经删除了
    date
    ):

    插入:

    insert into data(area_id,sensor,event_time,data) VALUES (1,'sensor1',now(),'["datapoint1":"value1"]');
    insert into data(area_id,sensor,event_time,data) VALUES (1,'sensor2',now(),'["datapoint1":"value1","count":"7"]');
    
    按区域id和传感器查询:

    >select area_id,sensor,dateof(event_time),data from data where area_id=1 and sensor='sensor1';
    
     area_id | sensor  | dateof(event_time)       | data
    ---------+---------+--------------------------+-------------------------
           1 | sensor1 | 2013-11-06 17:37:02+0000 | ["datapoint1":"value1"]
    
    (1 rows)
    
    按区域id查询:

    > select area_id,sensor,dateof(event_time),data from data where area_id=1;
    
     area_id | sensor  | dateof(event_time)       | data
    ---------+---------+--------------------------+-------------------------------------
           1 | sensor1 | 2013-11-06 17:37:02+0000 |             ["datapoint1":"value1"]
           1 | sensor2 | 2013-11-06 17:40:49+0000 | ["datapoint1":"value1","count":"7"]
    
    (2 rows)
    

    (使用
    [cqlsh 4.0.1 | Cassandra 2.0.1 | CQL spec 3.1.1 | Thrift protocol 19.37.0]进行测试)

    我猜这类似于使用映射字段,但允许客户端处理(反)序列化,它可能会做得稍微好一点。可能值得一提的是,我希望JSON数据点比任何查询中实际使用的数据点都多(我将更新问题以反映这一点)。这意味着在可能只需要1或2个字段(尽管不保证)的情况下,通过“在线”来反序列化完整的有效负载。如果一天有100万条记录,那就是很多数据。这可能是其他人正在做的——我不确定。我认为计数应该保持在一个单独的表中。如果你正在寻找最佳速度,你应该考虑每一个查询类型的一个表。我已经详细阐述了我的答案-你的点在满负荷是一个重要的考虑因素。您将在负载大小和灵活性之间进行权衡。如果您对传感器数据了解得更多,您可以为每种传感器类型编写自定义表,并对其进行更复杂的查询。不幸的是,在事先不知道结构的情况下,你将无法做到这一点。我想我将在这里使用混合解决方案。我将在与您描述的模式类似的模式中序列化完整事件。对于任何复杂的操作来说,将其取出并反序列化将是唯一的方法。我还将通过值对再次存储数据(嘿,存储是便宜的对),大致如下:创建表sensor_composite(area_id int,sensor varchar,date ascii,property varchar,event_time timeuuid,value varchar主键((area_id,sensor,date),property,event_time))。。。其目的是可以用于快速属性读取。是的,我认为这是有意义的-非规范化是新的规范化;-)
    > select area_id,sensor,dateof(event_time),data from data where area_id=1;
    
     area_id | sensor  | dateof(event_time)       | data
    ---------+---------+--------------------------+-------------------------------------
           1 | sensor1 | 2013-11-06 17:37:02+0000 |             ["datapoint1":"value1"]
           1 | sensor2 | 2013-11-06 17:40:49+0000 | ["datapoint1":"value1","count":"7"]
    
    (2 rows)