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

标签 clojure datomic datalog

鉴于 Datomic does not support pagination我想知道如何有效地支持查询,例如:

Take the first 30 entities on :history/body, find entities whose :history/body matches some regex.

这是我单独进行正则表达式匹配的方法:

{:find [?e]
 :where [[?e :history/body ?body]
         [(re-find #"foo.*bar$" ?body)]]}

观察结果:

  1. 然后我可以从这些实体中(获取...),但这与匹配前 30 个实体相同。
  2. 我可以获取所有个实体,获取 30,然后使用重新查找手动过滤,但如果我有 30M 个实体,则获取所有他们仅仅拿 30 似乎效率极低。另外:如果我想从 30M 实体中取出 20M 并通过重新查找过滤它们,该怎么办?

Datomic 文档讨论了如何在本地执行查询,但我尝试对一组 52913 个实体进行内存中转换(当然,它们是完全touched),并且需要〜 5秒。想象一下,如果是数百万或数十百万的话,情况会有多糟糕。

最佳答案

(这里只是集思广益)

首先,如果您曾经使用过正则表达式,您可能需要考虑在 :history/body 上建立全文索引,以便您可以执行以下操作:

[(fulltext $ :history/body "foo*bar") [[?e]]]

(注意:您无法更改现有实体架构上的 :db/fulltext true/false)

排序是您必须在查询之外执行的操作。但根据您的数据,您也许能够将查询限制在单个“页面”,然后将谓词仅应用于这些实体。

例如,如果我们仅通过自动递增的 :history/id:history 实体进行分页,那么我们会事先知道“Page 3”是:历史记录/id 61 到 90。

[:find ?e
 :in $ ?min-id ?max-id
 :where
 [?e :history/id ?id]
 (<= ?min-id ?id ?max-id)
 (fulltext $ :history/body "foo*bar") [[?e]]]

也许是这样的:

(defn get-filtered-history-page [page-n match]
  (let [per-page 30
        min-id (inc (* (dec page-n) per-page))
        max-id (+ min-id per-page)]
    (d/q '[:find ?e
           :in $ ?min-id ?max-id ?match
           :where
           [?e :history/id ?id]
           [(<= ?min-id ?id ?max-id)]
           [(fulltext $ :history/body ?match) [[?e]]]]
      (get-db) min-id max-id match)))

但是,当然,问题是约束分页集通常基于您事先不知道的顺序,因此这不是很有帮助。

关于clojure - 高效的 Datomic 查询对分页集执行过滤,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26064582/

相关文章:

datomic - 如何在数据日志查询中对结果进行排序

java - Java 中可用的各种 Datalog 实现有哪些?

clojure - 如何在 clojure 中转置嵌套向量

clojure - 函数局部、自引用、惰性斐波那契数列

clojure - 如何构造与DataScript中的引用向量完全匹配的查询?

database - 更改数据的数据记录模式

security - 限制 Clojure fn 的使用

clojure - 仅计算集合中的真实值

java - 设置 Datomic 类路径函数以供 Windows 中的事务处理程序使用

windows - Datomic dev-local 可以安装在 Windows 上吗?