3

假设我的后端有一百万篇文章实体,其inst属性称为date,或者有一百万个玩家实体,其int属性称为points。挑选10篇最新文章或得分最高的球员有什么好方法?

我是否需要将全部数百万美元提取给对等方,然后从他们那里分类并丢弃?

4

3 回答 3

2

在获取反向索引成为 Datomic 特性之前,您可以手动定义一个。

例如,对于 :db.type/instant,创建一个类型为 :db.type/long 的附加属性,您将使用该属性填充

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

并且可以获取最新的 10 篇文章

(take 10 (d/index-range db reverse-attr nil nil))
于 2014-05-02T14:21:31.463 回答
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 个项目,然后将新项目添加到其中。

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

;; "indexed" set of articles.
(d/entity db :articles-index)
于 2013-09-21T13:13:39.300 回答
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 ...)函数几乎肯定会使用此索引,但需要您知道开始和/或结束值。

于 2013-09-23T09:36:11.843 回答