Cassandra ドキュメント

バージョン

プレリリースバージョンのドキュメントを表示しています。

データ型

CQLは型付き言語であり、ネイティブ型コレクション型ユーザー定義型タプル型カスタム型を含む豊富なデータ型をサポートしています。

cql_type::= native_type| collection_type| user_defined_type | tuple_type | custom_type

ネイティブ型

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

string

ASCII文字列

bigint

integer

64ビット符号付きlong

blob

blob

任意のバイト(検証なし)

boolean

boolean

trueまたはfalseのいずれか

counter

integer

カウンタ列(64ビット符号付き値)。詳細はcountersを参照してください。

date

integerstring

日付(対応する時刻値なし)。詳細は以下のdatesを参照してください。

decimal

integerfloat

可変精度10進数

double

integerfloat

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

duration

duration,

ナノ秒精度の期間。詳細は以下のdurationsを参照してください。

float

integerfloat

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

inet

string

IPアドレス(IPv4(4バイト)またはIPv6(16バイト))。inet定数はありません。IPアドレスは文字列として入力する必要があります。

int

integer

32ビット符号付きint

smallint

integer

16ビット符号付きint

text

string

UTF8エンコードされた文字列

time

integerstring

ナノ秒精度の時刻(対応する日付値なし)。詳細は以下のtimesを参照してください。

timestamp

integerstring

ミリ秒精度のタイムスタンプ(日付と時刻)。詳細は以下のtimestampsを参照してください。

timeuuid

uuid

バージョン1 UUID、一般的に「競合のない」タイムスタンプとして使用されます。timeuuid-functionsも参照してください。

tinyint

integer

8ビット符号付きint

uuid

uuid

UUID(任意のバージョン)

varchar

string

UTF8エンコードされた文字列

varint

integer

任意精度の整数

vector

float

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では使用できません。この制限は、期間を順序付けできないためです。日付のコンテキストなしでは、1mo29dより大きいかどうかを知ることは事実上不可能です。

1d期間は24h期間と等しくありません。期間型は、夏時間をサポートできるように作成されているためです。

コレクション

CQLは、mapssetslistsの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_markerNULLのどちらもサポートされていないことに注意してください。

注目すべき特性

コレクションは、比較的少量のデータを格納/非正規化することを目的としています。「特定のユーザーの電話番号」、「メールに適用されたラベル」などによく機能します。しかし、項目が無制限に増加すると予想される場合(「ユーザーが送信したすべてのメッセージ」、「センサーによって登録されたイベント」など)、コレクションは適切ではなく、特定のテーブル(クラスタリング列を含む)を使用する必要があります。具体的には、(非凍結)コレクションには、以下の注目すべき特性と制限があります。

  • 個々のコレクションは内部的にインデックス付けされていません。つまり、コレクションの単一の要素にアクセスするためにも、コレクション全体を読み取る必要があります(そして、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はINSERTUPDATEの両方で使用できますが、どちらの場合も、設定された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_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を含む任意の型にすることができます。例えば

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;

UDTの削除

DROP TYPEステートメントを使用して、既存のユーザー定義型を削除できます。

drop_type_statement::= DROP TYPE [ IF EXISTS ] udt_name

型の削除は、その型の即時かつ不可逆的な削除につながります。ただし、他の型、テーブル、または関数によってまだ使用されている型を削除しようとすると、エラーが発生します。

削除された型が存在しない場合、IF EXISTSを使用しない限り、エラーが返されます。その場合は、操作はノーオペレーションになります。

タプル

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リテラル構文を使用して入力できます。