和其他语言一样,CQL也支持一系列灵活的数据类型,包括基本的数据类型,集合类型以及用户自定义数据类(User-Defined Types, UDTs)。本文将介绍CQL支持的数据类型。
数字数据类型(Numeric Data Types)
CQL支持的数字数据类型包括整型和浮点型,这些数据类型和Java的标准数据类型类似。包括以下几种:
int:32位有符号整型,和Java中的int类似;
bigint:64位长整型,和Java中的long类似;
smallint:16位有符号整型,和Java中的short类似,Apache Cassandra 2.2开始引入;
tinyint:8位有符号整型,和Java中的tinyint类似,Apache Cassandra 2.2开始引入;
varint:可变精度有符号整数,和Java中的java.math.BigInteger类似;
float:32位IEEE-754浮点型,和Java中的float类似;
double:64位IEEE-754浮点型,和Java中的double类似;
decimal:可变精度的decimal,和Java中的java.math.BigDecimal类似。
文本数据类型(Textual Data Types)
CQL中提供了两种数据类型用于存放文本类型:
text, varchar:UTF-8编码的字符串,这个在CQL中使用的比较普遍;
ascii:ASCII字符串。
时间和标识符数据类型(Time and Identity Data Types)
timestamp:时间可以使用64位有符号的整数表示,但是一般为了可读性,我们会选择支持ISO 8601标准的时间戳表示。建议在使用时间戳的时候都指定时区,而不是依赖系统的时区。
date, time:在Apache Cassandra 2.1版本之前只支持timestamp类型,里面包含了日期和时间;从Cassandra 2.2版本开始引入了date和time时间类型,分别表示日期和时间。和timestamp一样,这个也是支持ISO 8601标准的。
uuid:通用唯一识别码(universally unique identifier,UUID)是128位数据类型,其实现包含了很多种类型,其中最有名的为Type 1和Type 4。CQL中的uuid实现是Type 4 UUID,其实现完全是基于随机数的。UUID的数据类似于ab7c46ac-c194-4c71-bb03-0f64986f3daa,uuid类型通常用作代理键,可以单独使用,也可以与其他值组合使用。由于UUID的长度有限,因此并不能绝对保证它们是唯一的。我们可以在CQL中使用uuid() 获取Type 4 UUID。
timeuuid:这个是Type 1 UUID,它的实现基于计算机的MAC地址,系统时间和用于防止重复的序列号。CQL中提供了now(), dateOf()以及unixTimestampOf()等函数来操作timeuuid数据类型。由于这些简便的函数,timeuuid的使用频率比uuid数据类型多。
集合数据类型
这种数据类型可以存储集合数据类型,set里面的元素存储是无序的,但是cql返回的数据是有序的。set里面可以存储前面介绍的数据类型,也可以是用户自定义数据类型,甚至是其他集合类型。
下述案例以存储email信息为例,来说明set的使用:
cqlsh:test_keyspace> CREATE TABLE test_user (first_name text , last_name text,emails set<text>, PRIMARY KEY (first_name)) ;
cqlsh:test_keyspace> INSERT INTO test_user (first_name, last_name,emails) VALUES ('Wu', 'Shi',{'iteblog@iteblog.com'});
cqlsh:test_keyspace> SELECT * FROM test_user WHERE first_name = 'Wu';
first_name | emails | last_name
------------+-------------------------+-----------
Wu | {'iteblog@iteblog.com'} | Shi
(1 rows)
上述命令表示为first_name为Wu的数据添加了email信息。如果您还需要往里面加一些email信息,可以使用下述语法:
cqlsh:test_keyspace> UPDATE test_user SET emails = emails + {'cassandra@iteblog.com' } WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT * FROM test_user WHERE first_name = 'Wu';
first_name | emails | last_name
------------+--------------------------------------------------+-----------
Wu | {'cassandra@iteblog.com', 'iteblog@iteblog.com'} | Shi
(1 rows)
first_name为Wu的记录已经添加了两条email信息了。如果您需要删除email,可以使用下述语法:
cqlsh:test_keyspace> UPDATE test_user SET emails = emails - {'cassandra@iteblog.com'} WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT * FROM test_user WHERE first_name = 'Wu';
first_name | emails | last_name
------------+-------------------------+-----------
Wu | {'iteblog@iteblog.com'} | Shi
(1 rows)
cqlsh:test_keyspace> UPDATE test_user SET emails ={} WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT * FROM test_user WHERE first_name = 'Wu';
first_name | emails | last_name
------------+--------+-----------
Wu | null | Shi
(1 rows)
上述命令表示使用SET emails = emails - {'cassandra@iteblog.com'}
从用户email列表里面删除email,使用SET emails ={}
清空用户的email。
list
list包含了有序的列表数据,默认情况下,数据是按照插入顺序保存的。以test_user表为例,如果需要往该表中添加电话等信息,示例如下:
cqlsh:test_keyspace> ALTER TABLE test_user ADD phone list<text>;
cqlsh:test_keyspace> UPDATE test_user SET phone = ['1311234****' ] WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT * FROM test_user WHERE first_name = 'Wu';
first_name | emails | last_name | phone
------------+--------+-----------+-----------------
Wu | null | Shi | ['1311234****']
(1 rows)
上述命令表示给first_name为Wu的记录添加了电话信息。如果需要再添加电话信息,其操作和set添加信息类似,例如:
cqlsh:test_keyspace> UPDATE test_user SET phone = phone + ['1551111****' ] WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT * FROM test_user WHERE first_name = 'Wu';
first_name | emails | last_name | phone
------------+--------+-----------+--------------------------------
Wu | null | Shi | ['1311234****', '1551111****']
(1 rows)
可以看出,新加入的电话号码被放在list的后面了。如果使用下述语句,则可以往电话号码的前面添加信息:
cqlsh:test_keyspace> UPDATE test_user SET phone = ['1334444****' ] + phone WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT * FROM test_user WHERE first_name = 'Wu';
first_name | emails | last_name | phone
------------+--------+-----------+-----------------------------------------------
Wu | null | Shi | ['1334444****', '1311234****', '1551111****']
(1 rows)
您可以使用下标从list数据类型中修改数据:
cqlsh:test_keyspace> UPDATE test_user SET phone[1] = '1888888****' WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT * FROM test_user WHERE first_name = 'Wu';
first_name | emails | last_name | phone
------------+--------+-----------+-----------------------------------------------
Wu | null | Shi | ['1334444****', '1888888****', '1551111****']
(1 rows)
下标为1的元素被修改了。也可以使用下标删除数据:
cqlsh:test_keyspace> DELETE phone[2] from test_user WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT * FROM test_user WHERE first_name = 'Wu';
first_name | emails | last_name | phone
------------+--------+-----------+--------------------------------
Wu | null | Shi | ['1334444****', '1888888****']
(1 rows)
当然,删除元素也可以使用SET phone_numbers = phone_numbers - [ '1334444****' ]
。
map
map数据类型包含了key/value键值对。key和value可以是任何类型,除了counter类型。使用如下:
cqlsh:test_keyspace> ALTER TABLE test_user ADD login_sessions map<timeuuid, int>;
cqlsh:test_keyspace> UPDATE test_user SET login_sessions = {now(): 13, now(): 18} WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT first_name, login_sessions FROM test_user WHERE first_name = 'Wu';
first_name | login_sessions
------------+--------------------------------------------------------------------------------------
Wu | {1cc61ff0-5f8b-11e9-ac3a-5336cd8118f6: 13, 1cc61ff1-5f8b-11e9-ac3a-5336cd8118f6: 18}
(1 rows)
其他简单数据类型
boolean:取值只能为true/false,在cql中输入的这两个值无论大小如何写法,其输出都是True/False;
blob:二进制大对象(binary large object)是任意字节数组的术语简称。这个类型在存储媒体或者其他二进制数据类型时很有用,Cassandra并不会检查其中存储的二进制数据是否有效。Cassandra中二进制大对象是以十六进制存储的,如果想将任意的文本数据类型使用blob存储,可以使用textAsBlob()函数实现。
inet:这个数据类型可以表示IPv4或IPv6网络地址。cqlsh接受用于定义IPv4地址的任何合法格式,包括包含十进制,八进制或十六进制值的点或非点式表示。CQL统一输出为192.168.XX.XX这种格式的IP地址。
counter:计数器数据类型是64位有符号整数,其值不能直接设置,而只能递增或递减。计数器类型的使用有一些特殊限制,它不能用作主键的一部分;如果使用计数器,则除primary key列之外的所有列都必须是计数器。
用户自定义数据类型(User-Defined Types)
如果Cassandra中内置的数据类型无法满足您的需求,您还可以使用自定义数据类型。例如,需要使用一个字段存储用户的地址信息,需要获取地址的邮编、街道等信息。如果使用text来存储是不能满足我们的需求的,此时您可以自定义数据类型,示例如下:
cqlsh:test_keyspace> CREATE TYPE address (
... street text,
... city text,
... state text,
... zip_code int);
上述语句定义了address数据类型。需要注意的是,Cassandra中数据类型的定义是keyspace范围的,表明 address数据类型只能在test_keyspace里面使用。如果您使用DESCRIBE KEYSPACE test_keyspace
,可以看到address数据类型属于test_keyspace的一部分。现在定义好了address数据类型,使用示例如下:
cqlsh:test_keyspace> ALTER TABLE test_user ADD addresses map<text, frozen<address>>;
cqlsh:test_keyspace> UPDATE test_user SET addresses = addresses + {'home': { street: 'shangdi 9', city: 'Beijing', state: 'Beijing', zip_code: 100080} } WHERE first_name = 'Wu';
cqlsh:test_keyspace> SELECT first_name, addresses FROM test_user WHERE first_name = 'Wu';
first_name | addresses
------------+--------------------------------------------------------------------------------------
Wu | {'home': {street: 'shangdi 9', city: 'Beijing', state: 'Beijing', zip_code: 100080}}
(1 rows)