Skip to content

Commit e4b4d0b

Browse files
committed
Backport fixes from LUCENE-5889, LUCENE-7564, and LUCENE-7670
1 parent d4d960f commit e4b4d0b

4 files changed

Lines changed: 287 additions & 47 deletions

File tree

src/Lucene.Net.Suggest/Suggest/Analyzing/AnalyzingInfixSuggester.cs

Lines changed: 123 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,14 @@ public class AnalyzingInfixSuggester : Lookup, IDisposable
9292
private readonly Directory dir;
9393
internal readonly int minPrefixChars;
9494
private readonly bool commitOnBuild;
95+
private readonly bool closeIndexWriterOnBuild; // LUCENENET specific - Support for LUCENE-7564.
9596
// LUCENENET specific - index writer config factory for extending classes
9697
private readonly IAnalyzingInfixSuggesterIndexWriterConfigFactory indexWriterConfigFactory;
9798

9899
/// <summary>
99100
/// Used for ongoing NRT additions/updates. </summary>
100-
private IndexWriter writer;
101+
// LUCENENET specific - changed from private to protected internal for LUCENE-7564 test support.
102+
protected internal IndexWriter writer;
101103

102104
/// <summary>
103105
/// <see cref="IndexSearcher"/> used for lookups. </summary>
@@ -109,6 +111,12 @@ public class AnalyzingInfixSuggester : Lookup, IDisposable
109111
/// </summary>
110112
public const int DEFAULT_MIN_PREFIX_CHARS = 4;
111113

114+
/// <summary>
115+
/// Default option to close the <see cref="IndexWriter"/> once the index has been built.
116+
/// </summary>
117+
// LUCENENET specific - Support for LUCENE-7564.
118+
protected const bool DEFAULT_CLOSE_INDEXWRITER_ON_BUILD = true;
119+
112120
/// <summary>
113121
/// How we sort the postings and search results. </summary>
114122
private static readonly Sort SORT = new Sort(new SortField("weight", SortFieldType.INT64, true));
@@ -138,8 +146,9 @@ public AnalyzingInfixSuggester(LuceneVersion matchVersion, Directory dir, Analyz
138146
/// Prefixes shorter than this are indexed as character
139147
/// ngrams (increasing index size but making lookups
140148
/// faster). </param>
141-
// LUCENENET specific - LUCENE-5889, a 4.11.0 feature. calls new constructor with extra param.
142-
// LUCENENET UPGRADE TODO: Remove method at version 4.11.0. Was retained for perfect 4.8 compatibility
149+
// LUCENENET specific - backported from LUCENE-5889 (4.11.0), LUCENE-7564 (6.4.0), LUCENE-7670 (6.4.1).
150+
// Calls new constructor with default values for commitOnBuild and closeIndexWriterOnBuild.
151+
// Retained for backwards compatibility.
143152
public AnalyzingInfixSuggester(LuceneVersion matchVersion, Directory dir, Analyzer indexAnalyzer,
144153
Analyzer queryAnalyzer, int minPrefixChars)
145154
: this(matchVersion, dir, indexAnalyzer, queryAnalyzer, minPrefixChars, commitOnBuild: false)
@@ -165,7 +174,33 @@ public AnalyzingInfixSuggester(LuceneVersion matchVersion, Directory dir, Analyz
165174
// LUCENENET specific - LUCENE-5889, a 4.11.0 feature. (Code moved from other constructor to here.)
166175
public AnalyzingInfixSuggester(LuceneVersion matchVersion, Directory dir, Analyzer indexAnalyzer,
167176
Analyzer queryAnalyzer, int minPrefixChars, bool commitOnBuild)
168-
: this(new AnalyzingInfixSuggesterIndexWriterConfigFactory(SORT), matchVersion, dir, indexAnalyzer, queryAnalyzer, minPrefixChars, commitOnBuild)
177+
: this(matchVersion, dir, indexAnalyzer, queryAnalyzer, minPrefixChars, commitOnBuild, DEFAULT_CLOSE_INDEXWRITER_ON_BUILD)
178+
{
179+
}
180+
181+
/// <summary>
182+
/// Create a new instance, loading from a previously built
183+
/// <see cref="AnalyzingInfixSuggester"/> directory, if it exists. This directory must be
184+
/// private to the infix suggester (i.e., not an external
185+
/// Lucene index). Note that <see cref="Dispose()"/>
186+
/// will also dispose the provided directory.
187+
/// </summary>
188+
/// <param name="minPrefixChars"> Minimum number of leading characters
189+
/// before <see cref="PrefixQuery"/> is used (default 4).
190+
/// Prefixes shorter than this are indexed as character
191+
/// ngrams (increasing index size but making lookups
192+
/// faster). </param>
193+
/// <param name="commitOnBuild"> Call commit after the index has finished building. This
194+
/// would persist the suggester index to disk and future instances of this suggester can
195+
/// use this pre-built dictionary. </param>
196+
/// <param name="closeIndexWriterOnBuild"> If <c>true</c>, the <see cref="IndexWriter"/> will be closed
197+
/// after the index has finished building. </param>
198+
// LUCENENET specific - closeIndexWriterOnBuild backported from LUCENE-7564.
199+
// Note: Java's equivalent constructor also has allTermsRequired and highlight parameters, which
200+
// are not present here because those are method-level parameters in this version of Lucene.NET.
201+
public AnalyzingInfixSuggester(LuceneVersion matchVersion, Directory dir, Analyzer indexAnalyzer,
202+
Analyzer queryAnalyzer, int minPrefixChars, bool commitOnBuild, bool closeIndexWriterOnBuild)
203+
: this(new AnalyzingInfixSuggesterIndexWriterConfigFactory(SORT), matchVersion, dir, indexAnalyzer, queryAnalyzer, minPrefixChars, commitOnBuild, closeIndexWriterOnBuild)
169204
{
170205
}
171206

@@ -186,14 +221,41 @@ public AnalyzingInfixSuggester(LuceneVersion matchVersion, Directory dir, Analyz
186221
/// use this pre-built dictionary. </param>
187222
/// <param name="indexWriterConfigFactory"> Factory for creating the <see cref="IndexWriterConfig"/>. </param>
188223
// LUCENENET specific - added indexWriterConfigFactory parameter to allow for customizing the index writer config.
224+
// Retained for backwards compatibility.
189225
public AnalyzingInfixSuggester(IAnalyzingInfixSuggesterIndexWriterConfigFactory indexWriterConfigFactory, LuceneVersion matchVersion,
190226
Directory dir, Analyzer indexAnalyzer, Analyzer queryAnalyzer, int minPrefixChars, bool commitOnBuild)
227+
: this(indexWriterConfigFactory, matchVersion, dir, indexAnalyzer, queryAnalyzer, minPrefixChars, commitOnBuild, DEFAULT_CLOSE_INDEXWRITER_ON_BUILD)
228+
{
229+
}
230+
231+
/// <summary>
232+
/// Create a new instance, loading from a previously built
233+
/// <see cref="AnalyzingInfixSuggester"/> directory, if it exists. This directory must be
234+
/// private to the infix suggester (i.e., not an external
235+
/// Lucene index). Note that <see cref="Dispose()"/>
236+
/// will also dispose the provided directory.
237+
/// </summary>
238+
/// <param name="minPrefixChars"> Minimum number of leading characters
239+
/// before <see cref="PrefixQuery"/> is used (default 4).
240+
/// Prefixes shorter than this are indexed as character
241+
/// ngrams (increasing index size but making lookups
242+
/// faster). </param>
243+
/// <param name="commitOnBuild"> Call commit after the index has finished building. This
244+
/// would persist the suggester index to disk and future instances of this suggester can
245+
/// use this pre-built dictionary. </param>
246+
/// <param name="closeIndexWriterOnBuild"> If <c>true</c>, the <see cref="IndexWriter"/> will be closed
247+
/// after the index has finished building. </param>
248+
/// <param name="indexWriterConfigFactory"> Factory for creating the <see cref="IndexWriterConfig"/>. </param>
249+
// LUCENENET specific - added indexWriterConfigFactory and closeIndexWriterOnBuild parameters.
250+
public AnalyzingInfixSuggester(IAnalyzingInfixSuggesterIndexWriterConfigFactory indexWriterConfigFactory, LuceneVersion matchVersion,
251+
Directory dir, Analyzer indexAnalyzer, Analyzer queryAnalyzer, int minPrefixChars, bool commitOnBuild, bool closeIndexWriterOnBuild)
191252
{
192253
if (minPrefixChars < 0)
193254
{
194255
throw new ArgumentOutOfRangeException(nameof(minPrefixChars), "minPrefixChars must be >= 0; got: " + minPrefixChars);// LUCENENET specific - changed from IllegalArgumentException to ArgumentOutOfRangeException (.NET convention)
195256
}
196257

258+
// LUCENENET specific - moved IndexWriterConfig to AnalyzingInfixSuggesterIndexWriterConfigFactory
197259
if (indexWriterConfigFactory is null) throw new ArgumentNullException(nameof(indexWriterConfigFactory));
198260

199261
this.m_queryAnalyzer = queryAnalyzer;
@@ -202,14 +264,19 @@ public AnalyzingInfixSuggester(IAnalyzingInfixSuggesterIndexWriterConfigFactory
202264
this.dir = dir;
203265
this.minPrefixChars = minPrefixChars;
204266
this.commitOnBuild = commitOnBuild;
267+
this.closeIndexWriterOnBuild = closeIndexWriterOnBuild;
205268
this.indexWriterConfigFactory = indexWriterConfigFactory;
206269

207270
if (DirectoryReader.IndexExists(dir))
208271
{
209272
// Already built; open it:
210-
var config = indexWriterConfigFactory.Get(matchVersion, GetGramAnalyzer(), OpenMode.APPEND);
211-
writer = new IndexWriter(dir, config);
212-
m_searcherMgr = new SearcherManager(writer, true, null);
273+
274+
// LUCENENET specific - backported fix from Lucene 6.4.1 to fix #1242. previously was:
275+
// var config = indexWriterConfigFactory.Get(matchVersion, GetGramAnalyzer(), OpenMode.APPEND);
276+
// writer = new IndexWriter(dir, config);
277+
// m_searcherMgr = new SearcherManager(writer, true, null);
278+
279+
m_searcherMgr = new SearcherManager(dir, null);
213280
}
214281
}
215282

@@ -268,7 +335,7 @@ public override void Build(IInputEnumerator enumerator)
268335
}
269336

270337
//System.out.println("initial indexing time: " + ((System.nanoTime()-t0)/1000000) + " msec");
271-
if (commitOnBuild) //LUCENENET specific -Support for LUCENE - 5889.
338+
if (commitOnBuild || closeIndexWriterOnBuild) // LUCENENET specific - Support for LUCENE-5889, LUCENE-7564.
272339
{
273340
Commit();
274341
}
@@ -279,24 +346,40 @@ public override void Build(IInputEnumerator enumerator)
279346
{
280347
if (success)
281348
{
349+
if (closeIndexWriterOnBuild) // LUCENENET specific - Support for LUCENE-7564.
350+
{
351+
writer.Dispose();
352+
writer = null;
353+
}
282354
IOUtils.Dispose(r);
283355
}
284356
else
285357
{
286-
IOUtils.DisposeWhileHandlingException(writer, r);
287-
writer = null;
358+
if (writer != null)
359+
{
360+
writer.Rollback();
361+
writer = null;
362+
}
363+
IOUtils.DisposeWhileHandlingException(r);
288364
}
289365
}
290366
}
291367

292-
// LUCENENET specific -Support for LUCENE-5889.
368+
// LUCENENET specific - Support for LUCENE-5889, LUCENE-7564.
293369
public void Commit()
294370
{
295371
if (writer is null)
296372
{
297-
throw IllegalStateException.Create("Cannot commit on an closed writer. Add documents first");
373+
if (m_searcherMgr is null || closeIndexWriterOnBuild == false)
374+
{
375+
throw IllegalStateException.Create("Cannot commit on an closed writer. Add documents first");
376+
}
377+
// else no-op: writer was committed and closed after the index was built, so commit is unnecessary
378+
}
379+
else
380+
{
381+
writer.Commit();
298382
}
299-
writer.Commit();
300383
}
301384

302385
private Analyzer GetGramAnalyzer()
@@ -335,7 +418,7 @@ protected override TokenStreamComponents WrapComponents(string fieldName, TokenS
335418
}
336419
}
337420

338-
//LUCENENET specific -Support for LUCENE - 5889.
421+
// LUCENENET specific - Support for LUCENE-5889, LUCENE-7564.
339422
private void EnsureOpen()
340423
{
341424
if (writer != null)
@@ -346,13 +429,21 @@ private void EnsureOpen()
346429
{
347430
if (writer is null)
348431
{
349-
if (m_searcherMgr != null)
432+
if (DirectoryReader.IndexExists(dir))
433+
{
434+
// Already built; open it:
435+
writer = new IndexWriter(dir, indexWriterConfigFactory.Get(matchVersion, GetGramAnalyzer(), OpenMode.APPEND));
436+
}
437+
else
350438
{
351-
m_searcherMgr.Dispose();
352-
m_searcherMgr = null;
439+
writer = new IndexWriter(dir, indexWriterConfigFactory.Get(matchVersion, GetGramAnalyzer(), OpenMode.CREATE));
353440
}
354-
writer = new IndexWriter(dir, indexWriterConfigFactory.Get(matchVersion, GetGramAnalyzer(), OpenMode.CREATE));
441+
SearcherManager oldSearcherMgr = m_searcherMgr;
355442
m_searcherMgr = new SearcherManager(writer, true, null);
443+
if (oldSearcherMgr != null)
444+
{
445+
oldSearcherMgr.Dispose();
446+
}
356447
}
357448
}
358449
finally
@@ -370,21 +461,22 @@ private void EnsureOpen()
370461
/// </summary>
371462
public virtual void Add(BytesRef text, IEnumerable<BytesRef> contexts, long weight, BytesRef payload)
372463
{
373-
EnsureOpen(); //LUCENENET specific -Support for LUCENE - 5889.
464+
EnsureOpen(); // LUCENENET specific - Support for LUCENE-5889.
374465
writer.AddDocument(BuildDocument(text, contexts, weight, payload));
375466
}
376467

377468
/// <summary>
378469
/// Updates a previous suggestion, matching the exact same
379470
/// text as before. Use this to change the weight or
380-
/// payload of an already added suggstion. If you know
471+
/// payload of an already added suggestion. If you know
381472
/// this text is not already present you can use <see cref="Add"/>
382473
/// instead. After adding or updating a batch of
383474
/// new suggestions, you must call <see cref="Refresh()"/> in the
384475
/// end in order to see the suggestions in <see cref="DoLookup(string, IEnumerable{BytesRef}, int, bool, bool, CancellationToken)"/>
385476
/// </summary>
386477
public virtual void Update(BytesRef text, IEnumerable<BytesRef> contexts, long weight, BytesRef payload)
387478
{
479+
EnsureOpen(); // LUCENENET specific - Support for LUCENE-5889.
388480
writer.UpdateDocument(new Term(EXACT_TEXT_FIELD_NAME, text.Utf8ToString()), BuildDocument(text, contexts, weight, payload));
389481
}
390482

@@ -424,11 +516,16 @@ private Document BuildDocument(BytesRef text, IEnumerable<BytesRef> contexts, lo
424516
/// </summary>
425517
public virtual void Refresh()
426518
{
427-
if (m_searcherMgr is null) // LUCENENET specific -Support for LUCENE-5889.
519+
if (m_searcherMgr is null) // LUCENENET specific - Support for LUCENE-5889.
428520
{
429521
throw IllegalStateException.Create("suggester was not built");
430522
}
431-
m_searcherMgr.MaybeRefreshBlocking();
523+
if (writer != null) // LUCENENET specific - Support for LUCENE-7564.
524+
{
525+
m_searcherMgr.MaybeRefreshBlocking();
526+
}
527+
// else no-op: writer was committed and closed after the index was built
528+
// and before searcherMgr was constructed, so refresh is unnecessary
432529
}
433530

434531
/// <summary>
@@ -851,9 +948,12 @@ protected virtual void Dispose(bool disposing) // LUCENENET specific - implement
851948
if (writer != null)
852949
{
853950
writer.Dispose();
854-
dir.Dispose();
855951
writer = null;
856952
}
953+
if (dir != null) // LUCENENET specific - Support for LUCENE-7564. Close dir even when writer is null.
954+
{
955+
dir.Dispose();
956+
}
857957
}
858958
}
859959

src/Lucene.Net.Suggest/Suggest/Analyzing/BlendedInfixSuggester.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ public BlendedInfixSuggester(LuceneVersion matchVersion, Directory dir, Analyzer
105105
/// <param name="blenderType"> Type of blending strategy, see BlenderType for more precisions </param>
106106
/// <param name="numFactor"> Factor to multiply the number of searched elements before ponderate </param>
107107
/// <exception cref="IOException"> If there are problems opening the underlying Lucene index. </exception>
108-
// LUCENENET specific - LUCENE-5889, a 4.11.0 feature. calls new constructor with extra param.
109-
// LUCENENET UPGRADE TODO: Remove method at version 4.11.0. Was retained for perfect 4.8 compatibility
108+
// LUCENENET specific - retained for backwards compatibility. Calls new constructor with default
109+
// commitOnBuild value. Java does not have this overload without commitOnBuild post-LUCENE-5889.
110110
public BlendedInfixSuggester(LuceneVersion matchVersion, Directory dir, Analyzer indexAnalyzer, Analyzer queryAnalyzer, int minPrefixChars,
111111
BlenderType blenderType, int numFactor)
112112
: this(matchVersion, dir, indexAnalyzer, queryAnalyzer, minPrefixChars, blenderType, numFactor, commitOnBuild: false)

0 commit comments

Comments
 (0)