Cassandra是一个开源的分布式数据库,结合了Dynamo的Key/Value与Bigtable的面向列的特点。
Cassandra的特点如下:
1.灵活的schema:不需要象数据库一样预先设计schema,增加或者删除字段非常方便(on the fly)。
2.支持range查询:可以对Key进行范围查询。
3.高可用,可扩展:单点故障不影响集群服务,可线性扩展。
我们可以将Cassandra的数据模型想象成一个四维或者五维的Hash。
Column
Column是Cassandra中最小的数据单元。它是一个3元的数据类型,包含:name,value和timestamp。
将一个Column用JSON的形式表现出来如下:
- {
// 这是一个column
- name:
"逖靖寒的世界"
,
- value:
"[email protected]"
,
- timestamp: 123456789
- }
为了简单起见,我们可以忽略timestamp。就把column想象成一个name/value即可。
注意,这里提到的name和value都是byte[]类型的,长度不限。
SuperColumn
我们可以将SuperColumn想象成Column的数组,它包含一个name,以及一系列相应的Column。
将一个SuperColumn用JSON的形式表现如下:
- {
- // 这是一个SuperColumn
- name:
"逖靖寒的世界"
,
// 包含一系列的Columns
- value: {
- street: {name:
"street"
, value:
"1234 x street"
, timestamp: 123456789},
- city: {name:
"city"
, value:
"san francisco"
, timestamp: 123456789},
- zip: {name:
"zip"
, value:
"94107"
, timestamp: 123456789},
- }
- }
Columns和SuperColumns都是name与value的组合。最大的不同在于Column的value是一个“string”,而 SuperColumn的value是Columns的Map。
还有一点需要注意的是:SuperColumn’本身是不包含timestamp的。
ColumnFamily
ColumnFamily是一个包含了许多Row的结构,你可以将它想象成RDBMS中的Table。
每一个Row都包含有client提供的Key以及和该Key关联的一系列Column。
我们可以看看结构:
- UserProfile = {
- // 这是一个ColumnFamily
- phatduckk: {
- // 这是对应ColumnFamily的key
- // 这是Key下对应的Column
- username:
"gpcuster"
,
- email:
"[email protected]"
,
- phone:
"6666"
- },
// 第一个row结束
- ieure: {
// 这是ColumnFamily的另一个key
- //这是另一个Key对应的column
- username:
"pengguo"
,
- email:
"[email protected]"
,
- phone:
"888"
- age:
"66"
- },
- }
ColumnFamily的类型可以为Standard,也可以是Super类型。
我们刚刚看到的那个例子是一个Standard类型的ColumnFamily。Standard类型的ColumnFamily包含了一系列的 Columns(不是SuperColumn)。
Super类型的ColumnFamily包含了一系列的SuperColumn,但是并不能像SuperColumn那样包含一系列 Standard ColumnFamily。
这是一个简单的例子:
- AddressBook = {
// 这是一个Super类型的ColumnFamily
- phatduckk: {
// key
- friend1: {street:
"8th street"
, zip:
"90210"
, city:
"Beverley Hills"
, state:
"CA"
},
- John: {street:
"Howard street"
, zip:
"94404"
, city:
"FC"
, state:
"CA"
},
- Kim: {street:
"X street"
, zip:
"87876"
, city:
"Balls"
, state:
"VA"
},
- Tod: {street:
"Jerry street"
, zip:
"54556"
, city:
"Cartoon"
, state:
"CO"
},
- Bob: {street:
"Q Blvd"
, zip:
"24252"
, city:
"Nowhere"
, state:
"MN"
},
- ...
- },
// row结束
- ieure: {
// key
- joey: {street:
"A ave"
, zip:
"55485"
, city:
"Hell"
, state:
"NV"
},
- William: {street:
"Armpit Dr"
, zip:
"93301"
, city:
"Bakersfield"
, state:
"CA"
},
- },
- }
Keyspace
Keyspace是我们的数据最外层,你所有的ColumnFamily都属于某一个Keyspace。一般来说,我们的一个程序应用只会有一个 Keyspace。
简单测试
我们将Cassandra运行起来以后,启动命令行,执行如下操作:
- cassandra
>
set Keyspace1.Standard1['jsmith']['first'] = 'John'
- Value inserted.
- cassandra
>
set Keyspace1.Standard1['jsmith']['last'] = 'Smith'
- Value inserted.
- cassandra
>
set Keyspace1.Standard1['jsmith']['age'] = '42'
- Value inserted.
这个时候,Cassandra中就已经有3条数据了。
其中插入数据的各个字段含义如下:
接下来,我们执行查询操作:
- cassandra
>
get Keyspace1.Standard1['jsmith']
- (
column
=
age
,
value
=
42
;
timestamp
=
1249930062801
)
- (
column
=
first
,
value
=
John
;
timestamp
=
1249930053103
)
- (
column
=
last
,
value
=
Smith
;
timestamp
=
1249930058345
)
- Returned 3 rows.
这样,我们就可以将之前插入的数据查询出来了。
//最后可以做一点说明,cassandra中,可以把Keyspace1看成是一个单独的数据库,standard1看成是一些表的集合,key看成是某个单独表的名称,每个单独表都是由一组column组成的,每个column就是一个<name,value>向量。
排序
有一点需要明确,我们使用Cassandra的时候,数据在写入的时候就已经排好顺序了。
在某一个Key内的所有Column都是按照它的Name来排序的。我们可以在storage-conf.xml文件中指定排序的类型。
目前Cassandra提供的排序类型有:BytesType, UTF8Type,LexicalUUIDType, TimeUUIDType, AsciiType,和LongType。
现在假设你的原始数据如下:
- {name: 123, value: "hello there"},
- {name: 832416, value: "kjjkbcjkcbbd"},
- {name: 3, value: "101010101010"},
- {name: 976, value: "kjjkbcjkcbbd"}
当我们storage-conf.xml文件中指定排序的类型为LongType时:
<!--
ColumnFamily 在 storage-conf.xml 中定义
-->
<ColumnFamily CompareWith="LongType" Name="CF_NAME_HERE"/>
排序后的数据就是这样的:
- {name: 3, value: "101010101010"},
- {name: 123, value: "hello there"},
- {name: 976, value: "kjjkbcjkcbbd"},
- {name: 832416, value: "kjjkbcjkcbbd"}
如果我们指定排序的类型为UTF8Type
- <!--
- ColumnFamily 在 storage-conf.xml 中定义
- -->
- <
ColumnFamily
CompareWith
=
"UTF8Type"
Name
=
"CF_NAME_HERE"
/>
排序后的数据就是这样的:
- {name: 123, value: "hello there"},
- {name: 3, value: "101010101010"},
- {name: 832416, value: "kjjkbcjkcbbd"},
- {name: 976, value: "kjjkbcjkcbbd"}
大家可以看到,指定的排序类型不一样,排序的结果也是完全不同的。
对于SuperColumn,我们有一个额外的排序维度,所以我们可以指定CompareSubcolumnsWith来进行另一个维度的排序类 型。
假设我们的原始数据如下:
- {
// first SuperColumn from a Row
- name:
"workAddress"
,
// and the columns within it
- value: {
- street: {name:
"street"
, value:
"1234 x street"
},
- city: {name:
"city"
, value:
"san francisco"
},
- zip: {name:
"zip"
, value:
"94107"
}
- }
- },
- {
// another SuperColumn from same Row
- name:
"homeAddress"
,
// and the columns within it
- value: {
- street: {name:
"street"
, value:
"1234 x street"
},
- city: {name:
"city"
, value:
"san francisco"
},
- zip: {name:
"zip"
, value:
"94107"
}
- }
- }
然后我们定义CompareSubcolumnsWith和CompareWith的排序类型都是UTF8Type,那么排序后的结果为:
- {
// this one's first b/c when treated as UTF8 strings
- {
// another SuperColumn from same Row
// This Row comes first b/c "homeAddress" is before "workAddress"
- name:
"homeAddress"
,
// the columns within this SC are also sorted by their names too
- value: {
// see, these are sorted by Column name too
- city: {name:
"city"
, value:
"san francisco"
},
- street: {name:
"street"
, value:
"1234 x street"
},
- zip: {name:
"zip"
, value:
"94107"
}
- }
- },
- name:
"workAddress"
,
- value: {
// the columns within this SC are also sorted by their names too
- city: {name:
"city"
, value:
"san francisco"
},
- street: {name:
"street"
, value:
"1234 x street"
},
- zip: {name:
"zip"
, value:
"94107"
}
- }
- }
再额外提一句,Cassandra的排序功能是允许我们自己实现的,只要你继承 org.apache.cassandra.db.marshal.IType就可以了。
原文标题:大话Cassandra数据模型
链接: http://www.cnblogs.com/gpcuster/archive/2010/03/12/1684072.html