鉴于Datomic does not support pagination我想知道如何有效地支持查询,例如:
获取
:history/body
上的前30个实体,找到其实体:history/body
匹配某些正则表达式。
以下是我单独进行正则表达式匹配的方法:
{:find [?e]
:where [[?e :history/body ?body]
[(re-find #"foo.*bar$" ?body)]]}
观察:
(take ...)
,但那不与前30个实体的匹配相同。take 30
然后使用re-find
手动过滤,但如果我有30M实体,那么只需要take 30
效率极低。另外:如果我想从30M实体中取出20M并通过re-find
过滤它们会怎么样? Datomic docs讨论了如何在本地执行查询,但我尝试在一组52913个实体上进行内存中转换(授予它们,它们完全touch
ed)并且它需要~5秒。想象一下,在数百万或数百万的情况下,它有多糟糕。
答案 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)))
但是,当然,问题在于限制分页集通常是基于您事先不知道的顺序,所以这不是非常有用。