Browse Source

perf: linked references

1. don't use recursive rule `block-parent`
2. using `:block/path-ref` to get both parent and children
3. run `hidden-ref?` check for refs only (not path-refs)
Tienson Qin 4 months ago
parent
commit
d4b37189a0

+ 36 - 51
deps/db/src/logseq/db/common/reference.cljs

@@ -1,14 +1,14 @@
 (ns logseq.db.common.reference
   "References"
   (:require [cljs.reader :as reader]
+            [clojure.set :as set]
             [clojure.string :as string]
             [datascript.core :as d]
             [logseq.common.log :as log]
             [logseq.db :as ldb]
             [logseq.db.common.entity-plus :as entity-plus]
             [logseq.db.common.initial-data :as common-initial-data]
-            [logseq.db.frontend.class :as db-class]
-            [logseq.db.frontend.rules :as rules]))
+            [logseq.db.frontend.class :as db-class]))
 
 (defn get-filters
   [db page]
@@ -43,50 +43,23 @@
    (for [exclude excludes]
      (list 'not [variable :block/path-refs exclude]))))
 
-(defn- filter-refs-children-query
-  [includes excludes class-ids]
-  (let [clauses (concat
-                 [;; find refs from refed block's children only
-                  '(block-parent ?b ?c)
-                  ;; find all levels of parents
-                  '(block-parent ?p ?c)]
-                 (build-include-exclude-query '?c includes excludes)
-                 (when class-ids
-                   (mapcat
-                    (fn [class-id]
-                      (map
-                       (fn [variable]
-                         (list 'not [variable :block/tags class-id]))
-                       ['?b '?p '?c]))
-                    class-ids)))]
-    (into [:find '?b '?p '?c
-           :in '$ '% '[?id ...]
-           :where
-           ['?b :block/refs '?id]]
-          clauses)))
-
 (defn- filter-refs-query
-  [includes excludes class-ids]
+  [attribute includes excludes class-ids]
   (let [clauses (concat
                  (build-include-exclude-query '?b includes excludes)
                  (for [class-id class-ids]
                    (list 'not ['?b :block/tags class-id])))]
     (into [:find '[?b ...]
-           :in '$ '% '[?id ...]
+           :in '$ '[?id ...]
            :where
-           ['?b :block/refs '?id]]
+           ['?b attribute '?id]]
           clauses)))
 
-(defn- remove-hidden-ref
-  [db page-id refs]
-  (remove (fn [block] (common-initial-data/hidden-ref? db block page-id)) refs))
-
 (defn- get-ref-pages-count
   [db id ref-blocks children-ids]
   (when (seq ref-blocks)
     (let [children (->> children-ids
-                        (map (fn [id] (d/entity db id)))
-                        (remove-hidden-ref db id))]
+                        (map (fn [id] (d/entity db id))))]
       (->> (concat (mapcat :block/path-refs ref-blocks)
                    (mapcat :block/refs children))
            frequencies
@@ -98,6 +71,22 @@
                      [(:block/title ref) size])))
            (sort-by second #(> %1 %2))))))
 
+(defn- get-block-parents-until-top-ref
+  [db id ref-id ref-block-ids *result]
+  (loop [eid ref-id
+         parents []]
+    (when eid
+      (cond
+        (contains? @*result eid)
+        (swap! *result into parents)
+
+        (contains? ref-block-ids eid)
+        (when-not (common-initial-data/hidden-ref? db (d/entity db eid) id)
+          (swap! *result into (conj parents eid)))
+        :else
+        (let [e (d/entity db eid)]
+          (recur (:db/id (:block/parent e)) (conj parents eid)))))))
+
 (defn get-linked-references
   [db id]
   (let [entity (d/entity db id)
@@ -105,27 +94,23 @@
         page-filters (get-filters db entity)
         excludes (map :db/id (:excluded page-filters))
         includes (map :db/id (:included page-filters))
-        filter-exists? (or (seq excludes) (seq includes))
         class-ids (when (ldb/class? entity)
                     (let [class-children (db-class/get-structured-children db id)]
                       (set (conj class-children id))))
-        rules (rules/extract-rules rules/db-query-dsl-rules [:block-parent] {})
-        ref-blocks-query-result (d/q (filter-refs-query includes excludes class-ids) db rules ids)
-        children-query-result (d/q (filter-refs-children-query includes excludes class-ids) db rules ids)
-        ref-blocks (->> (map first children-query-result)
-                        (concat ref-blocks-query-result)
-                        distinct
-                        (map (fn [id] (d/entity db id)))
-                        (remove-hidden-ref db id))
-        children-ids (->>
-                      (distinct (concat
-                                 (map second children-query-result)
-                                 (map last children-query-result)))
-                      (remove (set (map :db/id ref-blocks))))
-        ref-pages-count (get-ref-pages-count db id ref-blocks children-ids)]
-    {:ref-pages-count ref-pages-count
-     :ref-blocks ref-blocks
-     :ref-matched-children-ids (when filter-exists? (set children-ids))}))
+        full-ref-block-ids (->> (mapcat (fn [id] (map :db/id (:block/_refs (d/entity db id)))) ids)
+                                set)
+        matched-ref-block-ids (set (d/q (filter-refs-query :block/path-refs includes excludes class-ids) db ids))
+        matched-refs-with-children-ids (let [*result (atom #{})]
+                                         (doseq [ref-id matched-ref-block-ids]
+                                           (get-block-parents-until-top-ref db id ref-id full-ref-block-ids *result))
+                                         @*result)
+        ref-blocks (->> (set/intersection full-ref-block-ids matched-refs-with-children-ids)
+                        (map (fn [id] (d/entity db id))))
+        filter-exists? (or (seq excludes) (seq includes))
+        children-ids (set (remove full-ref-block-ids matched-refs-with-children-ids))]
+    {:ref-blocks ref-blocks
+     :ref-pages-count (get-ref-pages-count db id ref-blocks children-ids)
+     :ref-matched-children-ids (when filter-exists? children-ids)}))
 
 (defn get-unlinked-references
   [db id]

+ 1 - 1
deps/db/src/logseq/db/common/view.cljs

@@ -281,7 +281,7 @@
                               (entity-util/built-in? e)))
                 (cond-> e
                   refs-count?
-                  (assoc :block.temp/refs-count (ldb/get-block-refs-count db (:db/id e)))))))
+                  (assoc :block.temp/refs-count (count (:block/_refs e)))))))
           (d/datoms db :avet property-ident))))
 
 (defn- get-entities

+ 13 - 13
src/test/frontend/db/reference_test.cljs

@@ -76,7 +76,7 @@
 
     (testing "Linked references without filters"
       (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references db (:db/id foo))]
-        (is (= [["baz" 4] ["Journal" 3] ["Jun 11th, 2025" 2] ["bar" 2]] (vec ref-pages-count))
+        (is (= [["baz" 4] ["Journal" 2] ["Jun 11th, 2025" 2] ["bar" 2]] (vec ref-pages-count))
             "ref-pages-count check failed")
         (is (empty? ref-matched-children-ids)
             "ref-matched-children-ids check failed")
@@ -88,9 +88,9 @@
                    [{:db/id (:db/id foo)
                      :logseq.property.linked-references/includes (:db/id bar)}])
       (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
-        (is (= [["Journal" 3] ["baz" 3] ["Jun 11th, 2025" 2] ["bar" 2]] (vec ref-pages-count))
+        (is (= [["baz" 3] ["Journal" 2] ["Jun 11th, 2025" 2] ["bar" 2]] (vec ref-pages-count))
             "ref-pages-count check failed")
-        (is (= 8 (count ref-matched-children-ids))
+        (is (= 7 (count ref-matched-children-ids))
             "ref-matched-children-ids check failed")
         (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
             "ref-blocks check failed")))
@@ -100,9 +100,9 @@
                    [{:db/id (:db/id foo)
                      :logseq.property.linked-references/includes (:db/id baz)}])
       (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
-        (is (= [["Journal" 3] ["baz" 3] ["Jun 11th, 2025" 2] ["bar" 2]] (vec ref-pages-count))
+        (is (= [["baz" 3] ["Journal" 2] ["Jun 11th, 2025" 2] ["bar" 2]] (vec ref-pages-count))
             "ref-pages-count check failed")
-        (is (= 8 (count ref-matched-children-ids))
+        (is (= 7 (count ref-matched-children-ids))
             "ref-matched-children-ids check failed")
         (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
             "ref-blocks check failed")))
@@ -113,9 +113,9 @@
                    [{:db/id (:db/id foo)
                      :logseq.property.linked-references/excludes (:db/id bar)}])
       (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
-        (is (= [["Journal" 3] ["Jun 11th, 2025" 2] ["baz" 2]] (vec ref-pages-count))
+        (is (= [["Journal" 2] ["Jun 11th, 2025" 2] ["baz" 2]] (vec ref-pages-count))
             "ref-pages-count check failed")
-        (is (= 3 (count ref-matched-children-ids))
+        (is (= 2 (count ref-matched-children-ids))
             "ref-matched-children-ids check failed")
         (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
             "ref-blocks check failed")))
@@ -126,9 +126,9 @@
                    [{:db/id (:db/id foo)
                      :logseq.property.linked-references/excludes (:db/id baz)}])
       (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
-        (is (= [["Journal" 3] ["Jun 11th, 2025" 2] ["bar" 1]] (vec ref-pages-count))
+        (is (= [["Journal" 2] ["Jun 11th, 2025" 2] ["bar" 1]] (vec ref-pages-count))
             "ref-pages-count check failed")
-        (is (= 4 (count ref-matched-children-ids))
+        (is (= 3 (count ref-matched-children-ids))
             "ref-matched-children-ids check failed")
         (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
             "ref-blocks check failed")))
@@ -153,9 +153,9 @@
                      :logseq.property.linked-references/includes (:db/id bar)
                      :logseq.property.linked-references/excludes (:db/id baz)}])
       (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
-        (is (= [["Journal" 2] ["Jun 11th, 2025" 1] ["bar" 1]] (vec ref-pages-count))
+        (is (= [["Journal" 1] ["Jun 11th, 2025" 1] ["bar" 1]] (vec ref-pages-count))
             "ref-pages-count check failed")
-        (is (= 4 (count ref-matched-children-ids))
+        (is (= 3 (count ref-matched-children-ids))
             "ref-matched-children-ids check failed")
         (is (= #{"[[foo]] 1"} (set (map :block/title ref-blocks)))
             "ref-blocks check failed")))
@@ -167,9 +167,9 @@
                      :logseq.property.linked-references/includes (:db/id baz)
                      :logseq.property.linked-references/excludes (:db/id bar)}])
       (let [{:keys [ref-pages-count ref-blocks ref-matched-children-ids]} (db-reference/get-linked-references @conn (:db/id foo))]
-        (is (= [["Journal" 3] ["Jun 11th, 2025" 2] ["baz" 2]] (vec ref-pages-count))
+        (is (= [["Journal" 2] ["Jun 11th, 2025" 2] ["baz" 2]] (vec ref-pages-count))
             "ref-pages-count check failed")
-        (is (= 3 (count ref-matched-children-ids))
+        (is (= 2 (count ref-matched-children-ids))
             "ref-matched-children-ids check failed")
         (is (= #{"[[foo]] 1" "[[foo]] 2"} (set (map :block/title ref-blocks)))
             "ref-blocks check failed")))))