CQL(Cassandra Query Language)数据类型,cqlcassandra
CQL是一种类型化语言,支持丰富的数据类型集,包括本地类型(native_types),集合类型(collection_type),用户定义类型(user_defined_type),元组类型(tuple_type)和自定义类型(custon_type):cql_type ::=native_type|collection_type|user_defined_type|tuple_type|custom_type
1.本地类型
CQL支持的本地类型有:
native_type ::= ASCII
| BIGINT
| BLOB
| BOOLEAN
| COUNTER
| DATE
| DECIMAL
| DOUBLE
| FLOAT
| INET
| INT
| SMALLINT
| TEXT
| TIME
| TIMESTAMP
| TIMEUUID
| TINYINT
| UUID
| VARCHAR
| VARINT
下表提供了本地数据类型的其他信息,以及每种类型支持的常量类型:
| type | constants supported | description |
|---|---|---|
ascii |
string |
ASCII字符串 |
bigint |
integer |
64位有符号长 |
blob |
blob |
任意字节(无验证) |
boolean |
boolean |
true或false |
counter |
integer |
计数器列(64位有符号值) |
date |
integer,string |
日期(没有相应的时间值) |
decimal |
integer,float |
可变精度十进制 |
double |
integerfloat |
64位IEEE-754浮点 |
float |
integer,float |
32位IEEE-754浮点 |
inet |
string |
IP地址,IPv4(4字节长)或IPv6(16字节长)。 注意,没有inet常量,IP地址应该作为字符串输入 |
int |
integer |
32位有符号长 |
smallint |
integer |
16位有符号长 |
text |
string |
UTF8编码字符串 |
time |
integer,string |
一个具有纳秒精度的时间(没有相应的日期值) |
timestamp |
integer,string |
时间戳(日期和时间),精度为毫秒 |
timeuuid |
uuid |
版本1 UUID,通常用作“无冲突”时间戳 |
tinyint |
integer |
8位有符号长int |
uuid |
uuid |
UUID(任何版本) |
varchar |
string |
UTF8编码字符串 |
varint |
integer |
任意精度整数 |
2.计数器
计数器类型用于定义计数器列。 计数器列是其值为64位有符号整数且支持2个操作的列:递增和递减(请参见语法的UPDATE语句)。 注意,不能设置计数器的值:在第一次递增/递减之前不存在计数器,并且第一次递增/递减被假定为先前值为0。
计数器有一些重要的限制
- 不能够用于表中PRIMARY KEY的列部分
- 包含计数器的表只能包含计数器数。 换句话说,表中处PRIMARY KEY外所有列都有计数器类型,或者没有计数器类型
- 计数器不支持到期
- 支持删除计数器,但只能保证在您第一次删除计数器时工作。 换句话说,您不应该重新更新您已删除的计数器(如果您这样做,不能保证正确的行为)
- 计数器更新本质上不是同义的。一个重要的后果是,如果计数器更新意外失败(超时或失去与协调器节点的连接),客户端无法知道是否已应用更新。尤其是在重复更新操作可能导致过度计数
3.使用时间戳
时间戳类型的值被编码为64位有符号整数,表示标准基本时间(1970年1月1日00:00:00 GMT)以来的毫秒数。可以把时间戳的值作为整数或使用表示ISO 8601日期的字符串输入CQL使用。 例如,以下所有值都是2011年3月2日上午04:05:00 GMT的有效时间戳值:
1299038700000'2011-02-03 04:05+0000''2011-02-03 04:05:00+0000''2011-02-03 04:05:00.000+0000''2011-02-03T04:05+0000''2011-02-03T04:05:00+0000''2011-02-03T04:05:00.000+0000'
4.使用日期
日期类型的值被编码为表示距离1970年1月1日的天数的32位无符号整数,其范围为2 ^ 31。
对于时间戳,日期可以作为整数或使用日期字符串输入。 在后一种情况下,格式应为yyyy-mm-dd(例如“2011-02-03”)。
5.使用时间
对于时间戳,时间可以作为整数输入或使用表示时间的字符串输入。 在后一种情况下,格式应为hh:mm:ss [.fffffffff](其中亚秒精度是可选的,如果提供,可以小于纳秒)。 例如,以下是一段时间的有效输入:
'08:12:54''08:12:54.123''08:12:54.123456''08:12:54.123456789'
6.集合
collection_type ::= MAP '<'并且可以使用字面量集合作为它们的输入值:cql_type','cql_type'>' | SET '<'cql_type'>' | LIST '<'cql_type'>'
collection_literal ::=请注意,在字面量集合中不支持bind_marker和NULL。map_literal|set_literal|list_literalmap_literal ::= '{' [term':'term(','term:term)* ] '}' set_literal ::= '{' [term(','term)* ] '}' list_literal ::= '[' [term(','term)* ] ']'
6-1.值得注意的特点
集合用于存储/反规范化数量相对较少的数据。 它们对于诸如“给定用户的电话号码”,“应用于电子邮件的标签”等的事物工作良好。但是当存储的数据无限增长的时候(“由用户发送的所有消息”,“由传感器注册的事件
“...),那么集合是不合适的,并且应该使用特定的表(具有聚类列)。 具体来说,(非冻结)集合具有以下值得注意的特征和限制:
- 单个集合不在内部编制索引。 这意味着即使访问集合的单个元素,也必须被读取整个集合(并且读取一个元素不在内部被分页)。
- 虽然对集合和映射的插入操作从来不会在内部产生先读后写,但是对列表的某些操作会执行。此外,一些列表操作本质上不是幂等性的,使得它们在超时问题的情况下重试。因此建议在可能的情况下选择使用集合而不使用列表。
6-2.Maps
CREATE TABLE users ( id text PRIMARY KEY, name text, favs map<text, text> // A map of text keys, and text values ); INSERT INTO users (id, name, favs) VALUES ('jsmith', 'John Smith', { 'fruit' : 'Apple', 'band' : 'Beatles' }); // Replace the existing map entirely. UPDATE users SET favs = { 'fruit' : 'Banana' } WHERE id = 'jsmith';
此外,map支持
- 更新或插入一个或多个元素:
UPDATE users SET favs['author'] = 'Ed Poe' WHERE id = 'jsmith'; UPDATE users SET favs = favs + { 'movie' : 'Cassablanca', 'band' : 'ZZ Top' } WHERE id = 'jsmith';
- 删除一个或多个元素(如果元素不存在,则删除它是一个无操作,但不会抛出错误):
DELETE favs['author'] FROM users WHERE id = 'jsmith'; UPDATE users SET favs = favs - { 'movie', 'band'} WHERE id = 'jsmith';最后,需要说明的是对于插入和更新操作都允许TTL,但是在这两种情况下,TTL集合仅适用于新插入/更新的元素。换一种说法下面的语句将仅仅只是把TTL应用于{'color':'green'}记录,其余的map不受影响:
UPDATE users USING TTL 10 SET favs['color'] = 'green' WHERE id = 'jsmith';
6-3.Sets
CREATE TABLE images ( name text PRIMARY KEY, owner text, tags set<text> // A set of text values ); INSERT INTO images (name, owner, tags) VALUES ('cat.jpg', 'jsmith', { 'pet', 'cute' }); // Replace the existing set entirely UPDATE images SET tags = { 'kitten', 'cat', 'lol' } WHERE name = 'cat.jpg';
此外,set支持
- 添加一个或多个元素(因为这是一个set,插入已经存在的元素是一个无操作):
UPDATE images SET tags = tags + { 'gray', 'cuddly' } WHERE name = 'cat.jpg';
- 删除一个或多个元素(如果元素不存在,则删除它是一个无操作,但不会抛出错误):
UPDATE images SET tags = tags - { 'cat' } WHERE name = 'cat.jpg';最后,和map相同,TTL只适用于新插入的值。
6-4.Lists
列表是非唯一值的(排序)集合,其中元素按列表中的位置排序。您可以定义和插入一个list:
CREATE TABLE plays ( id text PRIMARY KEY, game text, players int, scores list<int> // A list of integers ) INSERT INTO plays (id, game, players, scores) VALUES ('123-afde', 'quake', 3, [17, 4, 2]); // Replace the existing list entirely UPDATE plays SET scores = [ 3, 9, 4] WHERE id = '123-afde';
此外,list支持
- 将新值附加或者前置到list中:
UPDATE plays SET players = 5, scores = scores + [ 14, 21 ] WHERE id = '123-afde';
UPDATE plays SET players = 6, scores = [ 3 ] + scores WHERE id = '123-afde';
- 设置列表中特定位置的值。这意味着该列表具有用于该位置的预先存在的元素,否则将抛出该列表太小的错误:
UPDATE plays SET scores[1] = 7 WHERE id = '123-afde';
- 删除元素在列表中的位置。这意味着列表具有用于该位置的预先存在的元素,否则将抛出该列表太小的错误。此外,当操作从列表中移除元素时,列表大小将减小1,移动在删除的元素之后的所有元素的位置:
DELETE scores[1] FROM plays WHERE id = '123-afde';
- 删除列表中所有出现的特定值(如果某个元素在列表中根本不出现,则会被忽略,并且不会抛出任何错误):
UPDATE plays SET scores = scores - [ 12, 21 ] WHERE id = '123-afde';警告:附加和前置操作本质上不是幂等的。 因此,如果操作超时,则重试操作是不安全并且它有可能导致附加/前置值两次。
警告:通过位置设置和移除元素并移除特定值会在内部产生先读后写。因此,它们将比常规的更新耗费更多的资源,运行得更慢。
最后,和map相同,TTL只适用于新插入的值。
7.用户自定义类型
user_defined_type ::=UDT有一个名称(用于该类型的声明列),并且是一组命名和类型的字段。字段名称可以是任何类型,包括集合或其他UDT。例如:udt_nameudt_name ::= [keyspace_name'.' ]identifier
CREATE TYPE phone ( country_code int, number text, ) CREATE TYPE address ( street text, city text, zip text, phones map<text, phone> ) CREATE TABLE user ( name text PRIMARY KEY, addresses map<text, frozen<address>> )注意:
- 尝试创建已存在的类型将导致错误,除非使用IF NOT EXISTS选项。 如果使用它,如果类型已经存在,语句将是一个无操作。
- 类型本质上绑定到创建它的键空间,并且只能在该键空间中使用。在创建时,如果类型名称前缀为键空间名称,则在该键空间中创建。否则,将在当前键空间中创建。
- 从Cassandra
4.0开始,UDT必须在大多数情况下被冻结,因此在上面的表定义中冻结了<address>。
7-1.创建UDT
create_type_statement ::= CREATE TYPE [ IF NOT EXISTS ]udt_name'('field_definition( ','field_definition)* ')' field_definition ::=identifiercql_type
7-2.UDT字面量
udt_literal ::= '{'换句话说,一个UDT字面量就像一个map字面量,但它的键是类型的字段的名称。例如,可以使用以下代码插入到上一节中的表定义中:identifier':'term( ','identifier':'term)* '}'
INSERT INTO user (name, addresses) VALUES ('z3 Pr3z1den7', { 'home' : { street: '1600 Pennsylvania Ave NW', city: 'Washington', zip: '20500', phones: { 'cell' : { country_code: 1, number: '202 456-1111' }, 'landline' : { country_code: 1, number: '...' } } }, 'work' : { street: '1600 Pennsylvania Ave NW', city: 'Washington', zip: '20500', phones: { 'fax' : { country_code: 1, number: '...' } } } })为了有效,UDT字面量应该只包括由类型定义的字段,它是一个字面量,但它可以省略一些字段(在这种情况下,这些字段将为null)。
7-3.更改UDT
alter_type_statement ::= ALTER TYPE您可以:udt_namealter_type_modificationalter_type_modification ::= ALTERidentifierTYPEcql_type| ADDfield_definition| RENAMEidentifierTOidentifier(identifierTOidentifier)*
- 修改特定字段的类型(ALTER TYPE address ALTER zip TYPE bigint)。 此类更改的限制与更改列的类型相同。
- 添加一个新字段到类型(ALTER
TYPE
address ADD country text)。对于在添加之前创建的类型的任何值,该新字段将为null。 - 重命名类型的字段(
ALTER TYPE address RENAME zip TOzipcode)。
7-4.删除UDT
drop_type_statement ::= DROP TYPE [ IF EXISTS ] udt_name
删除类型会立即产生结果,不可逆地删除该类型。 但是,尝试删除仍在由另一个类型,表或函数使用的类型将导致错误。如果类型丢失不存在,将返回错误,除非使用IF EXISTS,在这种情况下,操作是无操作。
8.元组
tuple_type ::= TUPLE '<'因此可以使用:cql_type( ','cql_type)* '>' tuple_literal ::= '('term( ','term)* ')'
CREATE TABLE durations ( event text, duration tuple<int, text>, ) INSERT INTO durations (event, duration) VALUES ('ev1', (3, 'hours'));与其他“组合”类型(集合和UDT)不同,元组总是被冻结(不需要freeze关键字),并且不可能只更新元组的一些元素(不更新整个元组)。另外,元组字面量应该总是具有与在类型中声明的值相同的值,其中的一些值可以是null,但是它们需要被明确声明为这样。
9.自定义类型
自定义类型定义为:
custom_type ::= string
自定义类型是一个字符串,它包含继承自服务器端抽象类类的Java类的名称,并且可以由Cassandra加载(因此应该在运行Cassandra的每个节点的CLASSPATH中)。该类将定义什么值对类型有效,以及当用于聚类列时如何排序。处于一些其它目的,自定义类型的值与blob的值相同,并且可以使用blob字面量语法输入。