データ型
ネイティブ型
CQLでサポートされているネイティブ型は次のとおりです。
native_type::= ASCII | BIGINT | BLOB | BOOLEAN | COUNTER | DATE
| DECIMAL | DOUBLE | DURATION | FLOAT | INET | INT |
SMALLINT | TEXT | TIME | TIMESTAMP | TIMEUUID | TINYINT |
UUID | VARCHAR | VARINT | VECTOR
次の表は、ネイティブデータ型と、各型がサポートする定数の種類に関する追加情報を示しています。
型 | サポートされる定数 | 説明 |
---|---|---|
|
|
ASCII文字列 |
|
|
64ビット符号付きlong |
|
|
任意のバイト(検証なし) |
|
|
|
|
|
カウンタ列(64ビット符号付き値)。詳細は |
|
|
日付(対応する時刻値なし)。詳細は以下の |
|
|
可変精度10進数 |
|
|
64ビットIEEE-754浮動小数点数 |
|
|
ナノ秒精度の期間。詳細は以下の |
|
|
32ビットIEEE-754浮動小数点数 |
|
|
IPアドレス(IPv4(4バイト)またはIPv6(16バイト))。 |
|
|
32ビット符号付きint |
|
|
16ビット符号付きint |
|
|
UTF8エンコードされた文字列 |
|
|
ナノ秒精度の時刻(対応する日付値なし)。詳細は以下の |
|
|
ミリ秒精度のタイムスタンプ(日付と時刻)。詳細は以下の |
|
|
バージョン1 UUID、一般的に「競合のない」タイムスタンプとして使用されます。 |
|
|
8ビット符号付きint |
|
|
UUID(任意のバージョン) |
|
|
UTF8エンコードされた文字列 |
|
|
任意精度の整数 |
|
|
float値の固定長の非NULLフラット化された配列 CASSANDRA-18504 により、このデータ型がCassandra 5.0に追加されました。 |
カウンタ
counter
型は、カウンタ列を定義するために使用されます。カウンタ列は、値が64ビット符号付き整数であり、インクリメントとデクリメントの2つの操作がサポートされている列です(構文についてはUPDATE文を参照)。カウンタの値を設定することはできません。カウンタは、初めてインクリメント/デクリメントされるまで存在せず、最初のインクリメント/デクリメントは前の値が0であったかのように実行されます。
カウンタにはいくつかの重要な制限があります。
-
テーブルの
PRIMARY KEY
の一部である列には使用できません。 -
カウンタを含むテーブルには、カウンタのみを含めることができます。言い換えれば、
PRIMARY KEY
以外のテーブルのすべての列がcounter
型であるか、またはどれもcounter
型ではありません。 -
カウンタは有効期限をサポートしていません。
-
カウンタの削除はサポートされていますが、初めてカウンタを削除する場合にのみ確実に機能します。言い換えれば、削除したカウンタを再更新しないでください(更新した場合、適切な動作は保証されません)。
-
カウンタの更新は、本質的に冪等ではありません。重要な結果は、カウンタの更新が予期せず失敗した場合(タイムアウトまたはコーディネータノードへの接続の喪失)、クライアントは更新が適用されたかどうかを知る方法がないことです。特に、更新を再生しても、カウントの過剰になる場合と、ならない場合があります。
タイムスタンプの使用方法
timestamp
型の値は、エポック(1970年1月1日00:00:00 GMT)からのミリ秒数を表す64ビット符号付き整数としてエンコードされます。
タイムスタンプは、CQLでinteger
としての値、またはISO 8601日付を表すstring
を使用して入力できます。たとえば、以下のすべての値は、2011年3月2日午前4時5分0秒GMTの有効なtimestamp
値です。
-
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'
上記の+0000
はRFC 822の4桁のタイムゾーン仕様です。+0000
はGMTを表します。米国太平洋標準時は-0800
です。必要に応じてタイムゾーンを省略できます('2011-02-03 04:05:00'
)。省略した場合、日付はコーディネータCassandraノードが設定されているタイムゾーンとして解釈されます。ただし、タイムゾーンの設定が期待どおりであることに依存することには固有の困難があるため、可能な限りタイムスタンプには常にタイムゾーンを指定することをお勧めします。
時間の部分も省略できます('2011-02-03'
または'2011-02-03+0000'
)。省略した場合、時刻は指定されたタイムゾーンまたはデフォルトのタイムゾーンの00:00:00になります。ただし、日付の部分のみが関連する場合は、date型を使用することを検討してください。
Date型
date
型の値は、範囲の中央に「エポック」を持つ日数を表す32ビット符号なし整数としてエンコードされます(2^31)。エポックは1970年1月1日です。
タイムスタンプの場合、日付はinteger
として、または日付string
を使用して入力できます。後者の場合、形式はyyyy-mm-dd
である必要があります(たとえば、'2011-02-03'
)。
Time型
time
型の値は、午前0時からのナノ秒数を表す64ビット符号付き整数としてエンコードされます。
タイムスタンプの場合、時刻はinteger
として、または時刻を表すstring
を使用して入力できます。後者の場合、形式はhh:mm:ss[.fffffffff]
である必要があります(ここで、サブ秒の精度は省略可能であり、提供されている場合はナノ秒未満にすることができます)。たとえば、時刻の有効な入力は次のとおりです。
-
'08:12:54'
-
'08:12:54.123'
-
'08:12:54.123456'
-
'08:12:54.123456789'
Duration型
duration
型の値は、可変長の3つの符号付き整数としてエンコードされます。最初の整数は月数、2番目は日数、3番目はナノ秒数を表します。これは、月の日数が変化する可能性があり、夏時間によっては1日が23時間または25時間になる可能性があるためです。内部的には、月数と日数は32ビット整数としてデコードされ、ナノ秒数は64ビット整数としてデコードされます。
期間は次のように入力できます。
-
(quantity unit)+
(例:12h30m
)。ここで、単位は次のとおりです。-
y
:年(12ヶ月) -
mo
:月(1ヶ月) -
w
:週(7日) -
d
:日(1日) -
h
:時間(3,600,000,000,000ナノ秒) -
m
:分(60,000,000,000ナノ秒) -
s
:秒(1,000,000,000ナノ秒) -
ms
:ミリ秒(1,000,000ナノ秒) -
us
またはµs
:マイクロ秒(1000ナノ秒) -
ns
:ナノ秒(1ナノ秒)
-
-
ISO 8601形式:
P[n]Y[n]M[n]DT[n]H[n]M[n]S
またはP[n]W
-
ISO 8601代替形式:
P[YYYY]-[MM]-[DD]T[hh]:[mm]:[ss]
例:
INSERT INTO RiderResults (rider, race, result)
VALUES ('Christopher Froome', 'Tour de France', 89h4m48s);
INSERT INTO RiderResults (rider, race, result)
VALUES ('BARDET Romain', 'Tour de France', PT89H8M53S);
INSERT INTO RiderResults (rider, race, result)
VALUES ('QUINTANA Nairo', 'Tour de France', P0000-00-00T89:09:09);
期間列は、テーブルのPRIMARY KEY
では使用できません。この制限は、期間を順序付けできないためです。日付のコンテキストなしでは、1mo
が29d
より大きいかどうかを知ることは事実上不可能です。
1d
期間は24h
期間と等しくありません。期間型は、夏時間をサポートできるように作成されているためです。
コレクション
CQLは、maps
、sets
、lists
の3種類のコレクションをサポートしています。これらのコレクションの型は、
collection_type::= MAP '<' cql_type',' cql_type'>'
| SET '<' cql_type '>'
| LIST '<' cql_type'>'
で定義され、それらの値はコレクションリテラルを使用して入力できます。
collection_literal::= map_literal | set_literal | list_literal
map_literal::= '\{' [ term ':' term (',' term : term)* ] '}'
set_literal::= '\{' [ term (',' term)* ] '}'
list_literal::= '[' [ term (',' term)* ] ']'
ただし、コレクションリテラル内ではbind_marker
とNULL
のどちらもサポートされていないことに注意してください。
注目すべき特性
コレクションは、比較的少量のデータを格納/非正規化することを目的としています。「特定のユーザーの電話番号」、「メールに適用されたラベル」などによく機能します。しかし、項目が無制限に増加すると予想される場合(「ユーザーが送信したすべてのメッセージ」、「センサーによって登録されたイベント」など)、コレクションは適切ではなく、特定のテーブル(クラスタリング列を含む)を使用する必要があります。具体的には、(非凍結)コレクションには、以下の注目すべき特性と制限があります。
-
個々のコレクションは内部的にインデックス付けされていません。つまり、コレクションの単一の要素にアクセスするためにも、コレクション全体を読み取る必要があります(そして、1つの読み取りは内部的にページングされません)。
-
集合とマップに対する挿入操作では、内部的にリードビフォアライトが発生することはありませんが、リストに対する一部の操作では発生します。さらに、リストの一部の操作は本質的に冪等ではありません(詳細は以下のリストのセクションを参照)。そのため、タイムアウトの場合の再試行が問題になります。したがって、可能な限りリストよりも集合を使用することをお勧めします。
これらの制限の一部は将来削除または改善される可能性がありますが、大量のデータを格納するために(単一の)コレクションを使用することはアンチパターンであることに注意してください。
マップ
map
は、キーがユニークで、キーによってソートされた、キーと値のペアの(ソートされた)集合です。マップは次のように定義して挿入できます。
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';
さらに、マップは以下をサポートします。
-
1つ以上の要素の更新または挿入
UPDATE users SET favs['author'] = 'Ed Poe' WHERE id = 'jsmith'; UPDATE users SET favs = favs + { 'movie' : 'Cassablanca', 'band' : 'ZZ Top' } WHERE id = 'jsmith';
-
1つ以上の要素の削除(要素が存在しない場合、削除はノーオペレーションですが、エラーは発生しません)
DELETE favs['author'] FROM users WHERE id = 'jsmith'; UPDATE users SET favs = favs - { 'movie', 'band'} WHERE id = 'jsmith';
map
から複数の要素を削除するには、キーのset
を削除することに注意してください。
最後に、TTLはINSERT
とUPDATE
の両方で使用できますが、どちらの場合も、設定されたTTLは新しく挿入/更新された要素にのみ適用されます。言い換えれば
UPDATE users USING TTL 10 SET favs['color'] = 'green' WHERE id = 'jsmith';
は、{ 'color' : 'green' }
レコードにのみTTLを適用し、マップの残りの部分は影響を受けません。
集合
set
は、一意の値の(ソートされた)コレクションです。集合は次のように定義して挿入できます。
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';
さらに、集合は以下をサポートします。
-
1つ以上の要素の追加(集合であるため、既に存在する要素を挿入してもノーオペレーションです)
UPDATE images SET tags = tags + { 'gray', 'cuddly' } WHERE name = 'cat.jpg';
-
1つ以上の要素の削除(要素が存在しない場合、削除はノーオペレーションですが、エラーは発生しません)
UPDATE images SET tags = tags - { 'cat' } WHERE name = 'cat.jpg';
最後に、集合では、TTLは新しく挿入された値にのみ適用されます。
リスト
上記で述べ、このセクションの最後にさらに詳しく説明されているように、リストには制限があり、使用前に考慮すべき具体的なパフォーマンス上の考慮事項があります。一般的に、リストの代わりに集合を使用できる場合は、常に集合を使用することをお勧めします。 |
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';
さらに、リストは以下をサポートします。
-
リストへの値の追加と先頭への追加
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';
警告
追加と先頭への追加操作は、本質的に冪等ではありません。したがって、これらの操作のいずれかがタイムアウトした場合、操作を再試行しても安全ではなく、値が2回追加/先頭に追加される可能性があります(またはされない可能性があります)。 |
-
既存の要素がある位置にあるリスト内の値を設定します。リストにその位置がない場合は、エラーが発生します。
UPDATE plays SET scores[1] = 7 WHERE id = '123-afde';
-
既存の要素がある位置にあるリストから要素を削除します。リストにその位置がない場合は、エラーが発生します。さらに、この操作ではリストから要素が削除されるため、リストのサイズは1要素減少し、以降のすべての要素の位置が1つ前にシフトします。
DELETE scores[1] FROM plays WHERE id = '123-afde';
-
リストから特定の値のすべての出現を削除します(特定の要素がリストにまったく存在しない場合は、単に無視され、エラーは発生しません)。
UPDATE plays SET scores = scores - [ 12, 21 ] WHERE id = '123-afde';
警告
位置による要素の設定と削除、および特定の値の出現の削除は、内部的なリードビフォアライトが発生します。これらの操作は通常より遅く実行され、通常の更新よりも多くのリソースを使用します(独自の費用がかかる条件付き書き込みを除く)。 |
最後に、リストでは、TTLは新しく挿入された値にのみ適用されます。
ベクターの操作
ベクターは、特定のデータ型の非NULL値の固定サイズのシーケンスです。リストと同じリテラルを使用します。
ベクターは次のように定義、挿入、更新できます。
CREATE TABLE plays (
id text PRIMARY KEY,
game text,
players int,
scores vector<int, 3> // A vector of 3 integers
)
INSERT INTO plays (id, game, players, scores)
VALUES ('123-afde', 'quake', 3, [17, 4, 2]);
// Replace the existing vector entirely
UPDATE plays SET scores = [ 3, 9, 4] WHERE id = '123-afde';
ベクターの個々の値を変更することはできず、ベクターの個々の要素を選択することもできないことに注意してください。
ユーザー定義型(UDT)
CQLは、ユーザー定義型(UDT)の定義をサポートしています。このような型は、以下に説明するcreate_type_statement
、alter_type_statement
、drop_type_statement
を使用して作成、変更、削除できます。しかし、一度作成されたUDTは、その名前で参照されるだけです。
user_defined_type::= udt_name
udt_name::= [ keyspace_name '.' ] identifier
UDTの作成
新しいユーザー定義型を作成するには、次のように定義されたCREATE TYPE
ステートメントを使用します。
create_type_statement::= CREATE TYPE [ IF NOT EXISTS ] udt_name
'(' field_definition ( ',' field_definition)* ')'
field_definition::= identifier cql_type
UDTには名前があり(その型の列を宣言するために使用されます)、名前付きで型付けされたフィールドの集合です。フィールド名は、コレクションやその他のUDTを含む任意の型にすることができます。例えば
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>>
);
UDTに関する考慮事項
-
IF NOT EXISTS
オプションを使用しない限り、既に存在する型を作成しようとするとエラーが発生します。このオプションを使用すると、型が既に存在する場合は、ステートメントはノーオペレーションになります。 -
型は、作成されたキースペースに本質的にバインドされており、そのキースペースでのみ使用できます。作成時に、型名にキースペース名がプレフィックスとして付いている場合は、そのキースペースに作成されます。そうでない場合は、現在のキースペースに作成されます。
-
Cassandraでは、UDTはほとんどの場合凍結されている必要があるため、上記のテーブル定義では
frozen<address>
を使用しています。
UDTリテラル
ユーザー定義型が作成されると、UDTリテラルを使用して値を入力できます。
udt_literal::= '{' identifier ':' term ( ',' identifier ':' term)* '}'
言い換えれば、UDTリテラルはmapリテラルに似ていますが、そのキーは型のフィールド名です。例えば、前のセクションで定義されたテーブルに次のように挿入できます。
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
に設定されます)。
UDTの変更
既存のユーザー定義型は、ALTER TYPE
ステートメントを使用して変更できます。
alter_type_statement::= ALTER TYPE [ IF EXISTS ] udt_name alter_type_modification
alter_type_modification::= ADD [ IF NOT EXISTS ] field_definition
| RENAME [ IF EXISTS ] identifier TO identifier (AND identifier TO identifier )*
型が存在しない場合、IF EXISTS
を使用しない限り、ステートメントはエラーを返します。その場合は、操作はノーオペレーションになります。あなたはできます
-
型に新しいフィールドを追加する(
ALTER TYPE address ADD country text
)。この新しいフィールドは、追加前に作成された型のすべての値に対してNULL
になります。新しいフィールドが存在する場合は、ステートメントはエラーを返します。ただし、IF NOT EXISTS
を使用すると、操作はノーオペレーションになります。 -
型のフィールドの名前を変更します。フィールドが存在しない場合、ステートメントはエラーを返します。ただし、
IF EXISTS
を使用すると、操作はノーオペレーションになります。
ALTER TYPE address RENAME zip TO zipcode;
タプル
CQLは、タプルとタプル型(要素は異なる型にすることができます)もサポートしています。機能的には、タプルは匿名フィールドを持つ匿名UDTとして考えることができます。タプル型とタプルリテラルは次のように定義されます。
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などの他の複合型とは異なり、タプルは常にfrozen <frozen>
(frozen
キーワードは不要)であり、タプルの要素の一部のみを更新することはできません(タプル全体を更新せずに)。また、タプルリテラルには、そのタプルの型の宣言で宣言された数と同じ数の値が常に必要です(これらの値の一部はNULLにすることができますが、明示的にNULLとして宣言する必要があります)。
カスタム型
カスタム型は主に下位互換性のために存在し、その使用は推奨されません。その使用は複雑で、ユーザーフレンドリーではなく、提供されている他の型、特にユーザー定義型はほぼ常に十分です。 |
カスタム型は次のように定義されます。
custom_type::= string
カスタム型は、サーバー側のAbstractType
クラスを拡張し、CassandraによってロードできるJavaクラスの名前を含むstring
です(そのため、Cassandraを実行しているすべてのノードのCLASSPATH
に存在する必要があります)。このクラスは、型に対して有効な値と、クラスタリング列に使用されたときの型のソート方法を定義します。それ以外の目的では、カスタム型の値はblob
の値と同じであり、特にblob
リテラル構文を使用して入力できます。