Datomic中的SQL“limit”子句的等价物

时间:2014-11-27 03:22:48

标签: clojure datomic

标题说明了一切,但是说我有一个简单的查询如下:

(q '[:find ?c ?n :where [?c :my-thing/its-attribute ?n]]
   (d/db conn))

针对类似

的架构
[{:db/id (d/tempid :db.part/db)
  :db/ident :my-thing/its-attribute
  :db/valueType :db.type/string
  :db/doc "My thing's attribute"
  :db/cardinality :db.cardinality/one
  :db.install/_attribute :db.part/db}]

如果查询匹配所有内容(例如,100M条目),则返回的结果将很大。如果我只想要其中一些,那么最好的方法是什么?

6 个答案:

答案 0 :(得分:5)

两个随机名称使用rand(重复容忍)和样本(仅限不同)

(d/q '[:find [(rand 2 ?name) (sample 2 ?name)]
       :where [_ :artist/name ?name]]
     db)

此示例来自day-of-datomic github repo。

答案 1 :(得分:4)

对于"所有属性和值对的简单情况,排序",使用with seek-datoms是最佳选择。以下示例使用mbrainz示例数据库:

var pcnt = (this.y / (chartt.series[0].yData + chartt.series[1].yData) * 100);

并返回:

(def conn (d/connect "datomic:sql://mbrainz-1968-1973?jdbc:postgresql://localhost:5432/datomic?user=datomic&password=datomic")) (->> (d/seek-datoms (d/db conn) :avet :artist/sortName "Bea") (take 20))

当然,您可以映射一个用于美化输出的fn或添加更多属性等,例如在此示例中:


(#datom[17592186050196 81 "Beach Boys, The" 13194139539089 true]
 #datom[17592186047857 81 "Beatles, The" 13194139536749 true]
 #datom[17592186048553 81 "Beau Brummels, The" 13194139537425 true]
 #datom[17592186049043 81 "Beaver & Krause" 13194139537919 true]
 #datom[17592186046205 81 "Beaver, Paul" 13194139535085 true]
 #datom[17592186046692 81 "Beck, Bogert & Appice" 13194139535579 true]
 #datom[17592186046886 81 "Beck, Jeff" 13194139535761 true]
 #datom[17592186047111 81 "Beck, Jeff Group" 13194139535995 true]
 #datom[17592186046486 81 "Bedford, David" 13194139535371 true]
 #datom[17592186046992 81 "Bee Gees" 13194139535865 true]
 #datom[17592186045876 81 "Beethoven, Ludwig van" 13194139534747 true]
 #datom[17592186048427 81 "Beggars Opera" 13194139537321 true]
 #datom[17592186047091 81 "Beginning of the End, The" 13194139535969 true]
 #datom[17592186045945 81 "Belafonte, Harry" 13194139534825 true]
 #datom[17592186047485 81 "Bell, Archie & Drells, The" 13194139536359 true]
 #datom[17592186045915 81 "Bell, Carey" 13194139534799 true]
 #datom[17592186046324 81 "Bell, Vinnie" 13194139535215 true]
 #datom[17592186047164 81 "Bell, William" 13194139536047 true]
 #datom[17592186047652 81 "Belle, Marie-Paule" 13194139536541 true]
 #datom[17592186046496 81 "Bellou, Sotiria" 13194139535371 true])

返回:

(let [db (d/db conn)] (->> (d/seek-datoms db :avet :artist/sortName "Bea") (take 20) (map #(merge {:artist/name (:v %) :artist/type (-> (d/pull db [{:artist/type [:db/ident]}] (:e %)) :artist/type :db/ident)}))))

注意:要将 ({:artist/name "Beach Boys, The" :artist/type :artist.type/group} {:artist/name "Beatles, The" :artist/type :artist.type/group} {:artist/name "Beau Brummels, The" :artist/type :artist.type/group} {:artist/name "Beaver & Krause" :artist/type :artist.type/group} {:artist/name "Beaver, Paul" :artist/type :artist.type/person} {:artist/name "Beck, Bogert & Appice" :artist/type :artist.type/group} {:artist/name "Beck, Jeff" :artist/type :artist.type/person} {:artist/name "Beck, Jeff Group" :artist/type :artist.type/group} {:artist/name "Bedford, David" :artist/type :artist.type/person} {:artist/name "Bee Gees" :artist/type :artist.type/group} {:artist/name "Beethoven, Ludwig van" :artist/type :artist.type/person} {:artist/name "Beggars Opera" :artist/type :artist.type/group} {:artist/name "Beginning of the End, The" :artist/type :artist.type/group} {:artist/name "Belafonte, Harry" :artist/type :artist.type/person} {:artist/name "Bell, Archie & Drells, The" :artist/type :artist.type/group} {:artist/name "Bell, Carey" :artist/type :artist.type/person} {:artist/name "Bell, Vinnie" :artist/type :artist.type/person} {:artist/name "Bell, William" :artist/type :artist.type/person} {:artist/name "Belle, Marie-Paule" :artist/type :artist.type/person} {:artist/name "Bellou, Sotiria" :artist/type :artist.type/person}) seek-datomsdatoms一起使用,必须将相关属性编入索引。

答案 2 :(得分:1)

您是否尝试过使用get-some

来自:http://docs.datomic.com/query.html

  

GET-一些

     

get-some函数接受数据库,实体和一个或多个   基数 - 一个属性,返回实体id和的元组   实体拥有的第一个属性的值。

[(get-some $ ?person :person/customer-id :person/email) ?identifier]

- 编辑以回复评论 -

您还可以尝试创建一个选择低于特定数字的实体的查询。

user> (defn example-take-query [n]
        (into '[:find ?e :where [?e :age ?a]]
              [[`(~'> ~n ~'?e)]]))
#'user/example-take-query
user> (example-take-query 3)
[:find ?e :where [?e :age ?a] [(> 3 ?e)]]
user> (example-take-query 10)
[:find ?e :where [?e :age ?a] [(> 10 ?e)]]

答案 3 :(得分:1)

这个答案有点像@adamneilson的汇编以及对原始问题的评论。我试图完成与OP相同的事情,但是我不能在这里找到答案,所以希望这对某人有所帮助。

我的用例是用分页来获取100k记录。简单地使用take / drop是绝对不可行的,因为它需要很长时间(几十秒)。

我的解决方法是首先获取所需的实体ID,对该集合执行take / drop,然后使用entity对其进行映射。这是我的最终代码:

(defn eid->entity
  [eid]
  (into {} (d/touch (d/entity (d/db (get-conn)) eid))))

(defn find-eids
  [attr value limit offset]
  (let [query '[:find ?eid
                :in $ ?attr ?value
                :where [?eid ?attr ?value]]
        db (d/db (get-conn))
        result (drop offset (sort (d/q query db attr value)))]
    (map first (take limit result))))

(map eid->entity (find-eids :attr-name "value" 10 10)

这对我训练有素的大脑感觉非常错误,但我认为这是数据方式。并且它的速度并不是非常慢 - 对于10万条记录大约500毫秒,这对我来说已经足够了。

答案 4 :(得分:1)

在使用查询映射时,可以使用键:limit来实现SQL“ limit”子句的等效功能。

 (d/q {:query '[:find ?c ?n :where [?c :my-thing/its-attribute ?n]] 
       :offset 1
       :limit 10
       :args [(d/db conn)]})

您可以在datomic客户端api文档中阅读有关此内容的更多信息:

https://docs.datomic.com/client-api/datomic.client.api.html

或关于查询映射语法:

https://docs.datomic.com/on-prem/query.html#timeout

答案 5 :(得分:0)

我有一个类似的需求,一段时间后为一个集合组合了SystemUser的clojure MySql 方法:

context.SystemUsers.Select(u => new SystemUser
{
    Username = u.Username,
    Type = u.Type
});

repl的简单示例用法:

LIMIT

不确定它是否完全回答了您的问题,但可能会有所帮助。