首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >慢数据记录查询

慢数据记录查询
EN

Stack Overflow用户
提问于 2016-08-09 13:51:23
回答 1查看 304关注 0票数 3

我正在使用Datascript查询一个树结构,以查找两个节点的最后一个共同祖先,并给出了名称,下面是,但它非常慢--知道为什么(或者有更好的方法)吗?

代码语言:javascript
复制
(defn lca
  "Last common ancestor"
  [db name1 name2]
  (d/q '[
          :find [(pull ?anc [:db/id :name]) ...]
          :in    $ % ?name1 ?name2
          :where
            (?node1 :name ?name1)
            (?node2 :name ?name2)
            (anc ?anc1 ?node1)
            (anc ?anc2 ?node2)
            [(not= ?anc1 ?anc2)]
            (parent ?anc ?anc1)
            (parent ?anc ?anc2)
          ]
          @db
          '[
            [ (parent ?par ?child)
              (?par :children ?child)]
            [ (anc ?par ?child)
              (?par :children ?child)]
            [ (anc ?anc ?child)
              (?par :children ?child)
              (anc ?anc ?par)]
            ]
          name1
          name2))

我最初打算使用not来排除所有比上一个普通祖先更高的祖先,但是Datascript目前不支持not,因此两个父子句。

方案是:

代码语言:javascript
复制
:children {:db/valueType :db.type/ref 
           :db/cardinality :db.cardinality/many 
           :db/index true}
:name {:db/index true}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-08-10 16:06:05

在DataScript中,递归规则不是最快的事情。因此,通过直接将parent规则内联到查询代码中,您可能可以使查询速度稍微快一点。

另一件事是,查询不是最快的事情也是DataScript。解析查询、分配中间集合、迭代它们、管理变量等都花费了相当长的时间。在两种情况下,您可以更喜欢查询而不是手动访问数据库/索引:

  1. 查询的工作速度比您自己编写的要快(例如,在处理大型关系时,查询将使用散列联接,这是手动编写非常繁琐的事情)
  2. 查询以比命令式算法更简单的方式表达您的问题。

在您的例子中,这两种情况都不是真的(您不是真正地处理关系,而是线性地遍历图)。此外,还存在一个错误:如果node1和node2有共同的直接父级,则查询将无法工作。

我建议的是通过直接访问实体来做同样的事情。实体只是索引查找,没有任何与查询相关的开销,因此在这样简单的情况下,它们应该工作得更快。

这样的东西就够了:

代码语言:javascript
复制
(defn parent [node]
  (first (:_children node)))


(defn ancestors [node]
  (->> node
       (iterate parent)
       (take-while some?)
       reverse))


(defn last-common-ancestor [db name1 name2]
  (let [node1 (d/entity db [:name name1])
        node2 (d/entity db [:name name2])]
         ;; zipping ancestor chains together
    (->> (map vector (ancestors node1) (ancestors node2))
         ;; selecting common prefix
         (take-while (fn [[ac1 ac2]] (= ac1 ac2)))
         ;; last item in common prefix is what you looking for
         (last))))
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38852696

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档