选择具有某个属性值最高的实体

时间:2013-09-17 20:53:12

标签: datomic

假设我的后端有一百万个文章实体,其中 inst 属性名为 date ,或者一百万播放器具有 int 属性的实体,名为 points 。选择10篇最新文章或得分最高的球员有什么好方法?

我是否需要将全部数百万的内容提取给对等方,然后对它们进行排序和删除?

3 个答案:

答案 0 :(得分:2)

在掌握反向索引becomes a Datomic feature之前,您可以手动定义一个。

e.g。对于:db.type / instant,创建一个类型的附加属性:db.type / long,您将填充

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

可以使用

获取最新的10篇文章
(take 10 (d/index-range db reverse-attr nil nil))

答案 1 :(得分:1)

是的,您需要获取所有数据,因为没有可以帮助您的索引。

我会创建自己的“索引”并规范化这些数据。您可以拥有一组单独的N个实体,您可以根据需要保留多个实体。您可以从10开始,或考虑存储100以交换一些(可能可忽略的)速度以获得更大的灵活性。此索引可以存储在您作为模式的一部分添加的单独“单例”实体中。

 ;; 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]]

index-article的实现可能如下所示:

 {: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个项目,并且我们将新项目添加到其中。

现在你有一个可以从index,:articles-index查找的实体,并且可以从索引中查找最近的10篇文章(所有引用都被编入索引),而不会导致完整的数据库读取。

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

答案 2 :(得分: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}

这可确保该属性包含在AVET索引中。

然后,以下内容可让您访问“前十名”,尽管使用的是低级datoms来电。

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

显然,如果你需要进行任何进一步的过滤(“谁是这个俱乐部的前十名得分手??”)那么这种方法将无法运作,但那时你的要小得多手中的数据量,不需要担心索引。

我确实深入研究了Datalog提供的聚合功能,并且无法理解它们 - 我不确定max将使用此索引而不是数据的完整扫描。类似地,(index-range ...)函数几乎肯定会使用此索引,但需要您知道开始和/或结束值。