Cassandra Query Language

目次

本項では Cassandra Query Language が説明される。尚、本項は CQL の最新バージョンのドキュメントである。異なるバージョン間の差異は以下の変更を参照。

Note
本項は CQL 3 のドキュメントであり、CQL 3 は CQL 1 および CQL 2 (共に非推奨・廃止)と大きく異なり、後方互換性は無い。

CQL のモデルはデータを「行」と「列」を含む「テーブル」に格納する点において SQL と類似している。そのため、これらの単語(「行」、「列」、「テーブル」)は本ドキュメントにおいては SQL で使用される定義と同等とする。

定義

慣例

CQL構文についての説明は、本ドキュメントでは、次の慣例を踏襲する:

  • 言語規則は、バッカス・ナウア記法の(非公式な)派生系の一つに緩く従い表記する。特に、任意のアイテムは四角括弧([item])を使用し、繰り返されるアイテムには および ++ は少なくとも1つを意味)を使用する。

  • また、便宜上次の規則も使用する:非終端記号は小文字(と定義へのリンク)で表記、終端記号はすべて大文字で表記する。ただし、記号は識別子とキーワードであるため、実際には大文字と小文字は区別されない。また、いくつかの初期段階の規則の定義では正規表現を使用する。これは、re(<some regular expression>) で示す。

  • 以下に提示される言語規則および文法はドキュメント化の目的で提供されてあり、細かい部分は省略している場合もある。 例えば、CREATE TABLE 文の最後のカラム定義のコンマは任意であり、存在した場合も問題なくサポートされるが、本ドキュメントの文法ではそうではない記述を用いている。 また、文法が受け入れるすべての文が必ずしも有効な CQL であるとは限らない。

  • 文章内のキーワードや CQL コードは次のような固定幅フォントで表記される: fixed-width font

識別子とキーワード

CQL は、識別子(identifier または name)を使用してテーブル、列、その他のオブジェクトを識別する。識別子は、正規表現 [a-zA-Z][a-zA-Z0-9_]* に一致するトークンである。

SELECTWITH などのいくつかの識別子はキーワード(keyword)であり、言語に対して固定された意味を持ちそのほとんどは予約されている。これらのキーワードの一覧は、付録A:CQL キーワードに記載されている。

識別子と(引用符で囲まれていない)キーワードは大文字と小文字を区別しない。よって、 SELECTselectsElEcT と同等であり、myIdmyidMYID と同等となる。よく使用される慣例(本ドキュメントでも採用する)は、キーワードは大文字を使用し、その他の識別子は小文字を使用する。

尚、二重引用符( " )で任意の(空ではない)文字列を囲むことによって定義される、引用識別子(quoted_identifier)と呼ばれる2種類目の識別子も存在する(引用識別子に対し、引用符で囲まれるない単なる識別子は非引用識別子 unquoted_identifier とも言う)。引用識別子はキーワードとして扱われる事は無い。従い、"select" は予約されたキーワードとは解析されず、例えば、カラムを識別する事に使用できる。もちろん select はキーワードと解析され、カラムを識別する際などに使用すると構文解析(パーシング)エラーを引き起こす(引用識別子を使用する事は推奨されない)。尚、識別子とキーワードとは異なり、引用識別子は大文字と小文字を区別する( "My Quoted Id""my quoted id" は異なる引用識別子となる)。[a-zA-Z][a-zA-Z0-9_]* と一致する全て小文字の引用識別子は、引用符を取り除いた単なる識別子と同等に扱われる(従って、"myid"myidmyId と同等であるが、"myId" とは異なる)。引用識別子内では、二重引用符を繰り返す事により二重引用符をエスケープできるので、"foo""bar" などは有効な識別子となる。

Note
引用識別子を使用すると、任意の識別子を持つカラムを定義する事が可能になるが、稀にサーバが使用する特定の識別子と競合する場合が発生する。例えば、条件付きアップデート文を使用する際、サーバの応答に含まれる result-set で "[applied]" という識別子が使用される。もし、同じ識別子を使いカラムを定義してある場合、他に使用されるツールなどにとって混乱を引き起こす原因になり兼ねないので、例の様な識別子を使用する事は非推奨となる。より一般的には、引用識別子より非引用識別子が推奨され、引用識別子を使用する際は( "[applied]" )の様な四角括弧を使用する引用識別子や、( "f(x)" )の様な関数の呼び出しと混同されてしまう様な引用識別子を使用しない事が強く推奨される。

上記は、より正式に表すと:

unquoted_identifier ::=

re(‘[a-zA-Z][a-zA-Z0-9_]*’)

quoted_identifier ::=

‘”‘ (任意の文字、 二重に連ねエスケープする場合 ” も使用可)+ ‘”‘

定数

CQL は以下の種類の定数(constant)を定義する:

constant ::=

string | integer | float | boolean | uuid | blob | NULL

string ::=

‘\” (任意の文字、 二重に連ねエスケープする場合 ‘ も使用可)+ ‘\”
‘$$’ (‘$$’以外の任意の文字)+ ‘$$’

integer ::=

re(‘-?[0-9]+’)

float ::=

re(‘-?[0-9]+(\.[0-9]*)?([eE][+-]?[0-9+])?’) | NAN | INFINITY

boolean ::=

TRUE | FALSE

uuid ::=

hex{8}-hex{4}-hex{4}-hex{4}-hex{12}

hex ::=

re(“[0-9a-fA-F]”)

blob ::=

‘0’ (‘x’ | ‘X’) hex+

言い換えると:

  • 文字列定数(string constant)は、単一引用符(')で囲まれた任意の文字列であり、'It''s raining today' の様に単一引用符を二重に連ねエスケープする事で文字列定数内部でも使用できる。文字列定数は二重引用符を使用する識別子とキーワードと混同してはならない。あるいは、文字列定数は任意の文字列を二重のドル記号で囲む事でも定義できる。その際、$$It’s raining today$$ の様に単一引用符はエスケープせずに文字列定数内部で使用できる。ドル記号を使用した記法はユーザ定義関数内で単一引用符をエスケープする必要性を避けられるため(単一引用符と比べ二重ドル記号が稀なので)しばしば使用される。

  • 整数(integer constant)、浮動小数点(float constant)、及び論理定数(boolean constant)は想定通りに定義される。ただし、浮動小数点定数は特別な定数 NaNInfinity を許す。

  • CQL は uuid 定数をサポートする。

  • Blob 定数(バイナリ・ラージ・オブジェクト)は十六進法で表され、先頭に接頭辞 0x が付く。

  • 特別な NULL 定数は値が無い事を示す。

これら定数の型付けについては下記のデータ型を参照。

CQL には、値の種類を示す項(term)と言う概念があり、以下によって定義される:

function_call ::=

identifier ‘(‘ [ term (‘,’ term)* ] ‘)’

arithmetic_operation ::=

‘-‘ term | term (‘+’ | ‘-‘ | ‘*’ | ‘/’ | ‘%’) term

type_hint ::=

‘(‘ cql_type ‘)’ term

bind_marker ::=

‘?’ | ‘:’ identifier

よって、項とは次の内のどれかに当たる:

コメント

CQL のコメントは、2つのダッシュ(--)または2つのスラッシュ(//)で始まる。

複数行コメントは、/* および */ に囲まれる(ただし、コメントの階層構造化はサポートされてい無い)。

-- This is a comment
// This is a comment too
/* This is
   a multi-line comment */

CQL は、以下に分類できる文(statement)で構成されている:

全ての文は以下の一覧に含まれ、詳しくは上記の各参照先へ:

cql_statement ::=

statement [ ‘;’ ]

secondary_index_statement :==

create_index_statement
| drop_index_statement

プリペアードステートメント

CQL はプリペアードステートメントをサポートしている。プリペアードステートメントは、クエリを1回だけ解析し異なる値でクエリを複数回実行する事を可能にする最適化の一つ。

プリペアードステートメントを使用するには、バインドマーカー(bind_marker参照)を少なくとも1つ使用する文を準備する必要がある。その後、各バインドマーカーに提供される具体的な値を使い文を実行できる。文の準備と実行方法の詳細は、使用する CQL ドライバーによって異なるので使用するドライバーのドキュメントを参照する事をすすめる。

データ型

CQL は型付け言語であり、ネイティブ型コレクション型ユーザー定義型タプル型カスタム型など、豊富なデータ型(cql_type)の種類をサポートしている:

ネイティブ型

CQL でサポートされるネイティブ型は次のとおり:

native_type ::=

ASCII
| BIGINT
| BLOB
| BOOLEAN
| COUNTER
| DATE
| DECIMAL
| DOUBLE
| DURATION
| FLOAT
| INET
| INT
| SMALLINT
| TEXT
| TIME
| TIMESTAMP
| TIMEUUID
| TINYINT
| UUID
| VRCHAR
| VARINT

以下のテーブルは、ネイティブデータ型とそれぞれがサポートする定数の種類をに関する追加情報:

データ型 サポートされる定数 詳細

ascii

string

ASCII文字列

bigint

integer

64ビット符号付きロング

blob

blob

任意のバイト(データ検証無し)

boolean

boolean

true または false

counter

integer

カウンターカラム(64ビット符号付き)。詳細はカウンターを参照

date

integerstring

日付(時間情報無し)。詳細は日付の扱いを参照

decimal

integerfloat

可変精度の10進数

double

integerfloat

64ビットIEEE-754の浮動小数点数

duration

duration

ナノ秒精度の継続時間。詳細は継続時間の扱いを参照

float

integerfloat

32ビットIEEE-754の浮動小数点数

inet

string

IPv4(4バイト長)もしくは IPv6(16バイト長)のIP アドレス。注意すべきは inet 定数は存在せず、IP アドレスは string として入力するべき。

int

integer

32ビット符号付き整数

smallint

integer

16ビット符号付き整数

text

string

UTF-8エンコード文字列

time

integerstring

ナノ秒制度の時間(日付情報無し)。詳細は時間の扱いを参照。

timestamp

integerstring

ミリ秒制度のタイムスタンプ(日付と時間)。詳細はタイムスタンプの扱いを参照。

timeuuid

uuid

バージョン1のUUID。一般的に競合のないタイムスタンプとして使用される。timeuuid関数も参照。

tinyint

integer

8ビット符号付き整数

uuid

uuid

任意のバージョンのUUID

varchar

string

UTF-8エンコード文字列

varint

integer

任意精度の整数

カウンター

カウンター型(counter type)はカウンターカラムの定義に使用する。カウンターカラムの値は64ビット符号付き整数であり、2つの操作、インクリメントとデクリメント、をサポートする(詳しくはUPDATE文を参照)。尚、カウンターの値は設定する事が不可能。カウンターは最初のインクリメントまたはデクリメントが発生するまで存在せず、最初のインクリメントまたはデクリメントが実行される際は実行前のカウンターの値が0であったかの様に扱われる。

カウンターにはいくつかの重要な制限がある:

  • PRIMARY KEY として使用出来ない。

  • カウンターを含むテーブルはカウンターしか含んではならない。言い換えると、あるテーブルにおいて PRIMARY KEY 以外のカラムは全て counter 型を持つ必要がある、または、一つも counter 型を持たない必要がある。

  • カウンターに期限(expiration)を設定する事は出来ない。

  • カウンターに対する削除はサポートされてはいるが、あるカウンターに対して初めて削除を実行する時のみ正常な動作が保証される。言い換えると、一度削除されたカウンターに対して再アップデートを実行する事は推奨されない(仮に再アップデートを実行した場合、正常な動作は保証されない)。

  • カウンターに対するアップデートは冪等でない。この性質による重要な結果として、カウンターに対するアップデートが予期せず失敗すると(タイムアウトやコーディネーターノードとの接続を失うと)クライアントはアップデートが実行されたか知る方法が無い。特に、アップデートの再実行はオーバーカウントを発生させる場合もあれば発生させない場合もある。

タイムスタンプの扱い

timestamp 型の値はエポック(1970年01月01日00時00分00秒 GMT)から経過したミリ秒数を表す64ビット符号付き整数としてエンコードされる。

タイムスタンプは integer または stringISO 8601に従い)として CQL へ入力できる。例えば、以下は全て2011年03月02日 04:05:00 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 を表す。また、アメリカの太平洋標準時(PST)は -8000 で表される。タイムゾーンは省略可能で('2011-02-03 04:05:00')、省略された場合はコーディネーターノードのコンフィグに記されているタイムゾーンに従い前述のタイムスタンプのタイムゾーンを解釈する。しかし、ノードのタイムゾーンのコンフィグが常に思い通りに設定されているとは限らないので、可能であればタイムゾーンを省略せず明示的に記載する事が強く推奨される。

時刻もまた省略可能で('2011-02-03' または '2011-02-03+0000')、省略される場合はデフォルトで 00:00:00 を指定されたまたはデフォルトのタイムゾーンでの時刻として扱う。しかし、日付の部分のみに意味を持つデータである場合はdate型を使うと良い。

日付の扱い

date 型の値はエポックから経過した日数を表す32ビット符号無し整数としてエンコードされる。エポックとは1970年01月01日00時00分00秒 GMT と定義される。

タイムスタンプでは、integer または string として日付を入力することが可能。文字列を使用する場合、yyyy-mm-dd のフォーマットを使用する(例:'2011-02-03')。

時間の扱い

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 型の値は3つの符号付き整数(一つ目は月数、二つ目は日数、三つ目はナノ秒数)としてエンコードされる。一月に含まれる日数は可変であり、またサマータイムなどを考慮すると一日が23時間もしくは25時間である可能性がある事より前述の様に3つの整数として値をエンコードする。尚、月数と日数は32ビット符号付き整数、ナノ秒数は64ビット符号付き整数としてエンコードされる。

継続時間の入力は下記の文字列フォーマットを使用する:

  1. (quantity unit)+ : 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ナノ秒)

  1. ISO 8601 フォーマット: P[n]Y[n]M[n]DT[n]H[n]M[n]S または P[n]W

  1. 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 として使用できない。継続時間データに対するコンテクストの日付が無い限り(例えば、具体的な日付が無いと 1mo29d の大小の比較が不可能である)継続期間には順序を付ける事が出来ないので、この様な制限が生まれる。

サマータイムなどの考慮により、1d の継続時間は 24h の継続時間とは不等である。

コレクション

CQL3 は次の3つのコレクション(collection)をサポートし(マップセットリスト)それぞれの型は以下の様に定義される:

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 はコレクションリテラル内ではサポートされていない点に留意。

注意すべき特徴

コレクションは比較的小さいサイズのデータを保持・非正規化する事が本来の目的。なのでコレクションは「ユーザの電話番号」や「電子メールのラベル」等のデータに対しては最適だが、「あるユーザが送信して全メッセージ」や「あるセンサーが読み取った全ての値」などの制限無しに増加を続けるデータに対してはコレクションの使用は不適切で、代わりに(クラスタリングカラムを含む)特定のテーブルを使用する方が適切。Frozen(フリーズされた)コレクションは具体的に以下の様な特徴・制限を持つ:

  • コレクションは内部でインデックスの作成が行われないので、1つの要素にアクセスするためにもコレクション全体を読み取る必要がある(また内部でのページングも行われない)。

  • マップとセットに対するインサートは書き込み前に読み取りを発生させる事は無いが、リストに対する一部の操作は書き込み前に読み取りを発生させる。また、リストに対する操作の一部は冪等でないため(詳細はリスト参照)、タイムアウト時のリトライは問題を発生させる可能がある。従って、可能な限りリストよりセットを使用することが推奨される。

上記の制限事項などは将来的に廃止される可能性もあるが、(単一の)コレクションに多量のデータを保持する事はアンチパターンである事には注意をすべき。

マップ

map はソートされたキーバリューのペアであり、キーは一意でそのキーによりソートされている。マップの定義とインサートは以下で可能:

CREATE TABLE users (
    id text PRIMARY KEY,
    name text,
    favs map<text, text> // テキストのキーとテキストのバリューのマップ
);

INSERT INTO users (id, name, favs)
           VALUES ('jsmith', 'John Smith', { 'fruit' : 'Apple', 'band' : 'Beatles' });

// 既存のマップを丸ごと置き換える
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つ以上の要素の削除(要素が存在しない場合は NOP となるがエラーは表示されない):

    DELETE favs['author'] FROM users WHERE id = 'jsmith';
    UPDATE users SET favs = favs - { 'movie', 'band'} WHERE id = 'jsmith';

    複数の要素をマップから削除する際は、マップより削除したいキーの set を削除する。

最後に、INSERT および UPDATE では TTL(Time-to-Live)の設定は可能だが、新たにアップデート・インサートされる要素のみに適用される。例えば:

UPDATE users USING TTL 10 SET favs['color'] = 'green' WHERE id = 'jsmith';

上記は TTL を { 'color' : 'green' } のレコードのみに適用し、マップの残りには適用しない。

セット

set はソートされた一意な値のコレクションであり、セットの定義とインサートは以下で可能:

CREATE TABLE images (
    name text PRIMARY KEY,
    owner text,
    tags set<text> // テキストのセット
);

INSERT INTO images (name, owner, tags)
            VALUES ('cat.jpg', 'jsmith', { 'pet', 'cute' });

// 既存のセットを丸ごと置き換える
UPDATE images SET tags = { 'kitten', 'cat', 'lol' } WHERE name = 'cat.jpg';

更に、セットは以下をサポートする:

  • 1つ以上の要素の追加(セットなので既存の要素をインサートするのは NOP となる):

    UPDATE images SET tags = tags + { 'gray', 'cuddly' } WHERE name = 'cat.jpg';
  • 1つ以上の要素の削除(要素が存在しない場合は NOP となるがエラーは表示されない):

    UPDATE images SET tags = tags - { 'cat' } WHERE name = 'cat.jpg';

最後に、マップ同様、TTL を使用すると、新たにインサートされた要素にのみ適用される。

リスト
Note
前述のとおり、(このセクションの最後で再度説明)リストには制限やリストを使用する前に考慮すべきパフォーマンスに関する注意事項がある。一般に、リストの代わりにセットを使用できる場合は、セットを使用する事が強く推奨される。

list はソートされた一意制約の無いコレクションであり、各要素はリスト内の位置に従い順序付けられる。リストの定義とインサートは以下で可能:

CREATE TABLE plays (
    id text PRIMARY KEY,
    game text,
    players int,
    scores list<int> // 整数のリスト
)

INSERT INTO plays (id, game, players, scores)
           VALUES ('123-afde', 'quake', 3, [17, 4, 2]);

// 既存のリストを丸ごと置き換える
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';
  • リスト内の特定の位置の値の設定。この操作は値を設定する位置に既存の要素が存在する事を前提とするため、この条件を満たさない場合はリストが小さいと記述するエラーが発生する:

    UPDATE plays SET scores[1] = 7 WHERE id = '123-afde';
  • リスト内の特定の位置を使用して要素を削除。この操作は削除する要素の位置に既存の要素が存在する事を前提とするため、この条件を満たさない場合はリストが小さいと記述するエラーが発生する。また、この操作は要素を一つ削除するので、リストのサイズが1減少し、削除した要素の後に続く全ての要素の位置がその分前ズレする:

    DELETE scores[1] FROM plays WHERE id = '123-afde';
  • リスト内の特定の値の要素を全て削除(特定の値の要素が一つも存在しない場合は NOP となるがエラーは表示されない):

    UPDATE plays SET scores = scores - [ 12, 21 ] WHERE id = '123-afde';
Warning
リストへ値を追加・前置する操作は冪等ではない。よって、これらの操作がタイムアウト等してしまい操作を再度実行する事は安全ではなく、値の追加・前置が二重に発生する可能性がある。
Warning
リストの特定の位置へ値を設定、特定の位置の値の削除、または特定の値の全ての要素の削除は、いずれも書き込み前に読み取り(read-before-write)を発生させる。従い、これらの操作は一般的なアップデートと比較し実行がより遅く、リソースもより多く必要となる(条件付き書き込みは除外されるが、条件付き書き込みは独自のコストを持つ)。

最後に、マップ同様、TTL を使用すると、新たにインサートされた要素にのみ適用される。

ユーザ定義型

CQL はユーザ定義型(user-defined type 略: UDT)をサポートする。下記記載の create_type_statementalter_type_statementdrop_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 のカラムの宣言に使用)を持ち、識別子と型付けされたフィールドのセットからなる。フィールドはコレクションや他の 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>>
)

以下の点に注意:

  • 既存のデータ型を作成しようとするとエラーが発生する。ただし、IF NOT EXISTS のオプションを使用するとこの限りではなく、作成するデータ型が既に存在する場合はエラーとはならず NOP となる。

  • データ型は作成されたキースペースにバインドされ、そのキースペース内でのみ使用できる。作成時にデータ型の名前にキースペースが前置されている場合はその前置されたキースペース内でデータ型は作成され、作成時にキースペースで前置されていない場合はその時点で使用されているキースペース内で作成される。

  • Cassandra 4.0-alpha5 より、ほとんどの場合 UDT は frozen でなければならない。これが上記の例で frozen<address> が使われる理由。詳細については frozen に関する項を参照する事。

UDT リテラル

ユーザ定義型が作成された後、UDT リテラルを使用して値を入力できる:

udt_literal ::=

‘{‘ identifier ‘:’ term ( ‘,’ identifier ‘:’ term)* ‘}’

言い換えると、UDT リテラルはマップリテラルのキーをデータ型のフィールド名で置き換えた様な構造を持つ。例えば、上記の例で定義されたテーブルに以下を使用してインサートできる:

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 リテラルは対応する UDT で定義されているフィールドのみ使用する必要がある。ただし、フィールドの省略は可能(その場合省略されたフィールドは null となる)。

UDT の変更

既存のユーザ定義型の変更は以下に定義される ALTER TYPE 文を使用する:

alter_type_statement ::=

ALTER TYPE udt_name alter_type_modification

alter_type_modification ::=

ADD field_definition
| RENAME identifier TO identifier ( identifier TO identifier )*

次が可能:

  • データ型に新しいフィールドを追加(ALTER TYPE address ADD country text)。追加されたフィールドは、そのフィールドの追加以前に作成された既存の値では null となる。

  • データ型のフィールドの名前の変更(ALTER TYPE address RENAME zip TO zipcode)。

UDT の削除

既存のユーザ定義型の削除は以下に定義される DROP TYPE 文を使用する:

drop_type_statement ::=

DROP TYPE [ IF EXISTS ] udt_name

データ型の削除は実行されると直ちにデータ型を不可逆的に削除する。ただし、別のデータ型、テーブル、または関数に使用されているデータ型の削除を試みるとエラーが発生する。

削除されるデータ型が存在しない場合はエラーが発生するが、IF EXISTS のオプションを使用するとエラーではなく NOP となる。

タプル

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 キーワードを必要とせず)、タプルの要素の一部を(タプル全体の変更をせずに)変更する事は不可能。また、タプルリテラルは対応するタプル型で定義されている要素の個数と同等な要素の個数を持つ必要がある(要素は null であっても良いが、それを明示的に宣言する必要がある)。

カスタム型
Note
カスタム型は後方互換性のために存在し、その使用は非推奨となる。カスタム型の使用は複雑で使い辛く、他の提供されるデータ型、特にユーザ定義型、を使用すれば事足りることがほとんどであるはず。

カスタム型は以下に定義される:

custom_type ::=

string

カスタム型はサーバサイドの AbstractType クラスを継承し、Cassandra がロードできる(従って Cassandra を実行する全てのノードの CLASSPATH に含まれるべき) Java クラスの名前を含む string である。このクラスがカスタム型に対する有効な値とクラスタリングカラムとして使用された場合の時間のソート方法を定義する。機能的には、カスタム型の値は blob と同等であり、blob リテラルの構文を使用して入力する事が可能。

データ定義

CQL はデータをテーブルに格納する。テーブルはデータのレイアウトを定義するスキーマを持ち、テーブルはキースペース毎にまとめられる。キースペースは含まれるテーブル全てに適応されるいくつかのオプションを定義する。中でも大事なのはキースペースで使用される replication strategy のオプション。アプリケーション毎にキースペースは1つ使用する事が推奨され、従ってクラスターは1つのキースペースのみ定義する場合が多い。

本項ではキースペースとテーブルの作成、変更、削除の際に使用される文を説明する。

共通の定義

キースペースとテーブルの名前は以下に定義される:

keyspace_name ::=

name

table_name ::=

[ keyspace_name ‘.’ ] name

unquoted_name ::=

re(‘[a-zA-Z_0-9]{1,48}’)

quoted_name ::=

‘”‘ unquoted_name ‘”‘

キースペースとテーブルの名前は共に英数字を使用し、空ではなく、長さが48文字に制限される(文字数の制限はテーブルやキースペース名を含む事があるファイル名が特定のファイルシステムで設けられるファイル名の上限を超えない措置として実装されている)。デフォルトでは、キースペースとテーブル名は大文字と小文字の区別はしないが(myTablemytable は同等)、二重引用符を使用する事により大文字と小文字の区別を強制できる("myTable"mytable は異なる)。

また、テーブルは必ずキースペースに含まれ、テーブル名は含まれるキースペース名で修飾される事が可能。キースペース名の修飾がされていない場合は、テーブルはその時点で使用されているキースペースに含まれていると想定される(詳しくはUSE 文)。

更に、カラムの有効な名前は以下に定義される:

column_name ::=

identifier

続く項の準備として、この場で文のオプションを以下に定義する:

options ::=

option ( AND option )*

option ::=

identifier ‘=’ ( identifier | constant | map_literal )

CREATE KEYSPACE 文

キースペースは CREATE KEYSPACE 文を使用して作成する:

create_keyspace_statement ::=

CREATE KEYSPACE [ IF NOT EXISTS ] keyspace_name WITH options

例えば:

CREATE KEYSPACE excelsior
    WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 3};

CREATE KEYSPACE excalibur
    WITH replication = {'class': 'NetworkTopologyStrategy', 'DC1' : 1, 'DC2' : 3}
    AND durable_writes = false;

既存のキースペースを作成しようとするとエラーが発生するが、IF NOT EXISTS のオプションを使用するとエラーは発生せずに NOP となる。

サポートされているオプションは:

名前 種類 必須 デフォルト 説明

replication

マップ

Yes

キースペースで使用する replication strategy とオプション(詳しくは下記の詳細を参照)。

durable_writes

シンプル

No

True

キースペースのアップデートの際にコミットログを使用するか否か(自己責任で無効にする事)。

replication のプロパティは必須であり、最低でも使用する replication strategy クラスを定義する 'class' サブオプションを含まないといけない。残りのサブオプションは使用する replication strategy に依存する。デフォルトで Cassandra は以下の 'class' をサポートする:

SimpleStrategy

クラスター全体に渡り、定義される replication factor に従い、データを複製する単純な replication strategy。一般には、データセンターのレイアウトを無視し、クエリのレイテンシーが極端に変動する事態に繋がるのでプロダクションでの使用は強く非推奨される。プロダクションに適した replication strategy は NetworkTopologyStrategy を参照する事。SimpleStrategy は一つの必須の引数をサポートする:

サブオプション データ型 バージョン 説明

replication_factor

整数

全て

レンジ毎に格納するレプリカの個数。

NeworkTopologyStrategy

データ操作

UPDATE 文

関数

timeuuid関数

付録

付録A:CQL キーワード

変更

本ドキュメントに関するお問い合わせ

株式会社INTHEFOREST

©2020 株式会社INTHEFOREST