2013-09-17 4 views
2

Предположим, что я один миллион статье сущности в моем внутреннем интерфейсе с инст атрибут называется дата, или один миллион игрок объекты с атрибутом INT называется пункты. Каким образом можно выбрать 10 последних статей или топ-игроков?Выбор entitites с наибольшим значением некоторого атрибута

Нужно ли мне забирать миллионы для сверстников, а затем сортировать и отбрасывать их?

ответ

1

Да, вам нужно будет получить все данные, так как нет индекса, который поможет вам здесь.

Я бы создал свой собственный «индекс» и нормализовал эти данные. У вас может быть отдельный набор из N объектов, в которых вы храните столько, сколько хотите. Вы можете начать с 10 или подумать о том, чтобы сохранить 100 для торговли некоторой (возможно, незначительной) скоростью для большей гибкости. Этот индекс может храниться на отдельном объекте «singleton», который вы добавляете как часть вашей схемы.

;; The attribute that stores the index 
{:db/id #db/id[:db.part/db] 
    :db/ident :indexed-articles 
    :db/valueType :db.type/ref 
    :db/cardinality :db.cardinality/many 
    :db.install/_attribute :db.part/db} 

;; The named index entity. 
{:db/id #db/id[:db.part/db] 
    :db/ident :articles-index} 

У вас может быть функция базы данных, которая делает это. Каждый раз, когда вы вставляете новый объект, который хотите индексировать, вызовите эту функцию.

[[:db/add tempid :article/title "Foo] 
[:db/add tempid :article/date ....] 
[:index-article tempid 10]] 

Реализация индексации статьи может выглядеть следующим образом:

{:db/id #db/id[:db.part/user] 
    :db/ident :index-article 
    :db/fn #db/fn {:lang "clojure" 
       :params [db article-id idx-size] 
       :code (concat 
         (map 
         (fn [article] 
          [:db/retract 
          (d/entid db :articles-index) 
          :indexed-articles 
          (:db/id article)]) 
         (->> (datomic.api/entity db :articles-index) 
           (sort-by (fn [] ... implement me ...)) 
           (drop (dec idx-size)))) 
         [[:db/add (d/entid db :articles-index) :indexed-articles article-id]])}} 

Отказ от ответственности: Я на самом деле не проверял эту функцию, так что, вероятно, содержит ошибки :) Основная идея заключается в том, что мы убираем любые объекты «переполнения» из набора и добавьте новый. Когда idx-size равен 10, мы хотим обеспечить, чтобы в нем было только 9 элементов, и мы добавляем в него наш новый элемент.

Теперь у вас есть сущность, которую вы можете искать по индексу,: articles-index, а 10 самых последних статей можно искать из индекса (все индексы индексируются), не вызывая полного чтения базы данных.

;; "indexed" set of articles. 
(d/entity db :articles-index) 
+0

Я считаю, Индекс AVET - именно то, что вы ищете. Прочтите ответ pete23 для дальнейшего уточнения. –

1

Я изучал это и думаю, что у меня есть немного более элегантный ответ.

Объявить свой атрибут, как индексируется с :db/index true

{:db/id #db/id[:db.part/db -1] 
:db/ident :ocelot/number 
:db/valueType :db.type/long 
:db/cardinality :db.cardinality/one 
:db/doc "An ocelot number" 
:db/index true 
:db.install/_attribute :db.part/db} 

Это гарантирует, что атрибут включается в индекс Авет.

Далее предоставляется доступ к «первой десятке», хотя и используется низкоуровневый вызов datoms.

(take-last 10 (d/datoms (db conn) :avet :ocelot/number)) 

Очевидно, что если вам нужно сделать какой-либо дальнейшей фильтрации («кто в первую десятку бомбардиров в этом клубе?»), То этот подход не будет работать, но в этот момент у вас есть гораздо меньшее количество данных в ваших руках и не нужно беспокоиться об индексировании.

Я подробно рассмотрел функции агрегации, доступные из Datalog, и у меня возникли проблемы с моей головой вокруг них - и я не уверен, что, например, max будет использовать этот индекс, а не полное сканирование данных.Аналогично, функция (index-range ...) почти наверняка использует этот индекс, но требует знать начальные и/или конечные значения.

+1

Дальнейшие исследования с большим количеством оселотов указывают на то, что это решение - мусор - 'take-last' явно просматривает весь индекс, чтобы получить последние несколько, я надеялся на большую оптимизацию. 'index-range' выглядит намного надежнее, потому что скорость поиска быстрая, но нужен начальный индекс, который в этом случае является 10-м самым высоким значением ... что нам нужно. Требуется больше исследований, но я не могу не думать, что здесь должно быть что-то ... – pete23

2

До получения обратного индекса becomes a Datomic feature, вы можете вручную определить его.

например. для: db.type/мгновенного, создать дополнительный атрибут типа: db.type/длиной, которые вы бы заправить

(- (Long/MAX_VALUE) (.getTime date)) 

и последние 10 статей могут быть извлечены с

(take 10 (d/index-range db reverse-attr nil nil)) 
Смежные вопросы