You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by sa...@apache.org on 2016/11/16 23:10:23 UTC
[2/2] lucene-solr:branch_6x: LUCENE-7564: AnalyzingInfixSuggester
should close its IndexWriter by default at the end of build()
LUCENE-7564: AnalyzingInfixSuggester should close its IndexWriter by default at the end of build()
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/4fedb640
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/4fedb640
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/4fedb640
Branch: refs/heads/branch_6x
Commit: 4fedb640ab66920ea11c26ad520639912c95ff2c
Parents: 8bd4ad3
Author: Steve Rowe <sa...@apache.org>
Authored: Wed Nov 16 18:03:51 2016 -0500
Committer: Steve Rowe <sa...@apache.org>
Committed: Wed Nov 16 18:04:13 2016 -0500
----------------------------------------------------------------------
lucene/CHANGES.txt | 3 +
.../analyzing/AnalyzingInfixSuggester.java | 82 +++++++++++---
.../analyzing/AnalyzingInfixSuggesterTest.java | 111 +++++++++++++++++++
3 files changed, 181 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4fedb640/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 3aa6042..c252da8 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -39,6 +39,9 @@ Improvements
* LUCENE-7524: Added more detailed explanation of how IDF is computed in
ClassicSimilarity and BM25Similarity. (Adrien Grand)
+
+* LUCENE-7564: AnalyzingInfixSuggester should close its IndexWriter by default
+ at the end of build(). (Steve Rowe)
* LUCENE-7526: Enhanced UnifiedHighlighter's passage relevancy for queries with
wildcards and sometimes just terms. Added shouldPreferPassageRelevancyOverSpeed()
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4fedb640/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java
----------------------------------------------------------------------
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 3cb8ae4..1e98361 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,9 +129,10 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
private final boolean highlight;
private final boolean commitOnBuild;
+ private final boolean closeIndexWriterOnBuild;
/** Used for ongoing NRT additions/updates. */
- private IndexWriter writer;
+ protected IndexWriter writer;
/** {@link IndexSearcher} used for lookups. */
protected SearcherManager searcherMgr;
@@ -146,6 +147,9 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
/** Default higlighting option. */
public static final boolean DEFAULT_HIGHLIGHT = true;
+ /** Default option to close the IndexWriter once the index has been built. */
+ protected final static boolean DEFAULT_CLOSE_INDEXWRITER_ON_BUILD = true;
+
/** How we sort the postings and search results. */
private static final Sort SORT = new Sort(new SortField("weight", SortField.Type.LONG, true));
@@ -198,8 +202,34 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
*
*/
public AnalyzingInfixSuggester(Directory dir, Analyzer indexAnalyzer, Analyzer queryAnalyzer, int minPrefixChars,
- boolean commitOnBuild,
+ boolean commitOnBuild,
boolean allTermsRequired, boolean highlight) throws IOException {
+ this(dir, indexAnalyzer, queryAnalyzer, minPrefixChars, commitOnBuild, allTermsRequired, highlight,
+ DEFAULT_CLOSE_INDEXWRITER_ON_BUILD);
+ }
+
+ /** 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.
+ * @param closeIndexWriterOnBuild If true, the IndexWriter will be closed after the index has finished building.
+ */
+ public AnalyzingInfixSuggester(Directory dir, Analyzer indexAnalyzer, Analyzer queryAnalyzer, int minPrefixChars,
+ boolean commitOnBuild, boolean allTermsRequired,
+ boolean highlight, boolean closeIndexWriterOnBuild) throws IOException {
if (minPrefixChars < 0) {
throw new IllegalArgumentException("minPrefixChars must be >= 0; got: " + minPrefixChars);
@@ -212,6 +242,7 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
this.commitOnBuild = commitOnBuild;
this.allTermsRequired = allTermsRequired;
this.highlight = highlight;
+ this.closeIndexWriterOnBuild = closeIndexWriterOnBuild;
if (DirectoryReader.indexExists(dir)) {
// Already built; open it:
@@ -276,15 +307,22 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
}
//System.out.println("initial indexing time: " + ((System.nanoTime()-t0)/1000000) + " msec");
- if (commitOnBuild) {
+ if (commitOnBuild || closeIndexWriterOnBuild) {
commit();
}
searcherMgr = new SearcherManager(writer, null);
success = true;
} finally {
- if (success == false && writer != null) {
- writer.rollback();
- writer = null;
+ if (success) {
+ if (closeIndexWriterOnBuild) {
+ writer.close();
+ writer = null;
+ }
+ } else { // failure
+ if (writer != null) {
+ writer.rollback();
+ writer = null;
+ }
}
}
}
@@ -294,9 +332,13 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
* @see IndexWriter#commit */
public void commit() throws IOException {
if (writer == null) {
- throw new IllegalStateException("Cannot commit on an closed writer. Add documents first");
+ if (searcherMgr == null || closeIndexWriterOnBuild == false) {
+ throw new IllegalStateException("Cannot commit on an closed writer. Add documents first");
+ }
+ // else no-op: writer was committed and closed after the index was built, so commit is unnecessary
+ } else {
+ writer.commit();
}
- writer.commit();
}
private Analyzer getGramAnalyzer() {
@@ -321,13 +363,17 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
private synchronized void ensureOpen() throws IOException {
if (writer == null) {
- if (searcherMgr != null) {
- searcherMgr.close();
- searcherMgr = null;
+ if (DirectoryReader.indexExists(dir)) {
+ // Already built; open it:
+ writer = new IndexWriter(dir, getIndexWriterConfig(getGramAnalyzer(), IndexWriterConfig.OpenMode.APPEND));
+ } else {
+ writer = new IndexWriter(dir, getIndexWriterConfig(getGramAnalyzer(), IndexWriterConfig.OpenMode.CREATE));
}
- writer = new IndexWriter(dir,
- getIndexWriterConfig(getGramAnalyzer(), IndexWriterConfig.OpenMode.CREATE));
+ SearcherManager oldSearcherMgr = searcherMgr;
searcherMgr = new SearcherManager(writer, null);
+ if (oldSearcherMgr != null) {
+ oldSearcherMgr.close();
+ }
}
}
@@ -382,7 +428,11 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
if (searcherMgr == null) {
throw new IllegalStateException("suggester was not built");
}
- searcherMgr.maybeRefreshBlocking();
+ if (writer != null) {
+ searcherMgr.maybeRefreshBlocking();
+ }
+ // else no-op: writer was committed and closed after the index was built
+ // and before searchMgr was constructed, so refresh is unnecessary
}
/**
@@ -784,9 +834,11 @@ public class AnalyzingInfixSuggester extends Lookup implements Closeable {
}
if (writer != null) {
writer.close();
- dir.close();
writer = null;
}
+ if (dir != null) {
+ dir.close();
+ }
}
@Override
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/4fedb640/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggesterTest.java
----------------------------------------------------------------------
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 d98d052..fc5e2b7 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
@@ -35,11 +35,14 @@ import org.apache.lucene.analysis.StopFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
+import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.search.suggest.Input;
import org.apache.lucene.search.suggest.InputArrayIterator;
import org.apache.lucene.search.suggest.Lookup.LookupResult;
+import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IOUtils;
@@ -1334,4 +1337,112 @@ public class AnalyzingInfixSuggesterTest extends LuceneTestCase {
suggester.close();
}
+
+ public void testCloseIndexWriterOnBuild() throws Exception {
+ class MyAnalyzingInfixSuggester extends AnalyzingInfixSuggester {
+ public MyAnalyzingInfixSuggester(Directory dir, Analyzer indexAnalyzer, Analyzer queryAnalyzer,
+ int minPrefixChars, boolean commitOnBuild, boolean allTermsRequired,
+ boolean highlight, boolean closeIndexWriterOnBuild) throws IOException {
+ super(dir, indexAnalyzer, queryAnalyzer, minPrefixChars, commitOnBuild,
+ allTermsRequired, highlight, closeIndexWriterOnBuild);
+ }
+ public IndexWriter getIndexWriter() {
+ return writer;
+ }
+ public SearcherManager getSearcherManager() {
+ return searcherMgr;
+ }
+ }
+
+ // After build(), when closeIndexWriterOnBuild = true:
+ // * The IndexWriter should be null
+ // * The SearcherManager should be non-null
+ // * SearcherManager's IndexWriter reference should be closed
+ // (as evidenced by maybeRefreshBlocking() throwing AlreadyClosedException)
+ Analyzer a = new MockAnalyzer(random(), MockTokenizer.WHITESPACE, false);
+ MyAnalyzingInfixSuggester suggester = new MyAnalyzingInfixSuggester(newDirectory(), a, a, 3, false,
+ AnalyzingInfixSuggester.DEFAULT_ALL_TERMS_REQUIRED, AnalyzingInfixSuggester.DEFAULT_HIGHLIGHT, true);
+ suggester.build(new InputArrayIterator(sharedInputs));
+ assertNull(suggester.getIndexWriter());
+ assertNotNull(suggester.getSearcherManager());
+ expectThrows(AlreadyClosedException.class, () -> suggester.getSearcherManager().maybeRefreshBlocking());
+
+ suggester.close();
+ a.close();
+ }
+
+ public void testCommitAfterBuild() throws Exception {
+ performOperationWithAllOptionCombinations(suggester -> {
+ suggester.build(new InputArrayIterator(sharedInputs));
+ suggester.commit();
+ });
+ }
+
+ public void testRefreshAfterBuild() throws Exception {
+ performOperationWithAllOptionCombinations(suggester -> {
+ suggester.build(new InputArrayIterator(sharedInputs));
+ suggester.refresh();
+ });
+ }
+
+ public void testDisallowCommitBeforeBuild() throws Exception {
+ performOperationWithAllOptionCombinations
+ (suggester -> expectThrows(IllegalStateException.class, suggester::commit));
+ }
+
+ public void testDisallowRefreshBeforeBuild() throws Exception {
+ performOperationWithAllOptionCombinations
+ (suggester -> expectThrows(IllegalStateException.class, suggester::refresh));
+ }
+
+ private Input sharedInputs[] = new Input[] {
+ new Input("lend me your ear", 8, new BytesRef("foobar")),
+ new Input("a penny saved is a penny earned", 10, new BytesRef("foobaz")),
+ };
+
+ private interface SuggesterOperation {
+ void operate(AnalyzingInfixSuggester suggester) throws Exception;
+ }
+
+ /**
+ * Perform the given operation on suggesters constructed with all combinations of options
+ * commitOnBuild and closeIndexWriterOnBuild, including defaults.
+ */
+ private void performOperationWithAllOptionCombinations(SuggesterOperation operation) throws Exception {
+ Analyzer a = new MockAnalyzer(random(), MockTokenizer.WHITESPACE, false);
+
+ AnalyzingInfixSuggester suggester = new AnalyzingInfixSuggester(newDirectory(), a);
+ operation.operate(suggester);
+ suggester.close();
+
+ suggester = new AnalyzingInfixSuggester(newDirectory(), a, a, 3, false);
+ operation.operate(suggester);
+ suggester.close();
+
+ suggester = new AnalyzingInfixSuggester(newDirectory(), a, a, 3, true);
+ operation.operate(suggester);
+ suggester.close();
+
+ suggester = new AnalyzingInfixSuggester(newDirectory(), a, a, 3, true,
+ AnalyzingInfixSuggester.DEFAULT_ALL_TERMS_REQUIRED, AnalyzingInfixSuggester.DEFAULT_HIGHLIGHT, true);
+ operation.operate(suggester);
+ suggester.close();
+
+ suggester = new AnalyzingInfixSuggester(newDirectory(), a, a, 3, true,
+ AnalyzingInfixSuggester.DEFAULT_ALL_TERMS_REQUIRED, AnalyzingInfixSuggester.DEFAULT_HIGHLIGHT, false);
+ operation.operate(suggester);
+ suggester.close();
+
+ suggester = new AnalyzingInfixSuggester(newDirectory(), a, a, 3, false,
+ AnalyzingInfixSuggester.DEFAULT_ALL_TERMS_REQUIRED, AnalyzingInfixSuggester.DEFAULT_HIGHLIGHT, true);
+ operation.operate(suggester);
+ suggester.close();
+
+ suggester = new AnalyzingInfixSuggester(newDirectory(), a, a, 3, false,
+ AnalyzingInfixSuggester.DEFAULT_ALL_TERMS_REQUIRED, AnalyzingInfixSuggester.DEFAULT_HIGHLIGHT, false);
+ operation.operate(suggester);
+ suggester.close();
+
+ a.close();
+ }
}