clojure - 多次添加相同的数据不是最理想的吗?

标签 clojure datomic datalog

我目前在我的一个项目中使用 Datomic,一个问题困扰着我。

这是我的问题的简化版本:

  • 我需要解析一个小英语句子列表,并将完整的句子及其单词插入 Datomic。
  • 包含句子列表的文件很大(> 10 GB)
  • 同一个句子可以在文件中出现多次,他们的词也可以跨句出现多次
  • 在插入过程中,将设置一个属性,将每个句子与其对应的词相关联

为了简化插入过程,我很想多次写入相同的数据(即不检查数据库中是否已存在记录)。但我担心性能影响。

  • 多次添加相同的数据时,Datomic 中会发生什么情况?
  • 是否值得检查在交易之前是否已经添加了一个 datom?

  • 有没有办法防止 Datomic 覆盖以前的 datom(即,如果记录已经存在,则跳过事务)?

谢谢你的帮助

最佳答案

  • What happens in Datomic when the same datoms are added multiple times ?
  • Is it worth checking that a datom has already been added prior to the transaction ?

从逻辑上讲,Datomic 数据库是一组有序的数据原子,因此多次添加相同的数据原子是幂等的。但是,当您使用 tempid 声明一个数据时,您可以创建一个新数据来表示与旧数据相同的信息。这是:db/unique的地方进来了。

为确保实体不会被多次存储,您需要将 :db/unique 属性属性设置为 :db.unique/identity 以获得正确的属性.例如,如果您的模式包含 3 个属性 :word/text:sentence/text:sentence/words,那么 :word/text:sentence/text 应该是 :db.unique/identity,这会产生以下模式安装事务:

[{:db/cardinality :db.cardinality/one,
  :db/fulltext true,
  :db/index true,
  :db.install/_attribute :db.part/db,
  :db/id #db/id[:db.part/db -1000777],
  :db/ident :sentence/text,
  :db/valueType :db.type/string,
  :db/unique :db.unique/identity}
 {:db/cardinality :db.cardinality/one,
  :db/fulltext true,
  :db/index true,
  :db.install/_attribute :db.part/db,
  :db/id #db/id[:db.part/db -1000778],
  :db/ident :word/text,
  :db/valueType :db.type/string,
  :db/unique :db.unique/identity}
 {:db/cardinality :db.cardinality/many,
  :db/fulltext true,
  :db/index true,
  :db.install/_attribute :db.part/db,
  :db/id #db/id[:db.part/db -1000779],
  :db/ident :sentence/words,
  :db/valueType :db.type/ref}]

那么插入插入的事务看起来是这样的:

[{:sentence/text "Hello World!"
  :sentence/words [{:word/text "hello"
                    :db/id (d/tempid :db.part/user)}
                   {:word/text "world"
                    :db/id (d/tempid :db.part/user)}]
  :db/id (d/tempid :db.part/user)}]

关于性能:

您可能根本不需要优化,但在我看来,您的导入过程的潜在性能瓶颈是:

  1. 在 Transactor 中构建交易所花费的时间(包括唯一属性的索引查找等)
  2. 建立索引所花费的时间。

改进2.:当你插入的数据被排序时,索引速度更快,所以一个将是插入单词和句子排序。您可以使用 Unix 工具对大文件进行排序,即使它们不适合内存。所以这个过程是:

  • 排序句子,插入它们(:sentence/text)
  • 提取单词,排序,插入(:word/text)
  • 插入词句关系(:sentence/words)

改进 1.:事实上,它可以减轻交易者对已经存储的单词使用实体 ID 而不是整个单词文本的压力(这需要索引查找以确保唯一性) ).一个想法可能是通过利用并行性和/或仅针对频繁的单词在对等点上执行该查找(例如,您可以插入前 1000 个句子中的单词,然后检索它们的实体 ID 并将它们保存在 HashMap 中).

就我个人而言,除非经验表明它们是必要的,否则我不会进行这些优化。

关于clojure - 多次添加相同的数据不是最理想的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41305070/

相关文章:

clojure - 找不到 clojure/tools/logging__init.class

clojure - 哪些变量会影响 Clojure 函数?

clojure - 在提议使用新语言之前要回答的问题?

clojure - F#:类似于 Clojure 中的分区函数

clojure - 我们可以更改数据枚举还是可以向数据枚举添加任何新值?

clojure - 将Clojure Spec与Datomic实体一起使用

amazon-web-services - 由 : java. lang.ClassNotFoundException : com. amazonaws.services.dynamodbv2.model.PutItemRequest 引起

clojure - 我可以将实体及其父组件一直拉到组件树中吗?

clojure - 高效的 Datomic 查询对分页集执行过滤

prolog - Datalog、CLIPS、Prolog