4

鉴于 Datomic不支持分页,我想知道如何有效地支持查询,例如:

取前 30 个实体:history/body,找到 :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怎么办?

Datomic 文档讨论了查询是如何在本地执行的,但我尝试对一组 52913 个实体进行内存转换(当然,它们已完全touch编辑),这需要大约 5 秒。想象一下,数百万或数以百万计的情况会有多糟糕。

4

1 回答 1

1

(这里只是头脑风暴)

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

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

(注意:您不能更改:db/fulltext true/false现有实体架构)

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

例如,如果我们只是:history通过 auto-incrementing 对实体进行分页:history/id,那么我们会事先知道“Page 3”是:history/id61 到 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)))

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

于 2014-10-07T21:23:42.937 回答