高效的Datomic查询,用于对分页集执行过滤

时间:2014-09-26 16:55:22

标签: clojure datomic datalog

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

  

获取:history/body上的前30个实体,找到其实体   :history/body匹配某些正则表达式。

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

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

观察:

  1. 然后我可以(take ...),但那与前30个实体的匹配相同。
  2. 我可以所有实体,take 30然后使用re-find手动过滤,但如果我有30M实体,那么只需要take 30效率极低。另外:如果我想从30M实体中取出20M并通过re-find过滤它们会怎么样?
  3. Datomic docs讨论了如何在本地执行查询,但我尝试在一组52913个实体上进行内存中转换(授予它们,它们完全touch ed)并且它需要~5秒。想象一下,在数百万或数百万的情况下,它有多糟糕。

1 个答案:

答案 0 :(得分:1)

(只是头脑风暴,这里)

首先,如果你曾经使用过regexp,你可能需要考虑一个全文索引:history / body,以便你可以这样做:

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

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

排序是您在查询之外必须执行的操作。但是,根据您的数据,您可以将查询约束到单个"页面"然后将您的谓词应用于那些实体。

例如,如果我们仅通过自动递增:history:history/id个实体进行分页,那么我们事先就会知道"""是:history/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)))

但是,当然,问题在于限制分页集通常是基于您事先不知道的顺序,所以这不是非常有用。