cql 컬렉션(map, set, list)에는 기능도 많다. 자바로 개발되었던 이유로 cql을 사용해 탄력적으로 개발할 수 있다.



ALTER TABLE "user_status_updates"

ADD "starred_by_users" SET<text>;


ALTER TABLE "user_status_updates"

ADD "shared_by" LIST<text>;


ALTER TABLE "users"

ADD social_identities MAP<text,bigint>;



UPDATE 예제는 다음과 같다. UPDATE문은 INSERT문과 기반이 같은 upsert 이기 때문에 insert도 되고 update도 된다. 


CQL 컬렉션의 가장 강력한 기능은 컬렉션에 개별 값을 저장할 수 있다.



UPDATE images SET tags = tags + { 'cute', 'cuddly' } WHERE name = 'cat.jpg';

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



UPDATE plays SET players = 5, scores = scores + [ 14, 21 ] WHERE id = '123-afde';

UPDATE plays SET players = 5, scores = [ 12 ] + scores WHERE id = '123-afde';



UPDATE users SET favs['author'] = 'Ed Poe' WHERE id = 'jsmith'

UPDATE users SET favs = favs +  { 'movie' : 'Cassablanca' } WHERE id = 'jsmith'



주의 할점은 list의 삭제와 변경은 성능 이슈가 있지만, map과 set의 삭제와 변경은 list에 비해 성능 이슈가 덜하다.




또한 컬렉션 컬럼에 인덱스를 사용할 수 있다. 그러나 성능 이슈가 있을 수 있는 대용량 트래픽에서는 사용하지 않는 것이 좋다. 


map 컬렉션 컬럼에 보조 인덱스를 생성하면, map의 키와 map의 값 모두 인덱스가 생성된다. 따라서 맵의 키만 인덱스 생성을 원한다면 KEYS라는 오퍼레이터를 사용한다.


CREATE INDEX ON "users" (KEYS("social_identities"));




검색은 다음과 같이 진행한다. 


SELECT "username", "social_identities"

FROM users

WHERE "social_identities" CONTAINS KEY 'facebook';




CQL에서는 컬렉션 컬럼을 부분적으로 읽을 수 없다. 컬렉션에서 데이터를 검색하는 유일한 방법은 컬렉션 전체를 읽는 것이다. 따라서 성능 이슈가 있는 곳에 사용할 때는 주의 깊게 사용해야 한다.


용량 제한이 있는데 컬렉션은 64KB를 넘지 않는 데이터를 포함할 수 있다. 하나의 컬렉션에 64KB 이상의 데이터를 추가할 수 없지만 컬렉션을 읽으려 하면 64KB까지만 데이터를 읽기 때문에 결과가 잘려 데이터 손실이 발생한다.

따라서 제한 없이 커질 수 있을 예정의 데이터는 컬렉션 컬럼에 적합하지 않다. 만약 계속 데이터가 커진다면 64KB 크기를 넘지 않는 여러 개의 컬렉션으로 쪼개야 한다.



카산드라 컬렉션의 다른 한계는 WHERE...IN 절을 사용해 여러 로우를 선택할 때 컬렉션을 읽을 수 없다는 점이다. 다음 쿼리는 에러가 발생한다.


SELECT * FROM "user_status_updates"

WHERE "username" = 'alice'

AND "id" IN (

 1234

);




테이블에 컬렉션 컬럼이 존재하면 WHERE...IN을 사용할 때는 컬렉션이 아닌 컬럼만 명시적으로 선택해야 한다.



튜플도 지원한다.


CREATE TABLE cycling.route (race_id int, race_name text, point_id int, lat_long tuple<text, tuple<float,float>>, PRIMARY KEY (race_id, point_id));





컬럼을 사용하는 주요 포인트가 있다. 


보조 인덱스는 단일 컬럼에만 적용할 수 있다. 예를 들어 education_history 컬럼이 각각 name과 year 컬럼으로 분리되어 있다면 해당 컬럼들의 주어진 값 조합으로 레코드를 효율적으로 검색할 수있는 인덱스를 생성할 수 없다. 튜플을 사용해 두 값을 단일 컬럼에 위치시키고 해당 컬럼에 인덱스를 추가해서 여러 컬럼에 인덱스를 추가한 것과 동일한 효과를 얻을 수 있다.

(카산드라의 보조 인덱스 단점을 컬렉션으로 해결할 수 있는 특징이 있다.)




튜플의 확장 개념인 사용자 정의 타입( udt)를 지원하기도 한다. 이름을 더 추가한다.



cqlsh> CREATE TYPE cycling.basic_info (

  birthday timestamp,

  nationality text,

  weight text,

  height text

);



CREATE TABLE cycling.cyclist_stats ( id uuid PRIMARY KEY, lastname text, basics FROZEN<basic_info>);  




대부분의 상황에서 사용자 정의 타입은 이름이 포함된 필드와 부분 선택의 추가 이점을 제공하기 때문에 튜플보다 더 나은 선택이 될 것이다.






구분

리스트

튜플

사용자 정의 타입

크기

유연

유연

유연

고정

고정

개별 변경

가능

가능

가능

불가능

불가능

부분 선택

불가능

불가능

불가능

불가능

가능

이름-값 쌍

불가능

불가능

가능

불가능

가능

여러 타입

불가능

불가능

키와 값

가능

가능

인덱스

개별 엘리먼트

개별 엘리먼트

개별 엘리먼트

전체 값

전체 값

기본 키 사용 여부

불가능

불가능

불가능

가능

가능



참고


http://www.datastax.com/documentation/cql/3.3/cql/cql_reference/delete_r.html


http://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlUpdate.html


http://docs.datastax.com/en/cql/3.1/cql/cql_using/use_collections_c.html


http://cassandra.apache.org/doc/old/CQL-3.0.html#collections


https://docs.datastax.com/en/cql/3.1/cql/cql_reference/tupleType.html


https://docs.datastax.com/en/cql/latest/cql/cql_using/useCreateUDT.html

Posted by '김용환'
,

Mac OS에서 카산드라를 실행했다가 비정상 종료가 되면 가끔 다음 에러가 발생할 때가 있다. 


재시작을 한다 한들 결과를 똑같다.



INFO  [main] 2017-08-11 23:18:05,341 CommitLog.java:157 - Replaying ./bin/../data/commitlog/CommitLog-6-1502171952033.log, ./bin/../data/commitlog/CommitLog-6-1502171952034.log, ./bin/../data/commitlog/CommitLog-6-1502422474087.log, ./bin/../data/commitlog/CommitLog-6-1502422474088.log, ./bin/../data/commitlog/CommitLog-6-1502422504239.log, ./bin/../data/commitlog/CommitLog-6-1502422504240.log, ./bin/../data/commitlog/CommitLog-6-1502452966387.log, ./bin/../data/commitlog/CommitLog-6-1502452966388.log, ./bin/../data/commitlog/CommitLog-6-1502457013860.log, ./bin/../data/commitlog/CommitLog-6-1502457013861.log, ./bin/../data/commitlog/CommitLog-6-1502457041056.log, ./bin/../data/commitlog/CommitLog-6-1502457041057.log

ERROR [main] 2017-08-11 23:18:05,622 JVMStabilityInspector.java:82 - Exiting due to error while processing commit log during initialization.

org.apache.cassandra.db.commitlog.CommitLogReadHandler$CommitLogReadException: Unexpected error deserializing mutation; saved to /var/folders/ch/zbmq4sk149gcz172ylw54m140000gp/T/mutation410555022742916493dat.  This may be caused by replaying a mutation against a table with the same name but incompatible schema.  Exception follows: java.io.IOError: java.io.IOException: Corrupt empty row found in unfiltered partition


at org.apache.cassandra.db.commitlog.CommitLogReader.readMutation(CommitLogReader.java:409) [apache-cassandra-3.10.jar:3.10]

at org.apache.cassandra.db.commitlog.CommitLogReader.readSection(CommitLogReader.java:342) [apache-cassandra-3.10.jar:3.10]

at org.apache.cassandra.db.commitlog.CommitLogReader.readCommitLogSegment(CommitLogReader.java:201) [apache-cassandra-3.10.jar:3.10]

at org.apache.cassandra.db.commitlog.CommitLogReader.readAllFiles(CommitLogReader.java:84) [apache-cassandra-3.10.jar:3.10]

at org.apache.cassandra.db.commitlog.CommitLogReplayer.replayFiles(CommitLogReplayer.java:140) [apache-cassandra-3.10.jar:3.10]




commit 로그를 replay하다가 에러가 발생한 이유인데, commit log가 바이너리라서 읽기도 애매하긴 하다. 정확한 문제를 찾기도 전에 어려워질 수 있다. commit 로그를 백업 디렉토리에 move시켜 놓고 다시 재시작하면 정상적으로 동작한다. 


mkdir -p ~/dev/backup/

mv data/commitlog ~/dev/backup/

./bin/cassandra



'cassandra' 카테고리의 다른 글

[cassandra3]  (0) 2017.08.15
[cassandra3] 컬렉션과 사용자 정의 타입(udt)  (0) 2017.08.12
[cassandra] node local의 의미  (0) 2017.08.10
[cassandra3] select now()  (0) 2017.08.09
[cassandra3] schema 백업(backup)/복구(restore)하기  (0) 2017.08.08
Posted by '김용환'
,