web-dev-qa-db-ja.com

Datomicでのデータモデリング

私は Datomic を調査してきましたが、それは本当に興味深いようです。しかし、Datomicが技術的にどのように機能するかについて 非常に良い情報があるようです が、データモデリングについてどのように考えるべきかについてはあまり知りませんでした。

Datomicでのデータモデリングのベストプラクティスは何ですか?この件に関して良いリソースはありますか?

61
Tobias Furuholm

警告レクター

Datomicは新しく、私の経験は限られているので、この回答をベストプラクティスと見なすべきではありません。代わりに、これを、Datomicの紹介として、リレーショナルな背景を持ち、より生産的なデータストアを求めている人のために紹介してください。

入門

Datomicでは、ドメインデータを Entities としてモデル化し、 Values for Attributes を所有します。別の Entity への参照は、 Attribute Value にできるため、モデル化できます関係エンティティの間。

一見すると、これは従来のリレーショナルデータベースでデータをモデル化する方法とそれほど違いはありません。 SQLでは、テーブルの行は Entities であり、テーブルの列名は Attributes であり、 Values を持ちます。 Relationship は、主キーを参照する1つのテーブル行の外部キー Value で表されます Value 別のテーブル行の。

ドメインをモデリングするときに、従来のERダイアグラムをスケッチするだけでよいので、この類似性は素晴らしいです。 SQLデータベースの場合と同じようにリレーションシップに依存できますが、外部キーが処理されるため、外部キーをいじる必要はありません。 Datomicでの書き込みはトランザクションであり、読み取りは一貫しています。したがって、結合を利用して全体像を把握することで、データを適切な粒度でエンティティに分離できます。これは、更新中に有用なレベルの原子性を実現するためにBIGの非正規化エンティティを持つことが一般的である多くのNoSQLストアで失う便利さです。

この時点で、あなたは良いスタートを切っています。しかし、DatomicはSQLデータベースよりもはるかに柔軟性があります。

活用する

時間は本質的にすべてのDatomicデータの一部であるため、データの履歴をデータモデルの一部として具体的に含める必要はありません。これはおそらく、Datomicの最も話題の側面です。

Datomicでは、スキーマはSQLで必要な「長方形」に厳密に定義されていません。つまり、エンティティ 1 は、モデルを満たすために必要なあらゆる属性を持つことができます。エンティティはNULLまたはそれに適用されない属性のデフォルト値を持つ必要はありません。また、必要に応じて、特定の個々のエンティティに属性を追加できます。

したがって、時間の経過とともに個々のエンティティの形状を変更して、ドメインの変更(またはドメインの理解の変更)に対応することができます。だから何?これは、MongoDBやCouchDBなどのドキュメントストアと同じです。

違いは、Datomicを使用すると、影響を受けるすべてのエンティティに対してアトミックにスキーマの変更を実行できることです。すべてのエンティティの形状を更新するトランザクションを発行できることを意味し、任意のドメインロジックに基づいて言語で記述されています[2]、コミットされるまでリーダーに影響を与えることなく実行されます。リレーショナルストアスペースでもドキュメントストアスペースでも、この種のパワーに近いものは何も知りません。

エンティティも「単一のテーブルに住んでいる」と厳密に定義されていません。 Datomicでエンティティの「タイプ」を定義するものを決定します。明示的に選択して、モデル内のすべてのエンティティに、その「タイプ」を暗示する:table属性を持たせることができます。または、エンティティは、各タイプの属性要件を満たすだけで、任意の数の「タイプ」に準拠できます。

たとえば、モデルで次のことを義務付けることができます。

  • 人物には属性:name:ssn:dobが必要です
  • 従業員には:name:title:salaryが必要です
  • 居住者には:name:addressが必要です
  • メンバーには:id:plan:expirationが必要です

それは私のような実体を意味します:

{:name "Brian" :ssn 123-45-6789 :dob 1976-09-15 
 :address "400 South State St, Chicago, IL 60605"
 :id 42 :plan "Basic" :expiration 2012-05-01}

PersonResident、およびa MemberしかしNOTEmployee

Datomicクエリは Datalog で表され、Datomicに格納されていないデータとリソースを参照して、独自の言語で表されたルールを組み込むことができます。 Database Functions をDatomic内にファーストクラスの値として保存できます。これらはSQLのストアドプロシージャに似ていますが、トランザクション内で値として操作でき、言語でも記述できます。これらの機能の両方を使用すると、クエリと更新をよりドメイン中心の方法で表現できます。

最後に、OOとリレーショナルの世界との間の インピーダンスの不一致 は常に私を苛立たせてきました。関数型のデータ中心の言語(Clojure)を使用するとそれが容易になりますが、Datomicのように見えますコードからストレージにブリッジするための頭の体操を必要としない、耐久性のあるデータストアを提供するため。

例として、Datomicからフェッチされたエンティティは、Clojure(またはJava)マップのように見え、動作します。オブジェクトインスタンスや一般的なデータ構造に変換することなく、アプリケーションの上位レベルに渡すことができます。そのエンティティの関係をたどると、関連するエンティティがDatomicから遅延取得されます。ただし、同時更新が行われた場合でも、元のクエリと一致することが保証されます。そして、それらのエンティティは、最初のエンティティ内にネストされたプレーンな古いマップのように見えます。

これにより、データモデリングがより自然になり、私の意見では、はるかに少なくなります。

潜在的な落とし穴

  • 矛盾する属性

    上記の例は、モデルの潜在的な落とし穴を示しています。 :idEmployeeの属性であると後で決定した場合はどうなりますか?解決策は、属性を namespaces に整理することです。したがって、:member/id:employee/idの両方が存在します。これを事前に行うと、後で競合を回避するのに役立ちます。

  • 属性の定義は(まだ)変更できません

    Datomicで属性を特定のタイプ、インデックス付きかどうか、一意などとして定義したら、後で変更することはできません。ここでは、SQL用語でALTER TABLE ALTER COLUMNについて話します。とりあえず、正しい定義で置換属性を作成し、既存のデータを移動できます。

    これはひどく聞こえるかもしれませんが、そうではありません。トランザクションはシリアル化されているため、新しい属性を作成し、それにデータをコピーし、競合を解決して、古い属性を削除するトランザクションを送信できます。他のトランザクションからの干渉なしに実行され、ネイティブ言語のドメイン固有のロジックを利用して実行できます。基本的に、ALTER TABLEを発行するときにRDBMSが舞台裏で行っていることですが、ルールに名前を付けます。

  • 「お菓子屋の子供」にならないでください

    柔軟なスキーマは、データモデルがないことを意味しません。他のデータストアの場合と同じように、適切な方法で物事をモデル化するいくつかの事前計画をお勧めします。できるだけでなく、 /が必要なときに、Datomicの柔軟性を活用してください。

  • 常に変化する大容量のデータを保存しない

    Datomicは、BLOBや、絶えず変化する非常に大きなデータに適したデータストアではありません。以前の値の履歴を保持しているため そして、古いバージョンを(まだ)パージする方法はありません。この種のものは、ほとんど常にS3のようなオブジェクトストアに適しています。更新: 属性ごとに履歴を無効にする する方法があります。更新: excise data ;への方法もあります。ただし、オブジェクト自体ではなく外部オブジェクトへの参照を格納することは、BLOBを処理するための最良のアプローチである場合があります。この戦略を バイト配列 の使用と比較してください。

資源

ノート

  1. 行の意味でのエンティティを意味します。エンティティタイプとしてより適切に説明されるテーブルの意味ではありません。
  2. JavaとClojureは現在サポートされていますが、他のJVM言語も将来サポートされる可能性があると私は理解しています。
128
bkirkbri

Bkirkbriからの非常に良い答え。いくつか追加したい:

  1. 類似した「タイプ」またはスキーマではない多くのエンティティを保存する場合は、スキーマでtypeキーワードを使用します。

    
    [:db/add #db/id[:db.part/user] :db/ident :article.type/animal]
    [:db/add #db/id[:db.part/user] :db/ident :article.type/weapon]
    [:db/add #db/id[:db.part/user] :db/ident :article.type/candy]


    {:db/id #db/id[:db.part/db] :db/ident :article/type :db/valueType :db.type/ref :db/cardinality :db.cardinality/one :db/doc "The type of article" :db.install/_attribute :db.part/db}

それらを読み取るとき、クエリからエンティティIDを取得し、datomic.api/entityeidを使用して、必要に応じてタイプでディスパッチするマルチメソッドによってそれらを解析します。これは、すべての属性に対して適切なクエリを作成することが難しいためです。より複雑なスキーマで。

3
claj