From c0d5a92921ac34ffe7d0fba236f403357706dbc2 Mon Sep 17 00:00:00 2001 From: Jeremiah Via Date: Tue, 21 Nov 2023 09:37:54 -0800 Subject: [PATCH 1/4] Update linter and formatter --- cljfmt.edn | 1 + 1 file changed, 1 insertion(+) create mode 100644 cljfmt.edn diff --git a/cljfmt.edn b/cljfmt.edn new file mode 100644 index 0000000..3a98abf --- /dev/null +++ b/cljfmt.edn @@ -0,0 +1 @@ +{:extra-indents {}} From 550b126c67b89ff041bd20051b51fa3e293a5266 Mon Sep 17 00:00:00 2001 From: Jeremiah Via Date: Tue, 21 Nov 2023 09:40:17 -0800 Subject: [PATCH 2/4] Update formatting --- cljfmt.edn | 5 ++++- dev/user.clj | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cljfmt.edn b/cljfmt.edn index 3a98abf..d1c14da 100644 --- a/cljfmt.edn +++ b/cljfmt.edn @@ -1 +1,4 @@ -{:extra-indents {}} +{:sort-ns-references? true + :remove-consecutive-blank-lines? false + :extra-indents + {}} diff --git a/dev/user.clj b/dev/user.clj index 5796b46..28f4e39 100644 --- a/dev/user.clj +++ b/dev/user.clj @@ -1,7 +1,7 @@ (ns user - (:require [com.nytimes.querqy.commonrules :as c] - [com.nytimes.querqy :as q] - [clojure.math :as math])) + (:require + [com.nytimes.querqy :as q] + [com.nytimes.querqy.commonrules :as c])) (defn pin "Pin the given IDs to the top of the result set in the order given. Should only From 76ed2b85c5cf4ed883161d94ee3f7414d3b749ec Mon Sep 17 00:00:00 2001 From: Jeremiah Via Date: Wed, 10 Jan 2024 10:08:09 -0800 Subject: [PATCH 3/4] [#4] Fix clobbered boolean rules This requires sharing the BooleanInputParser among all the rules within the rules-rewriter and adding the input literals all at once at the end. --- dev/user.clj | 54 +----- src/com/nytimes/querqy/commonrules.clj | 185 ++++++++++--------- src/com/nytimes/querqy/model.clj | 10 +- test/com/nytimes/querqy/common-rules.txt | 6 + test/com/nytimes/querqy/commonrules_test.clj | 166 ++++++++--------- 5 files changed, 184 insertions(+), 237 deletions(-) diff --git a/dev/user.clj b/dev/user.clj index 28f4e39..7a96237 100644 --- a/dev/user.clj +++ b/dev/user.clj @@ -1,53 +1 @@ -(ns user - (:require - [com.nytimes.querqy :as q] - [com.nytimes.querqy.commonrules :as c])) - -(defn pin - "Pin the given IDs to the top of the result set in the order given. Should only - be used once within a given match rule." - [& ids] - (map-indexed - (fn [idx id] - (c/boost (- Float/MAX_VALUE idx) {:ids {:values [id]}})) - ids)) - -;; Let's assume we have some special thanksgiving related content that editorial -;; wants highly promoted, the documents with IDs 12345 and 5678. Rather than -;; tweak scores or sprinkle boosts around our rule set, we can instead use our -;; new pin rule which makes clear the intent of the boost and serves as -;; documentation for what we're trying to achieve with this rule. -(def rules - (c/rules-rewriter - (c/match "thanksgiving" - (pin "12345" "5678")))) - -;; We can now emit a query which pins results to the top. - -(def opts {:match/fields ["headline"]}) - -(q/emit (q/rewrite rules "thanksgiving recipes") opts) - -{:function_score - {:query - {:bool - {:must [], - :should - [{:match {"headline" {:query "thanksgiving"}}} - {:match {"headline" {:query "recipes"}}}], - :must_not [], - :filter []}}, - :functions - [{:filter {:ids {:values ["5678"]}}, :weight 1.0E37} - {:filter {:ids {:values ["12345"]}}, :weight 1.0E38}]}} - -(def base - {:function_score - {:query - {:bool {:must [], - :should [], - :must_not [], - :filter []}}, - :functions - [{:filter {:ids {:values ["5678"]}}, :weight 1.0E37} - {:filter {:ids {:values ["12345"]}}, :weight 1.0E38}]}}) +(ns user) diff --git a/src/com/nytimes/querqy/commonrules.clj b/src/com/nytimes/querqy/commonrules.clj index 2e09bda..71764c1 100644 --- a/src/com/nytimes/querqy/commonrules.clj +++ b/src/com/nytimes/querqy/commonrules.clj @@ -2,22 +2,24 @@ "CommonRules based rewriter" (:refer-clojure :exclude [filter]) (:require - [clojure.java.io :as io] - [clojure.string :as str] - [com.nytimes.querqy.model :as model] - [com.nytimes.querqy.parser :as parser]) + [clojure.java.io :as io] + [clojure.string :as str] + [com.nytimes.querqy.model :as model] + [com.nytimes.querqy.parser :as parser]) (:import - (java.io Reader) - (java.net URL) - (java.util List UUID) - (querqy.model Input Input$BooleanInput Input$SimpleInput) - (querqy.parser QuerqyParser) - (querqy.rewrite RewriterFactory) - (querqy.rewrite.commonrules CommonRulesRewriter LineParser QuerqyParserFactory SimpleCommonRulesParser WhiteSpaceQuerqyParserFactory) - (querqy.rewrite.commonrules.model BoostInstruction BoostInstruction$BoostDirection DeleteInstruction FilterInstruction Instructions SynonymInstruction TrieMapRulesCollectionBuilder) - (querqy.rewrite.commonrules.select SelectionStrategyFactory) - (querqy.rewrite.commonrules.select.booleaninput BooleanInputParser) - (querqy.rewrite.commonrules.select.booleaninput.model BooleanInputElement BooleanInputElement$Type BooleanInputLiteral))) + (java.io Reader) + (java.net URL) + (java.util List UUID) + (querqy.model Input Input$BooleanInput Input$SimpleInput) + (querqy.parser QuerqyParser) + (querqy.rewrite RewriterFactory) + (querqy.rewrite.commonrules CommonRulesRewriter LineParser QuerqyParserFactory SimpleCommonRulesParser WhiteSpaceQuerqyParserFactory) + (querqy.rewrite.commonrules.model BoostInstruction BoostInstruction$BoostDirection DeleteInstruction FilterInstruction Instructions SynonymInstruction TrieMapRulesCollectionBuilder) + (querqy.rewrite.commonrules.select SelectionStrategyFactory) + (querqy.rewrite.commonrules.select.booleaninput BooleanInputParser) + (querqy.rewrite.commonrules.select.booleaninput.model BooleanInputElement BooleanInputElement$Type BooleanInputLiteral))) + +(set! *warn-on-reflection* true) (defprotocol CommonRulesRewriterBuilder (common-rules-rewriter* [this])) @@ -27,12 +29,6 @@ (common-rules-rewriter* [_] (throw (IllegalArgumentException. "Must provide rules to rules-rewriter")))) -(defn- flatten-rules - [fns] - (reduce (fn [accm afn] (if (coll? afn) (into accm afn) (conj accm afn))) - [] - fns)) - (defn rules-rewriter "Create a CommonRulesRewriter. @@ -41,15 +37,15 @@ [& args] (if (and (= 1 (count args)) (instance? URL (first args))) (common-rules-rewriter* (first args)) - (common-rules-rewriter* (flatten-rules args)))) + (common-rules-rewriter* args))) (defn rewriter-factory [rules] (proxy [RewriterFactory] [(str (UUID/randomUUID))] (createRewriter [_ _] (CommonRulesRewriter. - rules - SelectionStrategyFactory/DEFAULT_SELECTION_STRATEGY)) + rules + SelectionStrategyFactory/DEFAULT_SELECTION_STRATEGY)) (getCacheableGenerableTerms [] #{}))) ;; ---------------------------------------------------------------------- @@ -63,10 +59,10 @@ ignore-case true parser (WhiteSpaceQuerqyParserFactory.)}}] (let [rules-parser (SimpleCommonRulesParser. - ^Reader stream - ^boolean boolean-input - ^QuerqyParserFactory parser - ^boolean ignore-case)] + ^Reader stream + ^boolean boolean-input + ^QuerqyParserFactory parser + ^boolean ignore-case)] (.parse rules-parser)))) (extend-protocol CommonRulesRewriterBuilder @@ -77,36 +73,51 @@ ;; ---------------------------------------------------------------------- ;; DSL -(extend-protocol CommonRulesRewriterBuilder - List - (common-rules-rewriter* [rules] - (let [rules-builder (TrieMapRulesCollectionBuilder. true)] - (doseq [rule-fn rules] - (rule-fn rules-builder)) - (rewriter-factory (.build rules-builder))))) - (def ^:dynamic ^QuerqyParser *query-parser* parser/whitespace-parser) -(declare match*) +(defrecord Rule [input instructions]) + +(defn match* + "Create a " + [head & tail] + (->Rule head (vec tail))) (defmacro match - "Create a match rule." - {:style/indent 1} - ;; TODO LEFT/ RIGHT boundaries + "Create a rewriter rule from matching text input or boolean input followed by + any number of query transformations. + + ```clojure + ;; Inject bar as a synonym to foo in any query. + (match \"foo\" + (synonym \"bar\")) + ```" [head & tail] - `(match* '~head (vec (flatten (vector ~@tail))))) + `(match* '~head ~@tail)) + +(defn- parse-string + [string] + (mapv #(LineParser/parseTerm %) (str/split string #"\s+"))) -(defn- parse-string [string] (mapv #(LineParser/parseTerm %) (str/split string #"\s+"))) +(defn- parse-query + [query] + (cond + (string? query) + (.parse *query-parser* query) -(defn- parse-query [query] - (cond (string? query) (.parse *query-parser* query) - (map? query) (model/rawq {:query query}))) + (map? query) + (model/rawq {:query query}))) -(defn delete? [obj] (instance? DeleteInstruction obj)) +(defn delete? + [obj] + (instance? DeleteInstruction obj)) -(defn delete [string] (DeleteInstruction. (parse-string string))) +(defn delete + [string] + (DeleteInstruction. (parse-string string))) -(defn synonym? [obj] (instance? SynonymInstruction obj)) +(defn synonym? + [obj] + (instance? SynonymInstruction obj)) (defn synonym "Create a synonym instruction." @@ -154,41 +165,43 @@ not (wrap (cons NOT (parse-boolean-input terms))) (map parse-boolean-input input)))) -;; - -(def rule-count (atom 0)) - -(defn ^:no-doc match* - ;; implements match for use by match macro - [input instructions] - (let [ord (swap! rule-count inc) - compiled (Instructions. ord ord instructions)] - (fn [^TrieMapRulesCollectionBuilder rules-builder] - (cond - ;; string rules - (string? input) - (let [simple-input (Input/parseSimpleInput input)] - (.addRule rules-builder - ^Input$SimpleInput simple-input - ^Instructions compiled)) - - ;; boolean rules - (list? input) - (do - (when (some delete? instructions) - (throw (IllegalArgumentException. "Cannot use a delete instruction with boolean input"))) - (when (some synonym? instructions) - (throw (IllegalArgumentException. "Cannot use a synonym instruction with boolean input"))) - (let [boolean-input-parser (BooleanInputParser.) - bool-input (Input$BooleanInput. (parse-boolean-input input) - boolean-input-parser - (pr-str input))] - - (.applyInstructions bool-input compiled rules-builder) - (doseq [^BooleanInputLiteral literal (.values (.getLiteralRegister boolean-input-parser))] - (let [input (LineParser/parseInput (str/join \space (.getTerms literal)))] - (.addRule rules-builder - ^Input$SimpleInput input - ^BooleanInputLiteral literal))))) - - :else (throw (IllegalArgumentException. "Can only parse a string or list as input")))))) +(defn parse-simple-input + ^Input$SimpleInput + [string] + (Input/parseSimpleInput string)) + +(extend-protocol CommonRulesRewriterBuilder + List + (common-rules-rewriter* [rules] + (let [rules (flatten rules) + counter (atom 0) + rules-builder (TrieMapRulesCollectionBuilder. true) + boolean-input-parser (BooleanInputParser.)] + (doseq [{:keys [input instructions]} rules] + (let [ord (swap! counter inc) + id (str input "#" ord) + instructions (Instructions. ord id instructions)] + (cond + (string? input) + (.addRule rules-builder (parse-simple-input input) instructions) + + (list? input) + (do + (when (some delete? instructions) + (throw (IllegalArgumentException. "Cannot use a delete instruction with boolean input"))) + + (when (some synonym? instructions) + (throw (IllegalArgumentException. "Cannot use a synonym instruction with boolean input"))) + + (let [bool-input (Input$BooleanInput. (parse-boolean-input input) boolean-input-parser (pr-str input))] + ;; inputPattern.applyInstructions(instructions, builder); + (.applyInstructions bool-input instructions rules-builder)))))) + + ;; Add boolean literals at the end + (doseq [^BooleanInputLiteral literal (.values (.getLiteralRegister boolean-input-parser))] + (let [string (str/join \space (.getTerms literal)) + input (parse-simple-input string)] + (.addRule rules-builder input literal))) + + ;; + (rewriter-factory (.build rules-builder))))) diff --git a/src/com/nytimes/querqy/model.clj b/src/com/nytimes/querqy/model.clj index 0c38e57..8ca671e 100644 --- a/src/com/nytimes/querqy/model.clj +++ b/src/com/nytimes/querqy/model.clj @@ -1,11 +1,11 @@ (ns com.nytimes.querqy.model "Builders for classes in the `querqy.model` package." (:require - [clojure.core.protocols :as cp] - [clojure.datafy :refer [datafy]] - [clojure.string :as str]) + [clojure.core.protocols :as cp] + [clojure.datafy :refer [datafy]] + [clojure.string :as str]) (:import - (querqy.model BooleanParent BooleanQuery BoostQuery BoostedTerm Clause Clause$Occur DisjunctionMaxQuery ExpandedQuery Input$SimpleInput MatchAllQuery QuerqyQuery Query Term))) + (querqy.model BooleanParent BooleanQuery BoostQuery BoostedTerm Clause Clause$Occur DisjunctionMaxQuery ExpandedQuery Input$SimpleInput MatchAllQuery QuerqyQuery Query Term))) (def should Clause$Occur/SHOULD) (def must Clause$Occur/MUST) @@ -112,7 +112,7 @@ BooleanQuery (datafy [^BooleanQuery q] {:type BooleanQuery - :occur (.getOccur q) + :occur (occur->kw (.getOccur q)) :clauses (mapv datafy (.getClauses q))}) BoostQuery diff --git a/test/com/nytimes/querqy/common-rules.txt b/test/com/nytimes/querqy/common-rules.txt index 1ab4f9d..8f540de 100644 --- a/test/com/nytimes/querqy/common-rules.txt +++ b/test/com/nytimes/querqy/common-rules.txt @@ -33,3 +33,9 @@ A8 => (A11 AND (NOT B11)) => UP(2): C11 + +(best AND netflix AND show) => + UP(2): netflix + +(best AND amazon AND show) => + UP(2): amazon diff --git a/test/com/nytimes/querqy/commonrules_test.clj b/test/com/nytimes/querqy/commonrules_test.clj index eb0b2d7..896304f 100644 --- a/test/com/nytimes/querqy/commonrules_test.clj +++ b/test/com/nytimes/querqy/commonrules_test.clj @@ -1,34 +1,40 @@ (ns com.nytimes.querqy.commonrules-test (:refer-clojure :exclude [filter]) (:require - [clojure.test :refer [deftest is testing]] - [testit.core :refer [facts =>]] - [clojure.datafy :refer [datafy]] - [com.nytimes.querqy.commonrules :as r :refer [match match* synonym boost filter delete]] - [clojure.java.io :as io] - [com.nytimes.querqy :as querqy]) + [clojure.datafy :refer [datafy]] + [clojure.java.io :as io] + [clojure.test :refer [deftest is]] + [com.nytimes.querqy :as querqy] + [com.nytimes.querqy.commonrules :as r :refer [boost delete filter match match* synonym]] + [testit.core :refer [=> =in=> facts]]) (:import - (querqy.rewrite.commonrules.select.booleaninput BooleanInputParser) - (querqy.rewrite.commonrules.select.booleaninput.model BooleanInputElement BooleanInputElement$Type))) + (querqy.rewrite.commonrules.select.booleaninput BooleanInputParser) + (querqy.rewrite.commonrules.select.booleaninput.model BooleanInputElement BooleanInputElement$Type))) + +(deftest match-macro-inputs + (facts "valid inputs to match macro" + (match "a" (synonym "b")) =in=> {:input "a"} + (match (or "a" "A") (synonym "b")) =in=> {:input '(or "a" "A")})) (defn parsed "Small helper function to convert the list of BooleanInputElements back into sexpr format. Helpful for visualizing the parsed output." [input] (let [parsed-input (r/parse-boolean-input input) - string-input (apply str (for [^BooleanInputElement token parsed-input] - (cond - (= BooleanInputElement$Type/AND (.-type token)) - " AND " + string-input (apply str + (for [^BooleanInputElement token parsed-input] + (cond + (= BooleanInputElement$Type/AND (.-type token)) + " AND " - (= BooleanInputElement$Type/OR (.-type token)) - " OR " + (= BooleanInputElement$Type/OR (.-type token)) + " OR " - (= BooleanInputElement$Type/NOT (.-type token)) - "NOT " + (= BooleanInputElement$Type/NOT (.-type token)) + "NOT " - :else - (.-term token))))] + :else + (.-term token))))] (.validateBooleanInput (BooleanInputParser.) parsed-input string-input) string-input)) @@ -46,23 +52,30 @@ (def resource-rewriter (r/rules-rewriter - (io/resource "com/nytimes/querqy/common-rules.txt"))) + (io/resource "com/nytimes/querqy/common-rules.txt"))) (def dsl-rewriter (r/rules-rewriter ;; basics - (match "A1" (synonym "B1")) - (match "A2 B2" (synonym "C2")) - (match "A3" (synonym "B3") (synonym "C3")) - (match "A4 B4" (synonym "C4") (synonym "D4")) - (match "A5" (boost 2 "B5")) - (match "A6" (filter "B6")) - (match "A7 B7" (delete "B7")) - (match "A8" (synonym "B8") (boost 2 "C8")) + (match "A1" (synonym "B1")) + (match "A2 B2" (synonym "C2")) + (match "A3" (synonym "B3") (synonym "C3")) + (match "A4 B4" (synonym "C4") (synonym "D4")) + (match "A5" (boost 2 "B5")) + (match "A6" (filter "B6")) + (match "A7 B7" (delete "B7")) + (match "A8" (synonym "B8") (boost 2 "C8")) ;; boolean rules - (match (or "A9" "B9") (boost 2 "C9")) - (match (and "A10" "B10") (boost 2 "C10")) - (match (and "A11" (not "B11")) (boost 2 "C11")))) + (match (or "A9" "B9") (boost 2 "C9")) + (match (and "A10" "B10") (boost 2 "C10")) + (match (and "A11" (not "B11")) (boost 2 "C11")) + + ;; multi anchor rules + (match (and "best" "netflix" "show") + (boost 2 "netflix")) + + (match (and "best" "amazon" "show") + (boost 2 "amazon")))) (defn rewrite "util to do a rewrite and datafy the result for easier comparison" @@ -83,66 +96,33 @@ (rewrite dsl-rewriter "B9") => (rewrite resource-rewriter "B9") (rewrite dsl-rewriter "A10 B10") => (rewrite resource-rewriter "A10 B10") (rewrite dsl-rewriter "A11") => (rewrite resource-rewriter "A11") - (rewrite dsl-rewriter "A11 B11") => (rewrite resource-rewriter "A11 B11"))) - -(deftest match-inputs-test - (testing "match accepts instructions or a list of instructions" - (is (fn? (match "a" - (synonym "b")))) - (is (fn? (match "a" - [(synonym "b") (synonym "c")]))) - (is (fn? (match "a" - [(synonym "b") (synonym "c")] - [(boost 2 "d") (boost 2 "e")]))))) - -(deftest rule-builder-test - (let [mutual-synonyms (fn [terms] - (for [term terms] - (let [tail (map synonym (disj terms term))] - (match* term tail)))) - rewriter (r/rules-rewriter (mutual-synonyms #{"a" "b" "c"}))] - (facts "custom rule builders" - (rewrite rewriter "a") => - {:type querqy.model.ExpandedQuery, - :user-query {:type querqy.model.Query, - :occur :should, - :clauses - [{:type querqy.model.DisjunctionMaxQuery, - :occur :should, - :clauses - [{:type querqy.model.Term, :field nil, :value "a"} - {:type querqy.model.Term, :field nil, :value "c"} - {:type querqy.model.Term, :field nil, :value "b"}]}]}, - :boost-up [], - :boost-down [], - :filter []} - - (rewrite rewriter "b") => - {:type querqy.model.ExpandedQuery, - :user-query {:type querqy.model.Query, - :occur :should, - :clauses - [{:type querqy.model.DisjunctionMaxQuery, - :occur :should, - :clauses - [{:type querqy.model.Term, :field nil, :value "b"} - {:type querqy.model.Term, :field nil, :value "c"} - {:type querqy.model.Term, :field nil, :value "a"}]}]}, - :boost-up [], - :boost-down [], - :filter []} - - (rewrite rewriter "c") => - {:type querqy.model.ExpandedQuery, - :user-query {:type querqy.model.Query, - :occur :should, - :clauses - [{:type querqy.model.DisjunctionMaxQuery, - :occur :should, - :clauses - [{:type querqy.model.Term, :field nil, :value "c"} - {:type querqy.model.Term, :field nil, :value "b"} - {:type querqy.model.Term, :field nil, :value "a"}]}]}, - :boost-up [], - :boost-down [], - :filter []}))) + (rewrite dsl-rewriter "A11 B11") => (rewrite resource-rewriter "A11 B11") + (rewrite dsl-rewriter "best netflix show") => (rewrite resource-rewriter "best netflix show") + (rewrite dsl-rewriter "best amazon show") => (rewrite resource-rewriter "best amazon show"))) + +;; Custom Functions + +(defn synonyms + "Create mutual synonyms" + [a b] + [(match* a (synonym b)) + (match* b (synonym a))]) + +(def rules-with-custom-functions + (r/rules-rewriter + (synonyms "chickpea" "garbanzo bean") + (synonyms "chickpeas" "garbanzo beans"))) + +(deftest custom-functions-test + (facts "helper functions can return multiple match rules" + (rewrite rules-with-custom-functions "chickpea salad") + =in=> + {:user-query + {:occur :should, + :clauses [{:occur :should, + :clauses [{:value "chickpea"} + {:occur :should, + :clauses + [{:occur :must, :clauses [{:value "garbanzo"}]} + {:occur :must, :clauses [{:value "bean"}]}]}]} + {:occur :should, :clauses [{:value "salad"}]}]}})) \ No newline at end of file From d4bf84a8704510310e28c51077806fc4a61c91bd Mon Sep 17 00:00:00 2001 From: Jeremiah Via Date: Thu, 11 Jan 2024 11:11:44 -0800 Subject: [PATCH 4/4] Run cljfmt --- src/com/nytimes/querqy/commonrules.clj | 42 ++++++++-------- src/com/nytimes/querqy/model.clj | 8 +-- test/com/nytimes/querqy/commonrules_test.clj | 52 ++++++++++---------- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/com/nytimes/querqy/commonrules.clj b/src/com/nytimes/querqy/commonrules.clj index 71764c1..e2fbf34 100644 --- a/src/com/nytimes/querqy/commonrules.clj +++ b/src/com/nytimes/querqy/commonrules.clj @@ -2,22 +2,22 @@ "CommonRules based rewriter" (:refer-clojure :exclude [filter]) (:require - [clojure.java.io :as io] - [clojure.string :as str] - [com.nytimes.querqy.model :as model] - [com.nytimes.querqy.parser :as parser]) + [clojure.java.io :as io] + [clojure.string :as str] + [com.nytimes.querqy.model :as model] + [com.nytimes.querqy.parser :as parser]) (:import - (java.io Reader) - (java.net URL) - (java.util List UUID) - (querqy.model Input Input$BooleanInput Input$SimpleInput) - (querqy.parser QuerqyParser) - (querqy.rewrite RewriterFactory) - (querqy.rewrite.commonrules CommonRulesRewriter LineParser QuerqyParserFactory SimpleCommonRulesParser WhiteSpaceQuerqyParserFactory) - (querqy.rewrite.commonrules.model BoostInstruction BoostInstruction$BoostDirection DeleteInstruction FilterInstruction Instructions SynonymInstruction TrieMapRulesCollectionBuilder) - (querqy.rewrite.commonrules.select SelectionStrategyFactory) - (querqy.rewrite.commonrules.select.booleaninput BooleanInputParser) - (querqy.rewrite.commonrules.select.booleaninput.model BooleanInputElement BooleanInputElement$Type BooleanInputLiteral))) + (java.io Reader) + (java.net URL) + (java.util List UUID) + (querqy.model Input Input$BooleanInput Input$SimpleInput) + (querqy.parser QuerqyParser) + (querqy.rewrite RewriterFactory) + (querqy.rewrite.commonrules CommonRulesRewriter LineParser QuerqyParserFactory SimpleCommonRulesParser WhiteSpaceQuerqyParserFactory) + (querqy.rewrite.commonrules.model BoostInstruction BoostInstruction$BoostDirection DeleteInstruction FilterInstruction Instructions SynonymInstruction TrieMapRulesCollectionBuilder) + (querqy.rewrite.commonrules.select SelectionStrategyFactory) + (querqy.rewrite.commonrules.select.booleaninput BooleanInputParser) + (querqy.rewrite.commonrules.select.booleaninput.model BooleanInputElement BooleanInputElement$Type BooleanInputLiteral))) (set! *warn-on-reflection* true) @@ -44,8 +44,8 @@ (proxy [RewriterFactory] [(str (UUID/randomUUID))] (createRewriter [_ _] (CommonRulesRewriter. - rules - SelectionStrategyFactory/DEFAULT_SELECTION_STRATEGY)) + rules + SelectionStrategyFactory/DEFAULT_SELECTION_STRATEGY)) (getCacheableGenerableTerms [] #{}))) ;; ---------------------------------------------------------------------- @@ -59,10 +59,10 @@ ignore-case true parser (WhiteSpaceQuerqyParserFactory.)}}] (let [rules-parser (SimpleCommonRulesParser. - ^Reader stream - ^boolean boolean-input - ^QuerqyParserFactory parser - ^boolean ignore-case)] + ^Reader stream + ^boolean boolean-input + ^QuerqyParserFactory parser + ^boolean ignore-case)] (.parse rules-parser)))) (extend-protocol CommonRulesRewriterBuilder diff --git a/src/com/nytimes/querqy/model.clj b/src/com/nytimes/querqy/model.clj index 8ca671e..019b602 100644 --- a/src/com/nytimes/querqy/model.clj +++ b/src/com/nytimes/querqy/model.clj @@ -1,11 +1,11 @@ (ns com.nytimes.querqy.model "Builders for classes in the `querqy.model` package." (:require - [clojure.core.protocols :as cp] - [clojure.datafy :refer [datafy]] - [clojure.string :as str]) + [clojure.core.protocols :as cp] + [clojure.datafy :refer [datafy]] + [clojure.string :as str]) (:import - (querqy.model BooleanParent BooleanQuery BoostQuery BoostedTerm Clause Clause$Occur DisjunctionMaxQuery ExpandedQuery Input$SimpleInput MatchAllQuery QuerqyQuery Query Term))) + (querqy.model BooleanParent BooleanQuery BoostQuery BoostedTerm Clause Clause$Occur DisjunctionMaxQuery ExpandedQuery Input$SimpleInput MatchAllQuery QuerqyQuery Query Term))) (def should Clause$Occur/SHOULD) (def must Clause$Occur/MUST) diff --git a/test/com/nytimes/querqy/commonrules_test.clj b/test/com/nytimes/querqy/commonrules_test.clj index 896304f..8921c08 100644 --- a/test/com/nytimes/querqy/commonrules_test.clj +++ b/test/com/nytimes/querqy/commonrules_test.clj @@ -1,15 +1,15 @@ (ns com.nytimes.querqy.commonrules-test (:refer-clojure :exclude [filter]) (:require - [clojure.datafy :refer [datafy]] - [clojure.java.io :as io] - [clojure.test :refer [deftest is]] - [com.nytimes.querqy :as querqy] - [com.nytimes.querqy.commonrules :as r :refer [boost delete filter match match* synonym]] - [testit.core :refer [=> =in=> facts]]) + [clojure.datafy :refer [datafy]] + [clojure.java.io :as io] + [clojure.test :refer [deftest is]] + [com.nytimes.querqy :as querqy] + [com.nytimes.querqy.commonrules :as r :refer [boost delete filter match match* synonym]] + [testit.core :refer [=> =in=> facts]]) (:import - (querqy.rewrite.commonrules.select.booleaninput BooleanInputParser) - (querqy.rewrite.commonrules.select.booleaninput.model BooleanInputElement BooleanInputElement$Type))) + (querqy.rewrite.commonrules.select.booleaninput BooleanInputParser) + (querqy.rewrite.commonrules.select.booleaninput.model BooleanInputElement BooleanInputElement$Type))) (deftest match-macro-inputs (facts "valid inputs to match macro" @@ -52,30 +52,30 @@ (def resource-rewriter (r/rules-rewriter - (io/resource "com/nytimes/querqy/common-rules.txt"))) + (io/resource "com/nytimes/querqy/common-rules.txt"))) (def dsl-rewriter (r/rules-rewriter ;; basics - (match "A1" (synonym "B1")) - (match "A2 B2" (synonym "C2")) - (match "A3" (synonym "B3") (synonym "C3")) - (match "A4 B4" (synonym "C4") (synonym "D4")) - (match "A5" (boost 2 "B5")) - (match "A6" (filter "B6")) - (match "A7 B7" (delete "B7")) - (match "A8" (synonym "B8") (boost 2 "C8")) + (match "A1" (synonym "B1")) + (match "A2 B2" (synonym "C2")) + (match "A3" (synonym "B3") (synonym "C3")) + (match "A4 B4" (synonym "C4") (synonym "D4")) + (match "A5" (boost 2 "B5")) + (match "A6" (filter "B6")) + (match "A7 B7" (delete "B7")) + (match "A8" (synonym "B8") (boost 2 "C8")) ;; boolean rules - (match (or "A9" "B9") (boost 2 "C9")) - (match (and "A10" "B10") (boost 2 "C10")) - (match (and "A11" (not "B11")) (boost 2 "C11")) + (match (or "A9" "B9") (boost 2 "C9")) + (match (and "A10" "B10") (boost 2 "C10")) + (match (and "A11" (not "B11")) (boost 2 "C11")) ;; multi anchor rules - (match (and "best" "netflix" "show") - (boost 2 "netflix")) + (match (and "best" "netflix" "show") + (boost 2 "netflix")) - (match (and "best" "amazon" "show") - (boost 2 "amazon")))) + (match (and "best" "amazon" "show") + (boost 2 "amazon")))) (defn rewrite "util to do a rewrite and datafy the result for easier comparison" @@ -110,8 +110,8 @@ (def rules-with-custom-functions (r/rules-rewriter - (synonyms "chickpea" "garbanzo bean") - (synonyms "chickpeas" "garbanzo beans"))) + (synonyms "chickpea" "garbanzo bean") + (synonyms "chickpeas" "garbanzo beans"))) (deftest custom-functions-test (facts "helper functions can return multiple match rules"