Datomic - 选择某些属性中具有最高值的实体

时间:2014-12-01 04:26:00

标签: search max datomic

假设我有一个电影列表,我可以这样做:

[:find ?year ?title ?rating
 :where
 [?Movie :movie/year ?year  ]
 [?Movie :movie/year ?title ]
 [?Movie :movie/year ?rating]]

如何进一步限制此选项才能获得评分最高的电影?我觉得我想要像...那样的东西。

[:find ?year ?title ?rating
 :where
 [?Movie :movie/year ?year  ]
 [?Movie :movie/year ?title ]
 [?Movie :movie/year ?rating]
 [(= ?rating (max ?rating)  ]]

但显然那不会做我想要的事情=)提示?

1 个答案:

答案 0 :(得分:4)

在Datomic中用两个查询做这种事情是可以的。让对等体在本地缓存数据库意味着在一个查询中完成尽可能多的工作的压力可以减轻一些。

[:find (max ?year) .
 :where [?m :movie/year ?year]]

其次是:

[:find ?maxyear ?title ?rating
 :in $ ?maxyear
 :where [?m :movie/year ?maxyear]
        [?m :movie/title ?title]
        [?m :movie/rating ?rating]]

没关系。 Clojure中的链式查询可能如下所示:

(let [db (d/db conn)]
  (->>
    (d/q '[:find (max ?year) .
           :where [?m :movie/year ?year]]
         db)
    (d/q '[:find ?maxyear ?title ?rating
           :in $ ?maxyear
           :where [?m :movie/year ?maxyear]
                  [?m :movie/title ?title]
                  [?m :movie/rating ?rating]]
         db)))

请注意,我们只在let绑定中获取连接的db值。它 可以使用集合返回函数来获得你提到的带有正确约束的结果,但是这可能不会像你期望的那样 - 就像这个获得最新Beatles版本的例子一样:

(d/q '[:find (max ?tuple)
       :where [?e :artist/name "The Beatles"]
              [?a :release/artists ?e]
              [?a :release/year ?y]
              [?a :release/name ?n]
              [(vector ?y ?n) ?tuple]]
      (d/db conn))

这取决于第一个元素的隐式排序,但它对多个最大值的行为如何?这将返回:

[[[2011 "Love"]]]

但是没有最大值,我们可以看到由max拉出的那个并不是唯一的:

[[2011 "1"]] [[2011 "Love"]]

如果你知道有多少期待,你可以设置,例如:

:find (max 2 ?tuple)

但这会让我们走上最好避免的道路。对于大多数情况,更喜欢简单,更健壮的组合查询的情况是有意义的。