[220416] Datomic 1 (Data Model) - 나홀로 발번역

Table of Contents

1 소개

2 Datomic Data Model

Datomic은 datoms 라고 불리는, 원자적이며(atom) 불변인 정보(사건)들의 집합이다. 데이터베이스에 테이블이 존재하지 않는다. 대신 유저가 정의한 universal schema 가 존재한다.

Datomic의 datalog queries 는 여러 접근 패턴을 지원하기위해 여러개의 인덱스를 사용한다. 이 인덱스는 identity and uniqueness , indelible time model, lookup refs 를 지원한다.

3 Database

Datomic에서 database value는 datoms 의 집합이다. 이것을 종종 database, db 라고 부르기도 함. db 특정 시점에의 불변값이며 절대 변경되지 않는다. 동일한 db 에서 여러번의 여러 쿼리를 사용하면, 단일 시점에 동일한 데이를 기반으로 동작한다.

4 Datoms

datom 은 불변원자사건(fact)이다. 이걸로 entiry, attribute, value, transaction 간의 관계추가, 철회 등을 나타낸다. datom 은 5개의 튜플로 분류된다.

  • an entity id (E)
  • an attribute (A)
  • a value for the attribute (V)
  • a transaction id (Tx)
  • a boolean (Op) indicating whether the datom is being added or retracted

5 Example Datom

type value
E 42
A :user/favorite-color
V :blue
Tx 1234
Op true

6 Entity

Entity는 datoms 의 집합을 말한다. 이 집합은 모두 동일한 E(entity id) 를 가진다.

7 Example Entity

E A V Tx Op
42 :user/favorite-color :blue 1234 true
42 :user/first-name "John" 1234 true
42 :user/last-name "Doe" 1234 true
42 :user/favorite-color :green 4567 true
42 :user/favorite-color :blue 4567 false

8 Point-In-Time Entity Example

엔티티의 point-in-time(특정시점부터, as-of) view 는 특정 Tx 시점에 Optrue 인 데이터만 고려한다. 위 예제에서 :blue 가 4567부터는 선호하지 않음. 그러므로 4567부터 point-in-time view는 아래와 같다.

E A V Tx Op
42 :user/first-name "John" 1234 true
42 :user/last-name "Doe" 1234 true
42 :user/favorite-color :green 4567 true

9 Map View Example

point-in-time view 특정시점 뷰를 볼 때 Tx , Op 를 생략하고 3-튜플로만 보면 보기 편리할 수 있다.

E A V Tx Op
42 :user/first-name "John" 1234 true
42 :user/last-name "Doe" 1234 true
42 :user/favorite-color :green 4567 true

이 3-튜플 뷰는 프로그래밍 언어 객체와 아주 유사하다. E는 thisself 과 유사하다. 한번 맵처럼 보자. E:db/id 로 대체하자.

{:db/id 42
 :user/favorite-color :green
 :user/first-name "John"
 :user/last-name "Doe"}

10 Universal schema

RDB에선, 엔티티가 가질 수 있는 속성(열)을 열거한 테이블 스키마를 미리 세팅해야 한다. Datomic에서는 개별 attribute의 속성들(properties)만 지정하면 된다. 모든 엔티티는 모든 attribute를 가질 수 있습니다. 왜냐하면 모든 datoms 는 단일 관계의 일부(part of a single relation)이기 때문이다. 이것을 universal schema라고합니다.

예를 들어, Datomic database에 inventory를 저장한다고 해보자. 모든 inventroy 아이템들은 unique한 문자열 id가 필요하므로, :inv/id attribute 를 생성한다. In addition, you create other named attributes, specifying the types and cardinalities of each. 더해서, 다른 attribute에 이름을 지어놓고, type과 cardinality를 특정한다. 이제 database에 다양한 inventory 아이템들을 저장할 수 있다, 각각 다른 attribute로, 아래 테이블을 보자.

E A V
7 :inv/id "SKU-1234"
7 :inv/color :green
8 :inv/id "SKU-5678"
8 :inv/watts 60000
8 :doc/url "http:…"

:inv/id를 제외한 엔티티 7과 8은 완전히 분리된 attribute를 가진다.

11 Defining Schema

각 Datamic database는 schema를 가진다. schema는 attribute의 종류(kind)와 집합(set)을 설명한다. 이 attribute는 당신의 domain entities와 연결될 수 있다.

스키마는 속성 자체의 특성만 정의한다. 어떤 attribute를 어떤 entity에 연결할 수 있는지는 정의하지않는다. 어떤 attribute를 적용할지는 우리 어플리케이션에서 결정한다.

이것은 애플리케이션이 시간이 지남에 따라 진화할 수 있는 큰 자유도를 제공한다. (스키마가 자유롭게 바뀔 수 있구나…) 예를들어, person을 entity로 모델링 할 때 어플리케이션은 이 person은 미리 종업원인지 고객인지 미리 결정할 필요가 없다. 고객속성과 직원속성의 조합을 동일한 엔터티에 연결할 수 있다. 애플리케이션은 적절한 속성의 존재를 찾는 것만으로 엔터티가 특정 추상화, 고객 또는 직원을 나타내는지 여부를 결정할 수 있다.

Datomic에 두 종류의 attribute가 있다.

  • Domain attributes : 도메인 데이터 측면에서 설명. domain attribute는 domain entity 데이터를 설명.
  • Schema attributes : 스키마 자체 측면에서 설명. schema attribute는 built-in 이고 확장될 수 없다. schema attribute로 domain attribute를 정의.

12 Time Model

Datomic 시간 모델은 트랜잭션이 기록될 때 자동으로 적용되어 다음 속성이 유지되도록 합니다.

  • 모든 트랜잭션은 데이터베이스 내에서 고유한 ID가 할당된다.
  • 트랜잭션은 완전히 직렬화되고, 트랜잭션 ID는 시간이 지남에 따라 증가하므로 모든 트랜잭션ID는 순서가 있다.
  • 모든 데이터에는 해당 데이터 추가 트랜잭션 ID가 포함된다. 따라서 트랜잭션 ID는 모.든. 데이터의 전체 순서 역할도 함.
  • 트랜잭션 ID는 그 자체로 엔티티 -> 이를 설명하는 데이터를 가질 수 있다. Datomic은 모든 트랜잭에 :db/txInstant 를 할당하여, 모든 datom 은 추가된 시간 wall clock time 을 볼 수 있다.
  • 트랜잭션은 다른 속성(attribute)를 가진다. 예를들어 시스템은 각 트랜잭션과 관련된 도메인별 출처정보를 기록할 수 있다.

예를들어, 한 트랜잭션 내 inventory database의 item의 개수를 설정하고, 이 개수를 나중에 업데이트 한다고 상상해보자. item 수 외에도 Datomic은 변경을 수행하는 트랜잭션, 변경이 발생한 시간 및 포함하기로 선택한 추가 출처 정보도 기록함. 이것들은 오류가 발생한 트랜잭션을 고치는 특정 트랜잭션을 기록하는데 사용할 수도 있음.

13 Time Model

아래의 예시는 Tx 가 트랜잭션의 글로벌 순서의 역할을 하는 모습을 보여줌. 또한 커스텀 속성을 사용하여 트랜잭션에 감사(Audit) 정보를 추가하는 방법도 보여줌.

:correction/forTx 1235Tx 1234 에 기록된 실수(mistake)를 수정하고 있음을 보여줌. ("Dewey" 에서 "Trunman"으로)

E A V Tx Op
42 :election/winner "Dewey" 1234 true
42 :election/winner "Dewey" 1234 false
42 :election/winner "Trunman" 1235 true
1235 :correction/for 1234 1235 true

Datomic의 시간모델을 사용하면 특정 시점의 '현재(as of)' 데이터를 완전히 복구할 수 있으며 둘 이상의 시점 간의 차이를 확인하는 쿼리도 허용한다.

14 Identity and Uniqueness

Datomic은 identity와 uniqueness를 지원하기 위해 몇가지 도구를 제공함.

  1. datom 을 생성할 때, 자동으로 entity id 라는 database-unique number를 datom 에 할당한다.
  2. 빌트인 :db/ident 속성(attribute)은 programmatic names에 이용될 수 있다.
  3. 빌트인 :db/unique 속성은 언제든지 추가할 수 있다. 기존 속성의 uniqueness properties 들 또한 언제든지 바뀔 수 있다. (uniqueness properties가 데이터에 유효한 경우에만) :db/unique 속성은 다음에 사용할 수 있다.
    • :db.unique/identity 를 사용하면 트랜잭션이 엔티티ID 대신 도메인 개념으로 작업할 수 있다. 예를들어, 기본 연락처에 이메일 또는 SKU번호는 :db.unique/identity 속성으로 모델링 할 수 있다.
    • :db.unique/value 는 식별키(자)의 단일보유자(single holder)임을 강제한다.
  4. :db.type/uuid 값 유형은 전역 고유 식별자에 효율적입니다.
  5. Lookup-refs는 고유한 속성에 대한 조회를 속성-값 쌍으로 나타낸다.

entity identifier는 Datomic이 엔티티를 고유하게 식별할 수 있는 세 가지 방법 중 하나를 말함.

  • an entity id (:db/id)
  • an ident (:db/ident)
  • a lookup ref.

특별히 지정하지 않으면 Datomic API는 이러한 종류의 entity identifier를 인자로 받는다.

15 Lookup Refs

많은 데이터베이스에서 엔티티는 이메일, 주문번호 같은 고유한 식별자를 갖습니다. 어플리케이션은 종종 이런 외부키를 기반으로 엔티티를 검색한다. 쿼리로 이러한 작업을 할 수 있지만, lookup ref 가 더 쉽다. lookup ref 는 attribute-identifier-value pair를 말함. 이 pair로 주어진 unique attribute value(고유 식별값)으로 엔티티를 식별한다.

예를들어:

[:person/email "joe@example.com"]

위 코드는 :person/email 의 값 "joe@example.com"으로 엔티티를 식별한다. lookup ref 는 pull API를 사용하여 엔티티를 조회할 때 사용할 수 있다. 혹은 datom API를 사용하여 datom을 조회할 수도 있다. 쿼리본문에서는 사용할 수 없으며, 대신 datalog clauses를 사하라.

lookup ref 를 사용하여 추가 조회 코드를 피하면서, 트랜잭션의 기존 엔티티를 참조할 수 있다.

{:db/id        [:person/email "joe@example.com"]
 :person/loves :pizza}

이 트랜잭션은 :person/email 가 "joe@example.com" 이며 피자를 좋아하는 엔티티라고 주장한다.(assert)

Lookup refs 는 다음과 같은 제한이 있다.

  • 지정된 속성은 :db.unique/value 또는 :db.unique/identity 로 정의되어야함.
  • 트랜잭션에서 사용될 때 lookup ref 는 트랜잭션이 처리되기 전에 존재하는 것처럼 지정된 속성의 인덱스에 대해 평가됩니다. 따라서 [lookup ref]를 사용하여 동일한 트랜잭션에서 정의되는 엔티티를 조회할 수 없습니다. (트랜잭션이 처리되기 전에 존재하는 것처럼 하기 때문)
  • lookup ref 는 매개변수화된 쿼리(parameterized query)에 대한 입력으로 사용할 수 있지만 쿼리 본문에는 사용할 수 없다.

16 Indelible(지울 수 없는) and Chronological(시간순)

Datomic은 지울 수 없고 시간순이다. 정보는 시간이 지남에 따라 축적되고 변화는 오래된 것을 수정하거나 제거하는 것이 아니라 새로운 것을 축적함으써 나타난다. 예를들어, "제거"는 무언가를 제거하는 것이 아니라 "철회(retraction)"를 추가함으로써 발생한다.

이것은 CRUD(Create/Read/Update/Delete) 패러다임과 완전히 대조된다.

CRUD Datomic
Create Assert
Read Read
Update Accumulate
Delete Retract
  • Assertion는 사실에 대한 세밀한 서술이다.
  • Read는 항상 특정 시점에서 변경할 수 없는 데이터베이스 값에 대해 수행된다.
  • Time은 ACID트랜잭션에 의해 데이터베이스에서 전역적으로 정렬된다.
  • 새로운 트랜잭션은 새로운 데이터를 축적만 한다. 존재하는 datoms은 절대 변하지 않는다.
  • Retraction은 나중에 어떤 시점의 assertion이 더이상 유지되지 않음을 말한다. 기존 assertion은 변경되지 않는다.

"indelible"과 "chronological"라는 용어는 구현전략인 "append-only" 의 반대되는 의미론적 특정을 묘사한다. Datomic은 "append-only"가 아니다. 그리고 "append-only system"과 관련된 성능 특정이 없다.

Author: Younghwan Nam

Created: 2024-04-16 Tue 10:05

Emacs 27.2 (Org mode 9.4.4)

Validate