Tag Archives: Column

[NoSQL/Cassandra] 카산드라를 이용한 간단한 블로그 설계 예제

사용자 삽입 이미지
[도대체 슈퍼컬럼이 무엇일까? 카산드라 데이터모델에 대한 소개]에서 카산드라의 데이터 모델에 대해 중구난방으로 설명을 해보았습니다. 이제 이러한 정보를 한데 모아서 간단한 블로그 어플리케이션을 만들어보도록 하겠습니다. 이 간단한 블로그는 다음과 같은 기능을 가집니다.

– 단일 블로그 지원
– 다수의 필자 지원
– 하나의 글은 제목, 글내용, 퍼머링크, 글 작성 시간을 데이터로 갖습니다.
– 하나의글은 다수의 태그를 가질 수 있습니다.
– 방문객들은 가입은 할 수 없지만 댓글을 작성할수는 있습니다.
– 댓글은 글내용, 작성시각, 글작성자의 이름을 데이터로 갖습니다.
– 글은 가장 시간을 기준으로 역정렬하여 보여줍니다. (가장 최근글이 처음으로 나옵니다)
– 태그를 선택시에 해당하는 모든 글은 시간을 기준으로 역정렬되어 보여줍니다.

이제 설명하게 되는 각각의 컬럼패밀리들은 하나의 단일 키스페이스에 포함되게됩니다. 예시를 위해 XML정의도 함께 보여드리겠습니다. CF는 컬럼패밀리(ColumnFamily)입니다.

필자의 컬럼패밀리(ColumnFamily)
필자의 정보를 담는 컬럼패밀리를 모델링하는 것은 매우 간단합니다. 필자는 자기 자신의 로우를 가질것이며 자신의 이름을 키로써 사용할 것입니다. 로우의 안에는 필자의 프로필 정보를 뜻하는 몇가지의 컬럼이 들어갈 것입니다. 여기서 컬럼패밀리의 로우의 데이터를 가져오기 위해 필자의 이름인 키를 이용하여 데이터를 가져올 것이며 모든 포함된 컬럼들을 가져올 것입니다. 여기의 필자의 이름은 특별히 정렬되어야 할 필요가 없으며 그러므로 정렬기준이 되는 옵션으로 BytesType을 사용하였습니다. 이 값은 데이터를 추가시에 아무런 Validation처리를 하지 않고 맨 뒤로 값을 추가하게 됩니다.

<!--
    ColumnFamily: Authors
    모든 필자의 정보를 이곳에 저장합니다.

    Row Key => 필자의 이름 (필자의 이름은 유니크함을 의미합니다)
    Column Name: 하나의 글에 대한 속성값들 (제목, 글내용, 기타)
    Column Value: 컬럼들의 값

    Access: 필자의 이름을 통해 모든 정보를 가져오게 됩니다
-->
    Authors : { // CF
        Arin Sarkissian : { // row key
            // 컬럼의 정보는 필자의 프로필입니다
            numPosts: 11,
            twitter: phatduckk,
            email: arin@example.com,
            bio: "bla bla bla"
        },
        // 다른 필자의 정보
        Author 2 {
            ...
        }
    }

<ColumnFamily CompareWith="BytesType" Name="Authors"/>

블로그글 컬럼패밀리(ColumnFamily)
블로그글 역시도 마찬가지로 단순한 키/밸류 방식을 따르고 있습니다. 하나의 로우는 하나의 글을 저장하게 됩니다. 이러한 로우의 컬럼들은 블로그글의 다양한 데이터를 포함하고 있습니다. 태그의 경우에는 일명 demornalize라고 불리는 사용에 필요한 형태로 데이터를 퇴화(?)랄까 변화시키는 과정을 거쳐 입력을 하게 됩니다. 여기서 태그에는 콤마를 붙여 구분하도록 입력하였습니다.
각각의 블로그글의 키로써는 퍼머링크(slug)를 사용하였습니다. 블로그글의 주소로써 곧바로 요청을 하면 바로 데이터를 꺼내줄 수 있어 용이할 듯 하네요.

<!--
    ColumnFamily: 블로그글
    모든 블로그글을 포함합니다.

    Row Key: 글의 퍼머링크(slug)
    Column Name: 블로그글에 필요한 각 요소(글제목, 글내용, 기타)
    Column Value: 컬럼들의 값

    Access: 퍼머링크 값을 통해 데이터를 가져오게 됩니다.
-->
    BlogEntries : { // CF
        i-got-a-new-guitar : { // 로우의 키
            title: This is a blog entry about my new, awesome guitar,
            body: this is a cool entry. etc etc yada yada
            author: Arin Sarkissian  // 필자컬럼패밀리의 로우키
            tags: life,guitar,music  // 태그들을 콤마로 분류
            pubDate: 1250558004      // unixtimestamp 형식의 글 작성시각
            slug: i-got-a-new-guitar
        },
        // 또다른 글
        another-cool-guitar : {
            ...
            tags: guitar,
            slug: another-cool-guitar
        },
        scream-is-the-best-movie-ever : {
            ...
            tags: movie,horror,
            slug: scream-is-the-best-movie-ever
        }
    }

<ColumnFamily CompareWith="BytesType" Name="BlogEntries"/>

태그의 컬럼패밀리(ColumnFamily)

여기서는 이제 카산드라의 흥미로운점에 대해 다루어보도록 하겠습니다. 태그의 컬럼패밀리에서는 지금까지와는 달리 조금 어려워질수도 있겠습니다. 여기서는 기본적으로 태그와 블로그글의 상호 연관관계에 대해 이해를 할 필요가 있습니다. 다음의 예제에서는 카산드라의 이미 정렬된채로 저장되는 데이터에 대한 설명과 함께 데이터를 가져올때 어떤식으로 가져올 수 있는지를 설명하게 됩니다. 이미 정렬된 태그정보를 이용하여 블로그글을 정렬된 순서로 가져올 수 있습니다.

여기서 태그를 구현하기 위해 중요한 설계 요소로는 모든 블로그 글에 대하여 “__notag__”라는 태그를 붙일것이라는 것입니다. 블로그 최근글보기를 수행할 경우 이 “__notag__”태그를 가지고 최신글을 가져오게 됩니다. 결과적으로 블로그에 3개의 태그를 달았다면 이 “__notag__”를 포함하여 총 4개의 태그를 가지는것이 됩니다.

또한 추가로 이해해야 할 점으로는 각각의 로우들을 시간순으로 정렬하기 위해서는 각각의 컬럼들이 Time UUID라는 타입을 기준으로 정렬할 수 있도록 컬럼패밀리의 CompareWith설정을 TimeUUIDType으로 변경해 주어야 합니다.  이경우에 모든 컬럼들은 시간순으로 정렬이 될것이며 특정 태그를 포함한 최근글을 가져오라는 명령을 수행하기에 적절한 상태가 됩니다.

이제 최근글 10개를 가져오기 위해 다음과 같은 과정을 수행합니다.

1. __notag__라는 태그를 가진 최근 글 10개를 가져옵니다. (이태그를 포함한다는 조건은 글 전체라는 의미가 됩니다)
2. 가져온 컬럼들의 묶음을 가지고 순환(Loop)을 돌며 처리를 합니다.
3. 순환을 돌며 블로그글 컬럼패밀리의 로우의 키를 알수가 있습니다.
4. 이 값(블로그글의 로우 키)을 가지고 블로그글을 가져옵니다.
5. 이 블로그글의 “author”컬럼의 값을 가지고 필자 컬럼패밀리의 로우를 가져오게 되면 필자의 프로필 데이터를 가져올 수 있습니다.
6. 이시점에서 우리는 블로그글뿐만 아니라 필자의 데이터도 가져올 수 있게 되었습니다.
7. 이제 블로그글 로우의 “tag”컬럼값을 ,를 기준으로 분리할 수 있습니다.
8. 이제 댓글을 제외한 블로그글을 보여주기 위한 모든 과정을 거쳤습니다.
<!--

    ColumnFamily: 태그
    블로그글을 정렬하기 위해 2차 인덱스로써 사용되기도 하는 요소

    Row Key => tag
    Column Names: TimeUUIDType
    Column Value: 블로그글 컬럼패밀리의 로우 키

    Access: 특정 태그가 달린 글을 가져올 수 있습니다.
-->
    TaggedPosts : { // CF
        // "guitar" 태그가 달린 글들
        guitar : {  // 태그 이름이 키가 됨
            // 컬럼의 이름은 TimeUUIDType이고 값은 블로그글의 로우의 키입니다
            timeuuid_1 : i-got-a-new-guitar,
            timeuuid_2 : another-cool-guitar,
        },
        // 여기에 모든 블로그글이 저장됩니다
        __notag__ : {
            timeuuid_1b : i-got-a-new-guitar,

            // notice this is in the guitar Row as well
            timeuuid_2b : another-cool-guitar,

            // and this is in the movie Row as well
            timeuuid_2b : scream-is-the-best-movie-ever,
        },
        // "movie" 태그가 달린 글
        movie: {
            timeuuid_1c: scream-is-the-best-movie-ever
        }
    }

<ColumnFamily CompareWith="TimeUUIDType" Name="TaggedPosts"/>

댓글 컬럼패밀리(ColumnFamily)
이제 마지막으로 댓글의 설계 모델을 표현해 보겠습니다. 여기서는 슈퍼컬럼(SuperColumn)을 사용합니다. 하나의 로우는 하나의 블로그글을 의미합니다. 이 블로그 주소를 키로 갖는 요소 하위에 있는 녀석들을 슈퍼컬럼이라고 합니다. 말그대로 컬럼과 로우 키의 중간쯤에 있는 요소입니다. 슈퍼컬럼은 UUID값이 될것이며 댓글도 마찬가지로 시간순으로 정렬을 하기 위해 TimeUUIDType을 사용할 것입니다. 모든 댓글은 시간순으로 정렬이 될 것이며 이 안에 있는 각각의 컬럼들은 댓글에 표현되기 위한 정보가 들어가게됩니다. 생각보다 복잡한 이야기는 아닙니다.

<!--
    ColumnFamily: 댓글
    댓글은 여기에 저장됩니다.

    Row key => 블로그글의 로우 키
    SuperColumn name: TimeUUIDType

    Access: 블로그 글마다 작성된 모든 댓글을 가져옵니다
-->
    Comments : {
        // scream-is-the-best-movie-ever에 대한 모든 댓글들
        scream-is-the-best-movie-ever : { // 로우 키
            // 오래된 글이 먼저 나옵니다
            timeuuid_1 : { // 슈퍼컬럼의 이름
                // 이 댓글(슈퍼컬럼)의 모든 컬럼들
                commenter: Joe Blow,
                email: joeb@example.com,
                comment: you're a dumb douche, the godfather is the best movie ever
                commentTime: 1250438004
            },

            ... scream-is-the-best-movie-ever에대한 더 많은 댓글들

            // 가장 최근에 작성된 댓글
            timeuuid_2 : {
                commenter: Some Dude,
                email: sd@example.com,
                comment: be nice Joe Blow this isnt youtube
                commentTime: 1250557004
            },
        },

        // i-got-a-new-guitar에 달린 댓글
        i-got-a-new-guitar : {
            timeuuid_1 : { // 슈퍼컬럼의 이름
                commenter: Johnny Guitar,
                email: guitardude@example.com,
                comment: nice axe dawg...
                commentTime: 1250438004
            },
        }
    }

<ColumnFamily CompareWith="TimeUUIDType" ColumnType="Super"
    CompareSubcolumnsWith="BytesType" Name="Comments"/>

이제 마지막으로 위에서 언급된 모든 컬럼 패밀리들을 한데모아서 보도록 하죠.

<Keyspace Name="BloggyAppy">
    <ColumnFamily CompareWith="BytesType" Name="Authors"/>
    <ColumnFamily CompareWith="BytesType" Name="BlogEntries"/>
    <ColumnFamily CompareWith="TimeUUIDType" Name="TaggedPosts"/>
    <ColumnFamily CompareWith="TimeUUIDType" Name="Comments"
        CompareSubcolumnsWith="BytesType" ColumnType="Super"/>
</Keyspace>

참고:
http://arin.me/blog/wtf-is-a-supercolumn-cassandra-data-model (Thanks!)

[NoSQL/Cassandra] 도대체 슈퍼컬럼이 무엇일까? 카산드라 데이터모델에 대한 소개

사용자 삽입 이미지
NoSQL중에 가장 주목받고 있는 Cassandra의 개념은 결코 어렵지 않습니다. 하지만 어떻게 생각하면 정말 어렵습니다. 처음 스프링을 공부할때 AOP(Aspect Oriented Programming)라는 개념이 어렵게 다가왔던 시절이 생각이 납니다. 그당시에 AOP가 어려웠던것은 바로 내 머리속에 너무나도 자연스럽게 자리잡고 있는 OOP(Object Oriented Programming) 때문이죠. 바로 객체 지향이 너무나도 머리속에 자연스럽게 자리잡고 있었기 때문에 AOP를 이해하는데 많은 방해가 되었습니다.

카산드라도 마찬가지로 이해를 하는데 불필요한 방해요소가 있습니다. 바로 RDBMS(Relational DataBase Management System)입니다. Oracle, MSSQL, MySQL등을 아주 많이 다뤄 보셨다고요? 그렇다면 카산드라가 정말 어려울 것입니다. 오히려 모르는것이 도움이 될 수 있습니다. 카산드라를 공부하긴 공부해할꺼 같은데 시작해서 인터넷의 글을 검색하다보면 답답해 미쳐버릴 지경입니다. 도대체 SELECT는 어떻게 해야 할까, JOIN은 어떻게 한다는거지? 두개 이상의 데이터를 어떻게 조합하여 사용할수 있는걸까? 하물며 Sub-Query는 어떻게 사용하는거지? 비슷한 개념이라도 있긴한가?

카산드라를 조금만 살펴보시면 알 수 있습니다만 없습니다. 하물며 그 기본적인 개념인 JOIN의 개념조차 없습니다. 정말 단순하게 set/get으로만 이루어진 단순한 명령뿐입니다. 도대체 이런 단순한 시스템을 뭘 믿고 엄청난 대용량의 데이터를 보관한단 말일까요? 우선 카산드라를 이해하기 위해서는 머리속에서 RDB라는 개념을 지우실 필요가 있습니다. 좀더 나아가 DB라고 하면 떠오르는 무엇인가를 지울 필요가 있습니다. DB == SQL 일까요? 사실 저는 그렇게 생각해오고 있었습니다. DB는 말그대로 데이터 저장소쯤으로 이해하시면 이제 쉬워집니다. 여기서는 SQL이라는것도 쿼리문이라는 단어도 필요가 없습니다. 이와 관련하여 멋진 블로그글이 있어 옮겨 적어봅니다.

다음의 글을 읽는데 필요한 사전 지식 : JSON

1. 조각들

컬림(Column)
컬럼은 데이터를 이루는 가장 작은 단위입니다. DB수업 시간에는 일명 튜플이라고 배우는것과 비숫합니다. 컬럼은 이름과 값을 가지며 데이터가 갱신된 시각이 기록됩니다.

{  // 이것이 컬럼입니다.
    name: "emailAddress",
    value: "arin@example.com",
    timestamp: 123456789
}

이것이 값을 표현하는 작은 단위의 전부입니다. 앞으로는 좀더 편하게 생각하기 위해서 타임스탬프값은 무시하도록 하겠습니다. 단지 키/밸류만 생각하도록 합시다. 컬럼들의 이름과 값은 둘다 바이너리(기술적인 용어로 byte[])로 저장이 되며 길이에는 제한이 없습니다.

슈퍼컬럼(SuperColumn)
슈퍼컬럼은 이름과 값으로 이루어져 있습니다. 여기서 값에는 제한이 없는 숫자만큼의 컬럼들을 포함할 수 있습니다. 컬럼의 이름이 각각의 키(Key)가 됩니다.

{   // 이것이 슈퍼컬럼입니다
    name: "homeAddress",
    // 무한한 컬럼들을 가질 수 있습니다
    value: {
        // note the keys is the name of the Column
        street: {name: "street", value: "1234 x street", timestamp: 123456789},
        city: {name: "city", value: "san francisco", timestamp: 123456789},
        zip: {name: "zip", value: "94107", timestamp: 123456789},
    }
}

여기서 미리 알아두어야 할점은 슈퍼컬럼은 사용하지 않을 수 있습니다. 현재의 슈퍼컬럼이라는 개념은 실제로는 컬럼패밀리(ColumnFamily)에 가깝습니다. 하지만 일단은 이해를 돕기 위해서 쓰는 글이니 그러려니 하고 봐주세요.

컬럼(Column) VS 슈퍼컬럼(SuperColumn)
컬럼과 슈퍼컬럼은 둘다 이름과 값으로 이루어진 튜플입니다. 하지만 가장 큰 차이는 컬럼의 값은 문자열(String)인데 반해 슈퍼컬럼의 값은 컬럼들의 Map입니다. 이것이 무슨말이냐 하면 슈퍼컬럼의 값은(여기서의 값은 컬럼의 이름이 됩니다) 다양한 형태의 데이터 타입을 가질 수 있습니다.  다른 작은 차이로는 슈퍼컬럼은 컬럼과 달리 타임스탬프(timestamp) 컴포넌트를 가지지 못합니다.

본격적으로 시작하기에 앞서
JSON문법을 예시로 들며 설명을 하고 있습니다만 좀더 간단하게 표현하기 위해 타임스탬프(timestamp)값을 빼기로 하고 컬럼과 슈퍼컬럼의 이름부분을 제거하겠습니다. 결과적으로 위의 슈퍼컬럼에서 보였던 예제는 다음과 같이 변할 수 있습니다.

homeAddress: {
    street: "1234 x street",
    city: "san francisco",
    zip: "94107",
}

2. 그룹으로 묶기

지금까지는 컬럼과 슈퍼컬럼의 단순한 단일 구조에 대해 설명해 보았습니다. 이번에 소개해 드릴 구조는 컬럼패밀리(ColumnFamily)라고 불리는데 Standard와 Super라는 모습을 가집니다.

컬럼패밀리(ColumnFamily)
컬럼패밀리는 무한한 로우(Row)를 가지는 구조를 가집니다. 여기서 로우라는 단위를 사용하는것은 RDBMS의 그 로우라고 생각하시면 쉬울듯 합니다. 각각의 로우는 키와 컬럼들의 집합인 Map을 값으로 가집니다.

UserProfile = { // 이것이 컬럼패밀리입니다
    phatduckk: {   // 이것은 컬럼패밀리안에 있는 키입니다
        // 이 로우는 무한한 컬럼들을 가질 수 있습니다
        username: "phatduckk",
        email: "phatduckk@example.com",
        phone: "(900) 976-6666"
    }, // end row
    ieure: {   // 이것은 또다른 컬럼패밀리안의 키입니다
        // 또다른 이 로우 역시 무한한 컬럼들을 가질 수 있습니다
        username: "ieure",
        email: "ieure@example.com",
        phone: "(888) 555-1212"
        age: "66",
        gender: "undecided"
    },
}

위의 모습은 마치 자바의 HashMap이나 Objective-C의 Dictionary 또는 일종의 배열을 생각하게 만듭니다. 여기서 또한 느껴야 할점은 여기에는 그어떤 스키마도 존재하지 않는다는 것입니다. 로우들은 미리 정의된 컬럼들의 리스트를 가지지 않습니다. 위의 예제에서 알 수 있듯이 ieure의 경우에는 age와 gender라는 값을 추가로 가지고 있습니다. 이것은 100% 유연합니다. 어떤 로우는 2000개의 컬럼을 가지고 있고 어떤 컬럼은 단지 2개의 컬럼을 가지고 있을수도 있습니다. 하나의 로우는 하나의 컬럼을 가지고 있어야만 합니다. 이것이 카산드라의 schema-less 관점입니다.

컬럼패밀리는 Super가 될 수 있습니다.
이제 컬럼패밀리의 Standard와 Super타입에 대해 알아볼 시간입니다. 지금까지 경험한 컬럼패밀리는 Standard 타입입니다. Standard타입이라는것은 모든 로우들이 일반적인 컬럼들의 집합 Map을 가짐을 의미합니다. 이것은 슈퍼컬럼이 존재하지 않음을 의미합니다.

컬럼패밀리의 타입이 Super가 된다는것은 쉽게 생각하면 Standard의 반대로 생각해 보면 됩니다. 각각의 로우는 슈퍼컬럼의 집합인 Map을 가지게 됩니다. 슈퍼컬럼에 대해서는 위에서 언급을 했으니 자세한 내용은 넘어가도록 하겠습니다.

AddressBook = { // Super타입의 컬럼패밀리입니다
    phatduckk: {    // 슈퍼컬럼패밀리안의 키입니다
        // 이곳에는 친구들의 주소록정보가 있습니다

        // 이 로우에는 무한히 많은 슈퍼컬럼을 가질 수 있습니다
        // 로우의 키는 슈퍼컬럼의 이름이 됩니다
        // 각각의 슈퍼컬럼들은 주소록 데이터가 됩니다
        friend1: {street: "8th street", zip: "90210", city: "Beverley Hills", state: "CA"},
        John: {street: "Howard street", zip: "94404", city: "FC", state: "CA"},
        Kim: {street: "X street", zip: "87876", city: "Balls", state: "VA"},
        Tod: {street: "Jerry street", zip: "54556", city: "Cartoon", state: "CO"},
        Bob: {street: "Q Blvd", zip: "24252", city: "Nowhere", state: "MN"},
        ...
        // 무한한 숫자의 슈퍼컬럼을 가질 수 있습니다
    }, // 로우 끝
    ieure: {     // 또다른 슈퍼컬럼패밀리안의 키입니다
        // ieure를 위한 주소록 정보의 전체가 있습니다
        joey: {street: "A ave", zip: "55485", city: "Hell", state: "NV"},
        William: {street: "Armpit Dr", zip: "93301", city: "Bakersfield", state: "CA"},
    },
}

키스페이스(Keyspace)
키스페이스는 데이터의 그룹의 가장 바깥쪽에 위치하는 개념입니다. 모든 컬럼패밀리가 하나의 키스페이스 안에 포함됩니다. 키스페이스는 일반적으로 어플리케이션의 이름과 동일합니다. 키스페이스는 다수의 컬럼패밀리를 가질 수 있음을 알 수 있었습니다. 하지만 이것이 각각의 컬럼패밀리들간에 어떠한 관계를 형성하는것은 아닙니다. 이것은 MySQL의 테이블(Table)과 같은 개념이 아닙니다. 컬럼패밀리들을 JOIN할수도 없습니다. ColumnFamily_1이 A라는 로우값을 가진다고 해서 ColumnFamily_2도 가질것이라는것을 의미하지는 않습니다.

3. 정렬

지금까지 다양한 데이터가 어떤식으로 저장되는지에 대해 알아보았습니다. 이제 중요하게 알아보아야 할 요소로는 정렬이 있을것 같습니다. 카산드라는 SQL과 같은 쿼리를 통해 데이터를 가져오는 DB가 아닙니다. 어떻게 데이터를 정렬해서 원하는 데이터만을 가져오는 방식을 특정 짓기는 어렵습니다. 데이터는 클러스터에 삽입되는 그 순간부터 정렬된 채로 저장이 됩니다. 그리고 영원히 정렬된채로 존재하게 됩니다. 이것은 읽기시에 가공할만한 속도의 향상을 가져다 줍니다. 하지만 이러한 데이터 접근 패턴에 맞게 데이터모델을 잘 설계하는것이 중요합니다.

컬럼은 그들을 포함하고 있는 로우안에서 컬럼의 이름으로 정렬이 됩니다. 이것은 매우 중요합니다. 컬럼패밀리의 CompareWith옵션에 의해 정렬에 대한 규칙도 달라지게 됩니다. 정렬을 위해서는 다음과 같은 방식이 제공됩니다.

BytesType, UTF8Type, LexicalUUIDType, TimeUUIDType, AsciiType, LongType

각각의 옵션들은 컬럼의 이름들을 어떻게 다른 데이터로 식별할 수 있는지에 대한 가이드라인을 제시해 줍니다. 예를 들자면 LongType의 경우에는 컬럼의 이름이 64비트 Long으로 이루어지게 됩니다. 다음의 예시를 통해 이것이 무엇을 의미하는지 알아보도록 합시다.

// 로우안의 각각의 컬럼들이 정렬되지 않은채로 데이터가 보관되어있습니다
// 카산드라는 절대로 정렬되지 않은 상태로 데이터를 보관하지 않습니다.
// 이것은 단지 예제일뿐입니다.
{name: 123, value: "hello there"},
{name: 832416, value: "kjjkbcjkcbbd"},
{name: 3, value: "101010101010"},
{name: 976, value: "kjjkbcjkcbbd"}[/code]
이제 LongType으로 설정을 할 경우에 컬럼들이 어떻게 정렬된 채로 보관이 되는지 알아봅시다.
[code]<ColumnFamily CompareWith="LongType" Name="CF_NAME_HERE"/>

// 각각의 컬럼의 이름들이 64bit Long으로 처리되었습니다
// 결과적으로 숫자로 인식을 하여 정렬이 되었습니다
{name: 3, value: "101010101010"},
{name: 123, value: "hello there"},
{name: 976, value: "kjjkbcjkcbbd"},
{name: 832416, value: "kjjkbcjkcbbd"}

위의 예시에서 알 수 있듯이 컬럼들의 이름은 64bit Long으로서 서로 값을 비교하여 정렬 되었습니다. CompareWith옵션을 바꿔봄으로써 이같은 결과와 다른 결과를 볼 수 있습니다. UTF8Type으로 정렬을 할 경우에 다음과 같은 정렬 결과를 보여줍니다.

<ColumnFamily CompareWith="UTF8Type" Name="CF_NAME_HERE"/>

// 각각의 컬럼 이름들이 UTF8문자열로 처리되었습니다
{name: 123, value: "hello there"},
{name: 3, value: "101010101010"},
{name: 832416, value: "kjjkbcjkcbbd"},
{name: 976, value: "kjjkbcjkcbbd"}

결과가 완벽하게 다른것을 알 수 있습니다.  이러한 정렬의 법칙은 슈퍼컬럼에게도 영향을 미칩니다. 하지만 이렇게 정렬된 슈퍼컬럼들안의 로우들 역시도 어떻 규칙으로 정렬을 할지를 설정할 수 있습니다. 각각의 슈퍼컬럼들 안의 컬럼들의 정렬은 CompareSubcolumnsWith의 값으로 결정할 수 있습니다.

// 2개의 슈퍼컬럼을 가지고 있습니다
// 현재 랜덤한 정렬상태를 가지고 있습니다

{ // 첫번째 슈퍼컬럼
  name: "workAddress",
  value: {
      street: {name: "street", value: "1234 x street"},
      city: {name: "city", value: "san francisco"},
      zip: {name: "zip", value: "94107"}
  }
},
{ // 또다른 슈퍼컬럼
  name: "homeAddress",
  value: {
      street: {name: "street", value: "1234 x street"},
      city: {name: "city", value: "san francisco"},
      zip: {name: "zip", value: "94107"}
  }
}

위의 데이터를 가지고 CompareSubcolumnsWithCompareWith옵션을 둘다 UTF8Type으로 변경해 보았을 경우 다음과 같은 결과를 보이게 됩니다.

{
    {
        // 이 로우가 첫번째 위치로 정렬되었습니다
        name: "homeAddress",

        // 슈퍼컬럼안의 컬럼들 역시 정렬되었습니다
        value: {
            city: {name: "city", value: "san francisco"},
            street: {name: "street", value: "1234 x street"},
            zip: {name: "zip", value: "94107"}
        }
    },
    name: "workAddress",
    value: {
        // 슈퍼컬럼안의 컬럼들 역시 정렬되었습니다
        city: {name: "city", value: "san francisco"},
        street: {name: "street", value: "1234 x street"},
        zip: {name: "zip", value: "94107"}
    }
}

위의 예제에서 알 수 있듯이 두개의 옵션을 가지고 다양한 형태로 데이터를 가져올 수 있습니다. 잊지 마셔야 할점은 CompareSubcolumnsWith은 슈퍼컬럼이 존재하는 즉 컬럼패밀리의 타입이 Super일 경우에나 사용할 수 있다는 점입니다. 설계상에 적절히 적용하시면 될듯합니다.