Datomic中的数据建模

Tob*_*olm 59 data-modeling datomic

我一直在研究Datomic,它看起来很有趣.虽然似乎有关于Datomic如何在技术上工作的非常好的信息,但我还没有看到如何考虑数据建模.

Datomic中的数据建模有哪些最佳实践?这个问题有什么好的资源吗?

bki*_*bri 128

警告Lector

由于Datomic是新的,我对它的体验有限,因此不应将此答案视为最佳实践.将此作为Datomic的介绍,为那些具有关系背景和渴望更高效数据存储的人提供.

入门

在Datomic,你为你的域数据模型的实体是具有价值属性.因为另一个参考实体可以是的的属性,你可以模拟关系之间的实体简单.

初看起来,这与传统关系数据库中的数据建模方式并没有什么不同.在SQL中,表行是实体,表的列是具有值的属性.甲关系由外键表示在表格中的一行引用主键价值另一个表行的.

这种相似性很好,因为您可以在建模域时勾画出传统的ER图.您可以像在SQL数据库中一样依赖关系,但不需要乱用外键,因为这是为您处理的.在Datomic中写入是事务性的,并且您的读取是一致的.因此,无论粒度感觉如何,您都可以将数据分成实体,依靠连接来提供更大的图像.对于许多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}
Run Code Online (Sandbox Code Playgroud)

可以推断为a Person,a Resident a Member 但不是 a Employee.

Datomic查询以Datalog表示,可以包含用您自己的语言表示的规则,引用未存储在Datomic中的数据和资源.您可以将数据库函数存储为Datomic中的第一类值.这些类似于SQL中的存储过程,但可以作为事务内部的值进行操作,也可以用您的语言编写.这两个功能都允许您以更加以域为中心的方式表达查询和更新.

最后,OO和关系世界之间的阻抗不匹配总是让我感到沮丧.使用功能性的,以数据为中心的语言(Clojure)可以帮助实现这一目标,但Datomic希望提供一种耐用的数据存储,不需要心理体操从代码桥接到存储.

例如,从Datomic获取的实体看起来像Clojure(或Java)地图.它可以传递到应用程序的更高级别,而无需转换为对象实例或通用数据结构.遍历该实体的关系将懒洋洋地从Datomic中获取相关实体.但保证它们将与原始查询一致,即使面对并发更新.这些实体看起来是嵌套在第一个实体内的普通旧地图.

这使得数据建模更加自然,而且在我看来更不用说了.

潜在的陷阱

  • 冲突的属性

    上面的例子说明了模型中的潜在缺陷.如果你以后决定这:id也是一个属性Employee怎么办?解决方案是将属性组织到命名空间中.所以你会同时拥有:member/id:employee/id.提前做这件事有助于避免以后发生冲突.

  • 属性的定义无法更改(尚未)

    一旦您将Datomic中的属性定义为特定类型,索引与否,唯一等,您将无法在以后更改.我们在ALTER TABLE ALTER COLUMN这里用SQL说法.现在,您可以使用正确的定义创建替换属性并移动现有数据.

    这可能听起来很糟糕,但事实并非如此.由于事务是序列化的,因此您可以提交一个创建新属性,将数据复制到其中,解决冲突并删除旧属性的事务.它将在不受其他事务干扰的情况下运行,并且可以利用您母语中的特定于域的逻辑来完成它.它实质上是RDBMS在发布时在幕后进行的操作ALTER TABLE,但是您可以命名规则.

  • 不要成为"糖果店里的孩子"

    灵活的架构并不意味着没有数据模型.我会建议一些前期规划,以一种理智的方式对事物进行建模,就像对待任何其他数据存储一样.在必要时,利用Datomic的灵活性,而不仅仅是因为你可以.

  • 避免存储大量不断变化的数据

    对于BLOB或不断变化的非常大的数据,Datomic不是一个好的数据存储.因为它保留了以前值的历史记录,并且还没有一种方法可以清除旧版本(尚未).这种东西几乎总是更适合像S3这样的对象存储.更新:有一种方法可以基于每个属性禁用历史记录.更新:现在还有一种方法可以删除数据 ; 但是,存储对外部对象而不是对象本身的引用可能仍然是处理BLOB的最佳方法.将此策略与使用字节数组进行比较.

资源

笔记

  1. 我的意思是行意义上的实体,而不是更恰当地描述为实体类型的表意义.
  2. 我的理解是目前支持Java和Clojure,但未来可能会支持其他JVM语言.

  • 我正在键入一个响应,但这远远优越.干得好. (5认同)
  • 这是一个非常好的概述.谢谢! (2认同)