diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index cc722e74828..275bbc24d0d 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -343,6 +343,10 @@ API Changes * LUCENE-6146: Replaced Directory.copy() with Directory.copyFrom(). (Robert Muir) +* LUCENE-6149: Infix suggesters' highlighting and allTermsRequired can + be set at the constructor for non-contextual lookup. + (Boon Low, Tomás Fernández Löbbe) + Bug Fixes * LUCENE-5650: Enforce read-only access to any path outside the temporary diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java index c1db1e0c4fe..45cd8c602d0 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java @@ -129,6 +129,10 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable { protected final Analyzer indexAnalyzer; private final Directory dir; final int minPrefixChars; + + private final boolean allTermsRequired; + private final boolean highlight; + private final boolean commitOnBuild; /** Used for ongoing NRT additions/updates. */ @@ -140,6 +144,12 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable { /** Default minimum number of leading characters before * PrefixQuery is used (4). */ public static final int DEFAULT_MIN_PREFIX_CHARS = 4; + + /** Default boolean clause option for multiple terms matching (all terms required). */ + public static final boolean DEFAULT_ALL_TERMS_REQUIRED = true; + + /** Default higlighting option. */ + public static final boolean DEFAULT_HIGHLIGHT = true; /** How we sort the postings and search results. */ private static final Sort SORT = new Sort(new SortField("weight", SortField.Type.LONG, true)); @@ -150,9 +160,9 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable { * Lucene index). Note that {@link #close} * will also close the provided directory. */ public AnalyzingInfixSuggester(Directory dir, Analyzer analyzer) throws IOException { - this(dir, analyzer, analyzer, DEFAULT_MIN_PREFIX_CHARS, false); + this(dir, analyzer, analyzer, DEFAULT_MIN_PREFIX_CHARS, false, DEFAULT_ALL_TERMS_REQUIRED, DEFAULT_HIGHLIGHT); } - + /** Create a new instance, loading from a previously built * AnalyzingInfixSuggester directory, if it exists. This directory must be * private to the infix suggester (i.e., not an external @@ -170,7 +180,32 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable { */ public AnalyzingInfixSuggester(Directory dir, Analyzer indexAnalyzer, Analyzer queryAnalyzer, int minPrefixChars, boolean commitOnBuild) throws IOException { - + this(dir, indexAnalyzer, queryAnalyzer, minPrefixChars, commitOnBuild, DEFAULT_ALL_TERMS_REQUIRED, DEFAULT_HIGHLIGHT); + } + + /** Create a new instance, loading from a previously built + * AnalyzingInfixSuggester directory, if it exists. This directory must be + * private to the infix suggester (i.e., not an external + * Lucene index). Note that {@link #close} + * will also close the provided directory. + * + * @param minPrefixChars Minimum number of leading characters + * before PrefixQuery is used (default 4). + * Prefixes shorter than this are indexed as character + * ngrams (increasing index size but making lookups + * faster). + * + * @param commitOnBuild Call commit after the index has finished building. This would persist the + * suggester index to disk and future instances of this suggester can use this pre-built dictionary. + * + * @param allTermsRequired All terms in the suggest query must be matched. + * @param highlight Highlight suggest query in suggestions. + * + */ + public AnalyzingInfixSuggester(Directory dir, Analyzer indexAnalyzer, Analyzer queryAnalyzer, int minPrefixChars, + boolean commitOnBuild, + boolean allTermsRequired, boolean highlight) throws IOException { + if (minPrefixChars < 0) { throw new IllegalArgumentException("minPrefixChars must be >= 0; got: " + minPrefixChars); } @@ -180,6 +215,8 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable { this.dir = dir; this.minPrefixChars = minPrefixChars; this.commitOnBuild = commitOnBuild; + this.allTermsRequired = allTermsRequired; + this.highlight = highlight; if (DirectoryReader.indexExists(dir)) { // Already built; open it: @@ -369,7 +406,7 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable { @Override public List lookup(CharSequence key, Set contexts, boolean onlyMorePopular, int num) throws IOException { - return lookup(key, contexts, num, true, true); + return lookup(key, contexts, num, allTermsRequired, highlight); } /** Lookup, without any context. */ diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/BlendedInfixSuggester.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/BlendedInfixSuggester.java index 0ccaed39bb9..7c05665d935 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/BlendedInfixSuggester.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/BlendedInfixSuggester.java @@ -117,7 +117,27 @@ public class BlendedInfixSuggester extends AnalyzingInfixSuggester { this.blenderType = blenderType; this.numFactor = numFactor; } - + + /** + * Create a new instance, loading from a previously built + * directory, if it exists. + * + * @param blenderType Type of blending strategy, see BlenderType for more precisions + * @param numFactor Factor to multiply the number of searched elements before ponderate + * @param commitOnBuild Call commit after the index has finished building. This would persist the + * suggester index to disk and future instances of this suggester can use this pre-built dictionary. + * @param allTermsRequired All terms in the suggest query must be matched. + * @param highlight Highlight suggest query in suggestions. + * @throws IOException If there are problems opening the underlying Lucene index. + */ + public BlendedInfixSuggester(Directory dir, Analyzer indexAnalyzer, Analyzer queryAnalyzer, + int minPrefixChars, BlenderType blenderType, int numFactor, + boolean commitOnBuild, boolean allTermsRequired, boolean highlight) throws IOException { + super(dir, indexAnalyzer, queryAnalyzer, minPrefixChars, commitOnBuild, allTermsRequired, highlight); + this.blenderType = blenderType; + this.numFactor = numFactor; + } + @Override public List lookup(CharSequence key, Set contexts, boolean onlyMorePopular, int num) throws IOException { // here we multiply the number of searched element by the defined factor diff --git a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggesterTest.java b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggesterTest.java index 71e4177f048..1b001ab681f 100644 --- a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggesterTest.java +++ b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggesterTest.java @@ -91,10 +91,50 @@ public class AnalyzingInfixSuggesterTest extends LuceneTestCase { assertEquals("a penny saved is a penny earned", results.get(0).highlightKey); assertEquals(10, results.get(0).value); assertEquals(new BytesRef("foobaz"), results.get(0).payload); - + + results = suggester.lookup(TestUtil.stringToCharSequence("money penny", random()), 10, false, true); + assertEquals(1, results.size()); + assertEquals("a penny saved is a penny earned", results.get(0).key); + assertEquals("a penny saved is a penny earned", results.get(0).highlightKey); + assertEquals(10, results.get(0).value); + assertEquals(new BytesRef("foobaz"), results.get(0).payload); + + results = suggester.lookup(TestUtil.stringToCharSequence("penny ea", random()), 10, false, true); + assertEquals(2, results.size()); + assertEquals("a penny saved is a penny earned", results.get(0).key); + assertEquals("a penny saved is a penny earned", results.get(0).highlightKey); + assertEquals("lend me your ear", results.get(1).key); + assertEquals("lend me your ear", results.get(1).highlightKey); + + results = suggester.lookup(TestUtil.stringToCharSequence("money penny", random()), 10, false, false); + assertEquals(1, results.size()); + assertEquals("a penny saved is a penny earned", results.get(0).key); + assertNull(results.get(0).highlightKey); + + testConstructorDefatuls(suggester, keys, a, true, true); + testConstructorDefatuls(suggester, keys, a, true, false); + testConstructorDefatuls(suggester, keys, a, false, false); + testConstructorDefatuls(suggester, keys, a, false, true); + suggester.close(); } + private void testConstructorDefatuls(AnalyzingInfixSuggester suggester, Input[] keys, Analyzer a, + boolean allTermsRequired, boolean highlight) throws IOException { + AnalyzingInfixSuggester suggester2 = new AnalyzingInfixSuggester(newDirectory(), a, a, 3, false, allTermsRequired, highlight); + suggester2.build(new InputArrayIterator(keys)); + + CharSequence key = TestUtil.stringToCharSequence("penny ea", random()); + + List results1 = suggester.lookup(key, 10, allTermsRequired, highlight); + List results2 = suggester2.lookup(key, false, 10); + assertEquals(results1.size(), results2.size()); + assertEquals(results1.get(0).key, results2.get(0).key); + assertEquals(results1.get(0).highlightKey, results2.get(0).highlightKey); + + suggester2.close(); + } + public void testAfterLoad() throws Exception { Input keys[] = new Input[] { new Input("lend me your ear", 8, new BytesRef("foobar")),