多次添加相同的数据不是最理想的吗?
Is it suboptimal to add the same datoms multiple times?
我目前在我的一个项目中使用 Datomic,有一个问题困扰着我。
这是我的问题的简化版本:
- 我需要解析一小段英语句子并将完整的句子及其单词插入 Datomic。
- 包含句子列表的文件很大 (> 10 GB)
- 同一个句子可以在文件中多次出现,它们的词也可以跨句子多次出现
- 在插入过程中,将设置一个属性,将每个句子与其对应的词相关联
为了简化插入过程,我很想多次写入相同的数据(即不检查数据库中是否已存在记录)。但我担心性能影响。
- 当多次添加相同的 datoms 时,Datomic 会发生什么情况?
是否值得检查在交易之前是否已经添加了一个 datom?
有没有办法防止 Datomic 覆盖以前的 datoms(即如果记录已经存在,跳过事务)?
感谢您的帮助
你还没有到需要像这样担心预优化的时候。零售计算机商店以大约 0.05 美元/GB 的价格出售硬盘,因此您在这里谈论的是价值 50 美分的存储空间。使用 Datomic 的内置存储压缩,这将更小。索引和其他开销会增加一点总量,但仍然太小,不用担心。
与任何问题一样,最好逐步构建解决方案。所以,也许用你的前 1% 的数据做一个实验,并用最简单的算法来计时。如果速度很快,请尝试 10%。您现在可以很好地估计整个问题加载数据需要多长时间。我打赌查询数据会比加载更快。
如果您 运行 在前 1% 或 10% 之后陷入障碍,那么您可以考虑重新设计。由于您构建了一些具体的东西,因此您不得不更详细地考虑问题和解决方案。这比挥手辩论和白板设计要好得多。您现在对您的数据和可能的解决方案实施有了更多的了解。
如果事实证明最简单的解决方案无法在更大的范围内工作,那么在有了第一个解决方案的经验后,第二个解决方案将更容易设计和实施。最终解决方案 spring 很少会从您的脑海中完整形成。计划对解决方案进行反复细化对于任何重大问题都非常重要。
这本开创性的书中我最喜欢的章节之一
Fred Brooks 的 神话中的人月 题为“计划扔掉一个人”。
- What happens in Datomic when the same datoms are added multiple times?
如果您要添加具有唯一标识 (:db.unique/identity) 的 word/sentence,那么 Datomic 将只在存储中保留它的一个副本(即单个实体)
- Is it worth checking that a datom has already been added prior to the transaction?
- Is there a way to prevent Datomic from overriding previous datoms (i.e if a record already exists, skip the transaction)?*
同样,使用 :db.unique/identity,那么您不需要查询实体 ID 来检查它是否存在。
更多信息请参考here
- 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 数据库是一组有序的 datom,因此多次添加相同的 datom 是幂等的。但是,当您使用 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)}]
关于性能:
您可能根本不需要优化,但在我看来,您导入过程的潜在性能瓶颈是:
- 在 Transactor 中构建事务所花费的时间(包括唯一属性的索引查找等)
- 建立索引所花费的时间。
改进2.
:当你插入的数据是排序的时候,索引速度更快,所以一个是插入单词和句子排序。您可以使用 Unix 工具对大文件进行排序,即使它们不适合内存。所以这个过程是:
- 排序句子,插入它们(
:sentence/text
)
- 提取单词,排序,插入 (
:word/text
)
- 插入词句关系(
:sentence/words
)
改进 1.
:事实上,它可以减轻交易者对已存储的单词使用实体 ID 而不是整个单词文本的压力(这需要索引查找以确保唯一性)。一个想法是在 Peer 上执行该查找,或者通过仅对频繁词使用并行性 and/or(例如,您可以插入前 1000 个句子中的词,然后检索它们的实体 ID 并将它们保存在一个哈希图)。
就我个人而言,除非经验表明它们是必要的,否则我不会进行这些优化。
我目前在我的一个项目中使用 Datomic,有一个问题困扰着我。
这是我的问题的简化版本:
- 我需要解析一小段英语句子并将完整的句子及其单词插入 Datomic。
- 包含句子列表的文件很大 (> 10 GB)
- 同一个句子可以在文件中多次出现,它们的词也可以跨句子多次出现
- 在插入过程中,将设置一个属性,将每个句子与其对应的词相关联
为了简化插入过程,我很想多次写入相同的数据(即不检查数据库中是否已存在记录)。但我担心性能影响。
- 当多次添加相同的 datoms 时,Datomic 会发生什么情况?
是否值得检查在交易之前是否已经添加了一个 datom?
有没有办法防止 Datomic 覆盖以前的 datoms(即如果记录已经存在,跳过事务)?
感谢您的帮助
你还没有到需要像这样担心预优化的时候。零售计算机商店以大约 0.05 美元/GB 的价格出售硬盘,因此您在这里谈论的是价值 50 美分的存储空间。使用 Datomic 的内置存储压缩,这将更小。索引和其他开销会增加一点总量,但仍然太小,不用担心。
与任何问题一样,最好逐步构建解决方案。所以,也许用你的前 1% 的数据做一个实验,并用最简单的算法来计时。如果速度很快,请尝试 10%。您现在可以很好地估计整个问题加载数据需要多长时间。我打赌查询数据会比加载更快。
如果您 运行 在前 1% 或 10% 之后陷入障碍,那么您可以考虑重新设计。由于您构建了一些具体的东西,因此您不得不更详细地考虑问题和解决方案。这比挥手辩论和白板设计要好得多。您现在对您的数据和可能的解决方案实施有了更多的了解。
如果事实证明最简单的解决方案无法在更大的范围内工作,那么在有了第一个解决方案的经验后,第二个解决方案将更容易设计和实施。最终解决方案 spring 很少会从您的脑海中完整形成。计划对解决方案进行反复细化对于任何重大问题都非常重要。
这本开创性的书中我最喜欢的章节之一 Fred Brooks 的 神话中的人月 题为“计划扔掉一个人”。
- What happens in Datomic when the same datoms are added multiple times?
如果您要添加具有唯一标识 (:db.unique/identity) 的 word/sentence,那么 Datomic 将只在存储中保留它的一个副本(即单个实体)
- Is it worth checking that a datom has already been added prior to the transaction?
- Is there a way to prevent Datomic from overriding previous datoms (i.e if a record already exists, skip the transaction)?*
同样,使用 :db.unique/identity,那么您不需要查询实体 ID 来检查它是否存在。
更多信息请参考here
- 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 数据库是一组有序的 datom,因此多次添加相同的 datom 是幂等的。但是,当您使用 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)}]
关于性能:
您可能根本不需要优化,但在我看来,您导入过程的潜在性能瓶颈是:
- 在 Transactor 中构建事务所花费的时间(包括唯一属性的索引查找等)
- 建立索引所花费的时间。
改进2.
:当你插入的数据是排序的时候,索引速度更快,所以一个是插入单词和句子排序。您可以使用 Unix 工具对大文件进行排序,即使它们不适合内存。所以这个过程是:
- 排序句子,插入它们(
:sentence/text
) - 提取单词,排序,插入 (
:word/text
) - 插入词句关系(
:sentence/words
)
改进 1.
:事实上,它可以减轻交易者对已存储的单词使用实体 ID 而不是整个单词文本的压力(这需要索引查找以确保唯一性)。一个想法是在 Peer 上执行该查找,或者通过仅对频繁词使用并行性 and/or(例如,您可以插入前 1000 个句子中的词,然后检索它们的实体 ID 并将它们保存在一个哈希图)。
就我个人而言,除非经验表明它们是必要的,否则我不会进行这些优化。