Cassandra存储time series类型数据时的内部数据结构?

因为我一直想用Cassandra来存储我们的数字电表中的数据,按照之前的文章(getting-started-time-series-data-modeling)的介绍,Cassandra真的和适合用于存储time series类型的数据,那么我就想要弄清楚,对于下面这张表

CREATE TABLE temperature (
weatherstation_id text,
event_time timestamp,
temperature text,
PRIMARY KEY (weatherstation_id,event_time));

在插入了下面这些数据之后,他内部究竟是怎么存储的?

INSERT INTO temperature(weatherstation_id,event_time,temperature) VALUES (‘1234ABCD‘,‘2013-04-03 07:01:00‘,‘72F‘);
INSERT INTO temperature(weatherstation_id,event_time,temperature) VALUES (‘1234ABCD‘,‘2013-04-03 07:02:00‘,‘73F‘);
INSERT INTO temperature(weatherstation_id,event_time,temperature) VALUES (‘1234ABCD‘,‘2013-04-03 07:03:00‘,‘73F‘);
INSERT INTO temperature(weatherstation_id,event_time,temperature) VALUES (‘1234ABCD‘,‘2013-04-03 07:04:00‘,‘74F‘);

如果按照传统的关系数据库的逻辑,那么在数据库中就存在如下行:

weatherstation_id, event_time, temprature
‘1234ABCD‘,‘2013-04-03 07:01:00‘,‘72F‘
‘1234ABCD‘,‘2013-04-03 07:02:00‘,‘73F‘
‘1234ABCD‘,‘2013-04-03 07:03:00‘,‘73F‘
‘1234ABCD‘,‘2013-04-03 07:04:00‘,‘74F‘

假如在数据库中真的也是这么存储的,那就和关系数据库一样了,那我继续使用Postgresql就可以了,还来瞎折腾干什么。

但是我真心希望文章getting-started-time-series-data-modeling所介绍的例子是正确的,我希望数据确实是按照下面这种方式来存储的,也就是同一个温度气象站的所有温度数据全都存储在同一行,row key就是weatherStationId。那么我就想要弄清楚上面这个temperature 表明明只定义了weatherstation_id, event_time, temperature三列,并且weatherstation_id, event_time作为primary key,为什么到存储的时候,event_time的值就变为列名了?这里究竟是一种什么样的转换规则。

然后,还有在很多地方出现的这张图中,这个 row key1究竟是哪个字段,他和primary key之间有什么关系?

在查阅了一些相关的资料,特别是看了understanding-how-cql3-maps-to-cassandras-internal-data-structure这篇文章之后,我感觉这次我真的懂了,下面来详细说说我的理解。

一、几个基本概念

1) Primary Key;

2) Partition Key;

3) Compound Primary key;

4) Composit Partition key;

5) Clustering Key;

6) Row Key;

首先给个公式,

Primary Key = Partition Key + [Clustering Key]

Row Key=PartitionKey

这里的意思就是,Primary Key是有Partition Key 和 Clustering key组成的,其中 Clustering key是可选的。

Primary key, Partition key, clustering key都可以由多个字段组成,其中Partition key如果要由多个字段组成,要用小括号括起来。

Row Key就是PartitionKey,也就是一行的唯一标识。

下面来给几个例子。

例子1:

CREATE TABLE users (
  user_name varchar PRIMARY KEY,
  password varchar,
  gender varchar,
  session_token varchar,
  state varchar,
  birth_year bigint
);   
 

在这例子中:

Primary key = user_name

Partition key = user_name

Clustering key = null

RowKey=user_name;

例子2:

CREATE TABLE emp (
  empID int,
  deptID int,
  first_name varchar,
  last_name varchar,
  PRIMARY KEY (empID, deptID)
);

Primary Key=empId, deptId;

Partition key=empId

Clustering Key=deptId

rowKey=empId

此时的Primary key 就叫做 Compound Primary Key

例子3:

CREATE TABLE Cats (
  block_id uuid,
  breed text,
  color text,
  short_hair boolean,
  PRIMARY KEY ((block_id, breed), color, short_hair)
);

Primary Key = (block_id, breed), color, short_hair

PartitionKey=block_id, breed

ClusteringKey=color, short_hair

rowKey=blockId, breed

此时的Primary key 就叫做 Compound Primary Key

此时的PartitionKey就叫做Composit Partition Key

二、Cassandra的表schema与内部存储结构的转换关系

下面主要借助文章understanding-how-cql3-maps-to-cassandras-internal-data-structure中的几个例子来说明这种转换关系。

(1)例子1:

CreateTable employees(
name text PRIMARY KEY,
age int,
role text
);

加上往该表中插入如下几条数据

此时,他在Cassandra内部实际上是这么存储的

可以看到,PartitionKey对应的name的值被作为row key

然后每一行有2列,每一列都包含列名和值,这个看起来和关系数据库区别不大,他相对于关系数据库其实存在数据冗余,就是每一行都单独存储了列名,而不是像关系数据库一样,有一个统一的列名。

(2) 例子2

CreateTable employees(
company text,
name text,
age int,
role text,
PRIMARY KEY(company, name)
);

往表内插入了如下数据

此时,在Cassandra内部实际上是这么存的

简单说明下

company 是row key,上面的数据中company只有OSC和RKG两个值,那就是有两个row key,所以在数据库中就有2行。

name是clustering key, 此时就相当于是clusteringkey的值和primary key的每一列一起组成一个组合列名,比如OSC,eric行就组成了eric:age, eric:role两列。而OSC, john行就组成了john:age, john:role两列。

(3)例子3

CreateTable example(
A text,
B text,
C text,
D text,
E text,
F text,
PrimaryKey((A,B),C,D)
)

往表中插入如下数据

此时在Cassandra内部是这么存的,这次不一样的就是,

PartitionKey是CompositPartitionKey,这就导致rowkey是一个组合键,比如下面的a:b, a:n, s:t

并且ClusteringKey也是由多列组成的,这样在和非Primary key的列拼接列名的时候,就要加上两个字段,比如下面的c:d:E, c:d:F

三、开篇的那个time series类型数据例子的存储结构

套用上一节的模式,开篇那个表在插入如下数据之后

weatherstation_id, event_time, temprature
‘1234ABCD‘,‘2013-04-03 07:01:00‘,‘72F‘
‘1234ABCD‘,‘2013-04-03 07:02:00‘,‘73F‘
‘1234ABCD‘,‘2013-04-03 07:03:00‘,‘73F‘
‘1234ABCD‘,‘2013-04-03 07:04:00‘,‘74F‘

在Cassandra的存储结构是这样的。

所有在同一个row key中的数据,在硬盘中就是连续存储的。

参考资料:

1)这个问题和我的疑问类似,http://stackoverflow.com/questions/23096572/cassandra-long-row-with-different-data-types

2)我也有这个疑问,http://stackoverflow.com/questions/30872897/row-key-in-cassandra-table

3)理解Cassandra的关键概念和数据模型,https://my.oschina.net/silentriver/blog/182678

4) understanding-how-cql3-maps-to-cassandras-internal-data-structure, https://www.slideshare.net/DataStax/understanding-how-cql3-maps-to-cassandras-internal-data-structure

时间: 2024-11-03 21:36:48

Cassandra存储time series类型数据时的内部数据结构?的相关文章

复制一张表的数据到另一张表,jq.grid里面有时间类型数据时展示不了数据

1.复制一张表的数据到另一张表 insert into jct_sys_lock_tbl_new  (BGN_DT, END_DT, TYPE, DESCR, flag, format, range, count)  select BGN_DT, END_DT, TYPE, DESCR, flag, format, range, count    from jct_sys_lock_tbl 也可以: insert into jct_sys_lock_tbl_new  select *    fr

解决用Jquery实现 Checkbox 显示后台Bool类型数据时出现的Bug

最近在进行一个EasyUI框架的搭建过过程中,需要把数据库中的Bool类型用Checkbox来显示,开始写的是 $("chkIsMech").checked=Json.IsMenu, 后来又试了$("#chkIsMenu").attr("checked", json.IsMenu);同样不行.又百度了好多,终于有篇文章出现了同样的问题,欣喜之余赶紧粘过来: document.getElementById("chkIsMenu"

向 mysql 数据库中写入datetime 类型数据时 出现全是0的错误解决办法

Date date = new Date();//获得系统时间. SimpleDateFormat sdf = new SimpleDateFormat( " yyyy-MM-dd HH:mm:ss " ); String nowTime = sdf.format(date); Date time = sdf.parse( nowTime );

关于.net 保存 decimal类型数据到SQLServer2012数据库时自动取整的问题

公司同事问我有没有遇到过decimal类型数据入库时,会自动取整的问题(比如12.3入库后值是12,12.8入库后值是13,入库后自动四舍五入自动取整): 之前就遇到过从数据去decimal类型数据时,会自动取整的问题:我想应该是同样的问题吧,叫同事设置SQLParameter参数时,设置Scale=2,Precision=18:类似代码如下: var param1 = new SqlParameter("@Money",System.Data.SqlDbType.Decimal);

.NET向WebService传值为decimal、double、int、DateTime等非string类型属性时,服务器端接收不到数据的问题

最近在做CRM项目时,使用C#调用SAP PI发布的WebService服务时遇到的问题: 向WebService传值为decimal.double.int.DateTime等非string类型数据时,服务器端接收不到数据.查询了很多资料,终于解决了问题,总结如下. 问题现象: 用C#.NET调用PI开发的WebService时,在客户端将封装的带有decimal属性的对象传到服务器端时,服务器端可以得到string类型的属性值,却不能得到int.double.decimal类型和DateTim

计算float类型数据

1 #include<iostream> 2 3 using namespace std; 4 5 int main() 6 { 7 float k,p; 8 9 k = 1.0/172.0; 10 p = 1/172; 11 12 cout<<"k = "<<k<<endl; 13 cout<<"p = "<<p<<endl; 14 15 } 计算float类型数据时,计算式里的数

Hibernate操作Clob类型数据

在POJO中字符串大对象可以声明成一个java.lang.String或java.sql.Clob类型. 当程序从数据库中加载Clob类型数据时,仅仅加载了一个Clob类型的数据的逻辑指针.我们需要通过使用Clob.getCaracterStream()方法得到Clob类型的数据输入流之后才能获取大对象数据. 看下面具体代码 package dao; import java.io.BufferedReader; import java.io.IOException; import java.io

Hibernate操作Clob类型数据是怎样弄的

在POJO中字符串大对象可以声明成一个java.lang.String或java.sql.Clob类型. 当程序从数据库中加载Clob类型数据时,仅仅加载了一个Clob类型的数据的逻辑指针.我们需要通过使用Clob.getCaracterStream()方法得到Clob类型的数据输入流之后才能获取大对象数据. 看下面具体代码 package dao; import java.io.BufferedReader; import java.io.IOException; import java.io

解决使用DbContext保存Decimal数据时总是保留小数位2位问题

通过System.Data.Entity.DbContext保留Decimal类型数据时,默认只保留小数位2位.要解决该问题,可以通过在OnModelCreating事件中添加相应代码即可,具体参考如下代码中将shop.Longitude设置为小数位20位: public class UserDbContext : System.Data.Entity.DbContext { public UserDbContext() : base("MyContext") { this.Confi