Explorar o código

Fix perf issue with property rules for db graphs

Use multiple clauses instead as confirmed by perf test.
Using multiple clauses made rule preparation for d/q more complex
so introduced extract-rules
Gabriel Horner %!s(int64=2) %!d(string=hai) anos
pai
achega
3f52860cf1

+ 1 - 1
deps/db/script/query.cljs

@@ -29,7 +29,7 @@
   (let [[graph-name query*] args
         conn (read-graph graph-name)
         query (into (edn/read-string query*) [:in '$ '%]) ;; assumes no :in are in queries
-        results (mapv first (apply d/q query @conn [(vals rules/db-query-dsl-rules)]))]
+        results (mapv first (d/q query @conn (rules/extract-rules rules/db-query-dsl-rules)))]
     (println "DB contains" (count (d/datoms @conn :eavt)) "datoms")
     (prn results)))
 

+ 36 - 16
deps/db/src/logseq/db/rules.cljc

@@ -157,19 +157,39 @@
       [(get ?bp ?prop-uuid)]]
 
     :property
-    '[(property ?b ?key ?val)
-      [?b :block/properties ?prop]
-      [(missing? $ ?b :block/name)]
-      [(name ?key) ?key-str]
-      [?prop-b :block/name ?key-str]
-      [?prop-b :block/type "property"]
-      [?prop-b :block/uuid ?prop-uuid]
-      [(get ?prop ?prop-uuid) ?v]
-     ;; TODO: Need to find a more performant way to do this
-      (or-join [?v]
-               [(= ?v ?val)]
-               (and [(str ?val) ?str-val]
-                    ;; str-val is for integer pages that aren't strings
-                    [?prop-val-b :block/original-name ?str-val]
-                    [?prop-val-b :block/uuid ?val-uuid]
-                    [(contains? ?v ?val-uuid)]))]}))
+    '[;; Clause 1: Match non-ref values
+      [(property ?b ?key ?val)
+       [?b :block/properties ?prop]
+       [(missing? $ ?b :block/name)]
+       [(name ?key) ?key-str]
+       [?prop-b :block/name ?key-str]
+       [?prop-b :block/type "property"]
+       [?prop-b :block/uuid ?prop-uuid]
+       [(get ?prop ?prop-uuid) ?v]
+       [(= ?v ?val)]]
+
+      ;; Clause 2: Match values joined by ref values
+      [(property ?b ?key ?val)
+       [?b :block/properties ?prop]
+       [(missing? $ ?b :block/name)]
+       [(name ?key) ?key-str]
+       [?prop-b :block/name ?key-str]
+       [?prop-b :block/type "property"]
+       [?prop-b :block/uuid ?prop-uuid]
+       [(get ?prop ?prop-uuid) ?v]
+       [(str ?val) ?str-val]
+      ;; str-val is for integer pages that aren't strings
+       [?prop-val-b :block/original-name ?str-val]
+       [?prop-val-b :block/uuid ?val-uuid]
+       [(contains? ?v ?val-uuid)]]]}))
+
+(defn extract-rules
+  "Given a rules map and the rule names to extract, returns a vector of rules to
+  be passed to datascript.core/q. Can handle rules with multiple or single clauses"
+  ([rules-m] (extract-rules rules-m (keys rules-m)))
+  ([rules-m rules]
+   (vec
+    (mapcat #(let [val (rules-m %)]
+              ;; if vector?, rule has multiple clauses
+               (if (vector? (first val)) val [val]))
+            rules))))

+ 2 - 2
src/main/frontend/db/query_custom.cljs

@@ -38,7 +38,7 @@
                   (assoc (vec inputs)
                          ;; last position is rules
                          (dec (count inputs))
-                         (->> (mapv query-dsl-rules rules-found)
+                         (->> (rules/extract-rules query-dsl-rules rules-found)
                               (into (last inputs))
                               ;; user could give rules that we already have
                               distinct
@@ -56,7 +56,7 @@
             (update :rules
                     (fn [rules]
                       (into (or rules [])
-                            (mapv query-dsl-rules rules-found))))))
+                            (rules/extract-rules query-dsl-rules rules-found))))))
       query-m)))
 
 (defn custom-query

+ 1 - 1
src/main/frontend/db/query_dsl.cljs

@@ -555,7 +555,7 @@ Some bindings in this fn:
                                      (if (= key :and) (rest result) result))))]
       {:query result'
        :rules (if db-graph?
-                (mapv rules/db-query-dsl-rules rules)
+                (rules/extract-rules rules/db-query-dsl-rules rules)
                 (mapv rules/query-dsl-rules rules))
        :sort-by @sort-by
        :blocks? (boolean @blocks?)

+ 2 - 1
src/test/frontend/db/query_dsl_test.cljs

@@ -155,7 +155,8 @@ prop-d:: nada"
                                   {:file/path (str "pages/page" idx ".md")
                                    :file/content (if (seq tags)
                                                    (str "tags:: " (str/join ", " (map page-ref/->page-ref tags)))
-                                                   "")})))
+                                                   "")
+                                   :file/blocks [[(str "block for page" idx) {:tags (set tags)}]]})))
         _ (load-test-files pages)
         {:keys [result time]}
         (util/with-time (dsl-query "(and (property tags tag1) (property tags tag2))"))]