Cassandra的最新版本是2.1。在Cassandra旧的数据模型中,非常强调column-family。column-family类似于关系型数据库中的表。但是在新的版本中,Cassandra的数据模型发生了很大的改变:table取代了column-family;同时新开发了CQL。和SQL的作用类似,CQL用于操作Cassandra中的数据。CQL的语法看起来非常接近SQL。从这两点,加上Hadoop生态系统中产品的一些变化,可以看出,在hadoop和nosql领域,近期类SQL化可以说是众多产品间竞争的焦点。
要想快速了解Cassandra的数据模型,从CQL开始是个不错的选择,让用户对Cassandra的使用有个直观的认识。
(这里需要强调一下,由于Cassandra在新版本中的重大变化,导致一些学习资料已经过期。例如《Cassandra, the definition guide》。最好的学习资料可能是
http://www.datastax.com/documentation/cql/3.1/cql/cql_intro_c.html)
这里还有一个不错的视频教学:
https://academy.datastax.com/courses/introducing-cassandra-query-language-cql
Cassandra数据模型中的核心关键字是keyspace, table, collection。下面我们将逐一讲解,需要注意的是CQL需要在cqlsh(cql shell)中运行,因此默认读者已经安装了cqlsh并配置好了Cassandra。如果没有安装所以不能实际操作,那么通过本文得到一个大概的印象也是不错的选择。
keyspace是table的容器,和关系型数据库中的数据库类似。创建一个keyspace:
cqlsh> CREATE KEYSPACE demodb
WITH REPLICATION = { 'class' : 'NetworkTopologyStrategy', 'dc1' : 3 };
replication中配置的属性涉及Cassandra的架构,这里我们不讨论。
然后我们使用use链接到该keyspace,和关系型数据库完全一样。
USE demodb;
之后我们就可以创建table了。
CREATE TABLE emp (
empID int,
deptID int,
first_name varchar,
last_name varchar,
PRIMARY KEY (empID, deptID));
创建表的同时,我们创建了一个主键。主键是一行数据的唯一标示符。注意这里是一个复合主键,由empID和depID组成。在Cassandra中复合主键和关系型数据库的主键有很大不同。Cassandra认为复合主键中的第一个column是partition ID,也就是说Cassandra会根据这个column的值来分区。不同的区,即partition可能会被存储在不同的node上。这也是为什么Cassandra's data model is a partitioned row store。也就是说一个表中的数据会根据分区的不同被存储在不同的node去,但同一行数据不会被分割到不同的node上。复合主键中的其他column会被用来给数据排序,或者索引,上例中是depID。
那么如果一个table中的partitionID的重合度太高会如何呢?比如上例中,如果表中绝大部分数据的empID都是一样的,意味着大部分数据只能被存储在一个node上(一个分区内),导致单个节点不足以存储这些数据,或者单个节点的负载太重。此时需要使用composite partition key来进一步划分数据,由此将数据分散到更多的node上去。
之后我们可以简单的插入一些数据:
INSERT INTO emp (empID, deptID, first_name, last_name)
VALUES (104, 15, 'jane', 'smith');
查询keyspace信息:
SELECT * FROM system.schema_keyspaces;
另外两个常用系统表是system.schema_columnfamilies and system.schema_columns.
我们可以在table中使用collection用于一些特殊需要,首先来看一个例子:
CREATE TABLE users (
user_id text PRIMARY KEY,
first_name text,
last_name text,
emails set<text>
);
INSERT INTO users (user_id, first_name, last_name, emails)
VALUES('frodo', 'Frodo', 'Baggins', {'f@baggins.com', 'baggins@gmail.com'});
我们看到,在用户表中的email列比较特殊,它可以存储多个值。这意味着一个用户可能有多个email地址。该例中email就是一个collection,collection中的每个值,例如'f@baggins.com',就是一个item。Collection有三种:set, list和map。这里不详述了。
Use collections when you want to store or denormalize a small amount of data.If the data you need to store has unbounded growth potential, such as all the messages sent by a user or events registered by a sensor, do not use collections.
最后一个需要注意的地方,也是和关系型数据库很大不同的地方:primary key。只有primary key中涉及的column,才可以作为查询条件。如果where条件中使用了没有被索引的字段,Cassandra会报错并不执行该语句。因此在Cassandra中,将所有字段都包含在primary key中是很常见的做法。
更多的内容参考文章开始的链接。