2014-09-26 4 views
3

Учитывая, что Datomic does not support pagination я задаюсь вопросом, как эффективно поддерживать такой запрос:Эффективного 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 кажется дико неэффективным. Кроме того: что, если я захочу взять 20M из своих 30M-объектов и фильтровать их через re-find?

Datomic документы говорят о том, как выполняются запросы локально, но я пытался делать в памяти преобразования на множестве 52913 лиц (предоставленных, они полностью touch ред), и это занимает ~ 5 секунд. Представьте себе, насколько это плохо было бы в миллионах или десятках миллионов.

ответ

1

(Только мозговой штурм, здесь)

Прежде всего, если вы когда-либо с помощью регулярных выражений, вы можете рассмотреть полнотекстовый индекс на: истории/тела, так что вы можете сделать:

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

(Примечание: вы не можете изменить :db/fulltext true/false на существующую схему сущностей)

Сортировка - это то, что вам нужно делать вне запроса. Но в зависимости от ваших данных вы можете ограничить свой запрос на одну «страницу», а затем применить свой предикат только к этим объектам.

Например, если бы мы только постраничный :history объектов по автоинкрементному :history/id, то мы заранее знаем, что «Page 3» является :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))) 

Но, конечно же, проблема заключается в том, что сдерживающий постраничного набор, как правило, на основе упорядочения вы не знаете заранее, так что это не очень полезно.

+0

Спасибо. Я проработаю это, когда у меня будет шанс, похоже, хорошее начало. – devth