From d0e24718a137aa6200fa7777d3925a03d62e6647 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Tue, 27 Aug 2024 12:55:33 +0200 Subject: [PATCH] Make the gram root settable --- .../search/querytransform/NGramSearcher.java | 18 ++++++++++- .../test/NGramSearcherTestCase.java | 32 ++++++++++++++++--- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java b/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java index 7e5110f8ba1b..e27c482513a6 100644 --- a/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java +++ b/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java @@ -15,11 +15,16 @@ import com.yahoo.prelude.query.CompositeItem; import com.yahoo.prelude.query.HasIndexItem; import com.yahoo.prelude.query.Item; +import com.yahoo.prelude.query.NearItem; +import com.yahoo.prelude.query.ONearItem; +import com.yahoo.prelude.query.OrItem; import com.yahoo.prelude.query.PhraseItem; import com.yahoo.prelude.query.SegmentItem; import com.yahoo.prelude.query.Substring; import com.yahoo.prelude.query.TermItem; +import com.yahoo.prelude.query.WeakAndItem; import com.yahoo.prelude.query.WordItem; +import com.yahoo.processing.request.CompoundName; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.Searcher; @@ -44,6 +49,8 @@ @After(JUNIPER_TAG_REPLACING) public class NGramSearcher extends Searcher { + private static final CompoundName gramMatch = CompoundName.from("gram.match"); + private final GramSplitter gramSplitter; private final CharacterClasses characterClasses; @@ -151,7 +158,16 @@ protected CompositeItem createGramRoot(HasIndexItem term, Query query) { /** Creates the root of the query subtree without access to the term being replaced. */ protected CompositeItem createGramRoot(Query query) { - return new AndItem(); + return switch (query.properties().getString(gramMatch, "all")) { + case "all" -> new AndItem(); + case "any" -> new OrItem(); + case "weakAnd" -> new WeakAndItem(); + case "phrase" -> new PhraseItem(); + case "near" -> new NearItem(); + case "onear" -> new ONearItem(); + default -> throw new IllegalArgumentException("Invalid gram.match value '" + query.properties().getString(gramMatch) + + "'. Must be 'all', 'any', 'weakAnd', 'phrase', 'near' or 'onear'"); + }; } private void replaceItemByGrams(Item item, Item grams, int indexInParent) { diff --git a/container-search/src/test/java/com/yahoo/search/querytransform/test/NGramSearcherTestCase.java b/container-search/src/test/java/com/yahoo/search/querytransform/test/NGramSearcherTestCase.java index c7ec6b669058..9c4045a3ef50 100644 --- a/container-search/src/test/java/com/yahoo/search/querytransform/test/NGramSearcherTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/querytransform/test/NGramSearcherTestCase.java @@ -173,6 +173,30 @@ void testNGramRewritingShortOnly() { assertEquals("WEAKAND(100) gram3:en", q.getModel().getQueryTree().toString()); } + @Test + void testSettingGramMatching() { + assertEquals("WEAKAND(100) (AND gram2:en gram2:ng)", search("?query=gram2:eng")); + assertEquals("WEAKAND(100) (AND gram2:en gram2:ng)", search("?query=gram2:eng&gram.match=all")); + assertEquals("WEAKAND(100) (OR gram2:en gram2:ng)", search("?query=gram2:eng&gram.match=any")); + assertEquals("WEAKAND(100) (WEAKAND(100) gram2:en gram2:ng)", search("?query=gram2:eng&gram.match=weakAnd")); + assertEquals("WEAKAND(100) gram2:\"en ng\"", search("?query=gram2:eng&gram.match=phrase")); + assertEquals("WEAKAND(100) (NEAR(2) gram2:en gram2:ng)", search("?query=gram2:eng&gram.match=near")); + assertEquals("WEAKAND(100) (ONEAR(2) gram2:en gram2:ng)", search("?query=gram2:eng&gram.match=onear")); + try { + search("?query=gram2:eng&gram.match=invalid"); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertEquals("Invalid gram.match value 'invalid'. Must be 'all', 'any', 'weakAnd', 'phrase', 'near' or 'onear'", + e.getMessage()); + } + } + + String search(String query) { + Query q = new Query(query); + createExecution().search(q); + return q.getModel().getQueryTree().toString(); + } + @Test void testNGramRewritingShortInMixes() { Query q = new Query("?query=test:a+gram3:en"); @@ -335,19 +359,19 @@ void testNGramRecombining() { Hit h1 = r.hits().get("hit1"); assertEquals("Should be untouched,\u001feven if containing \u001f", h1.getField("test").toString()); - assertTrue(h1.getField("test") instanceof String); + assertInstanceOf(String.class, h1.getField("test")); assertEquals("Blue red Ed A", h1.getField("gram2").toString()); - assertTrue(h1.getField("gram2") instanceof XMLString); + assertInstanceOf(XMLString.class, h1.getField("gram2")); assertEquals("Blue red ed a\u001f", h1.getField("gram3").toString(), "Separators on borders work"); - assertTrue(h1.getField("gram3") instanceof String); + assertInstanceOf(String.class, h1.getField("gram3")); Hit h2 = r.hits().get("hit2"); assertEquals("katt i...morgen", h2.getField("gram3").toString()); - assertTrue(h2.getField("gram3") instanceof JSONString); + assertInstanceOf(JSONString.class, h2.getField("gram3")); Hit h3 = r.hits().get("hit3"); assertEquals("\u001ffin\u001f \u001fen\u001f \u001fa\u001f", h3.getField("gram2").toString());