From a48f8e7681fc7c10ddad15cb8c76802f577ffa5f Mon Sep 17 00:00:00 2001 From: Yizuo Tian Date: Mon, 16 May 2022 16:45:23 -0700 Subject: [PATCH] Resolves #1676: Lucene merge based on probability --- docs/ReleaseNotes.md | 2 +- .../record/lucene/LuceneLogMessageKeys.java | 2 + .../lucene/LuceneRecordContextProperties.java | 5 +++ ...endedInfixSuggesterWithoutTermVectors.java | 35 ++++++++++++++-- ...OptimizedWrappedBlendedInfixSuggester.java | 41 ++++++++++++++++--- .../lucene/directory/FDBDirectoryManager.java | 34 ++++++++++++++- .../lucene/directory/FDBDirectoryWrapper.java | 36 ++++++++++++++-- 7 files changed, 140 insertions(+), 15 deletions(-) diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index b51109152a..84d14d3a43 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -25,7 +25,7 @@ This release also updates downstream dependency versions. Most notably, the prot * **Bug fix** Fix 3 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN) * **Bug fix** Fix 4 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN) * **Bug fix** Fix 5 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN) -* **Performance** Improvement 1 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN) +* **Performance** Lucene merge based on probability [(Issue #1676)](https://github.com/FoundationDB/fdb-record-layer/issues/1676) * **Performance** Improvement 2 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN) * **Performance** Improvement 3 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN) * **Performance** Improvement 4 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN) diff --git a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/LuceneLogMessageKeys.java b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/LuceneLogMessageKeys.java index e2032bdbed..6646be4d5a 100644 --- a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/LuceneLogMessageKeys.java +++ b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/LuceneLogMessageKeys.java @@ -59,6 +59,8 @@ public enum LuceneLogMessageKeys { INPUT, LENGTH, LOCK_NAME, + MERGE_SOURCE, + MERGE_TRIGGER, OFFSET, ORIGINAL_DATA_SIZE, POINTER, diff --git a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/LuceneRecordContextProperties.java b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/LuceneRecordContextProperties.java index 0077cc6162..62e6c2ca73 100644 --- a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/LuceneRecordContextProperties.java +++ b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/LuceneRecordContextProperties.java @@ -104,4 +104,9 @@ public final class LuceneRecordContextProperties { * False to use a {@link com.apple.foundationdb.record.lucene.codec.LuceneOptimizedBlendedInfixSuggesterWithoutTermVectors} that does not store term vectors, and sort matches based on positions detection in memory. */ public static final RecordLayerPropertyKey LUCENE_AUTO_COMPLETE_WITH_TERM_VECTORS = RecordLayerPropertyKey.booleanPropertyKey("com.apple.foundationdb.record.lucene.autoComplete.withTermVectors", true); + + /** + * This controls whether Lucene indexes' directories (and their directories for auto-complete) should be merged based on probability to reduce multiple merges per transaction. + */ + public static final RecordLayerPropertyKey LUCENE_MULTIPLE_MERGE_OPTIMIZATION_ENABLED = RecordLayerPropertyKey.booleanPropertyKey("com.apple.foundationdb.record.lucene.multipleMerge.optimizationEnabled", true); } diff --git a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/codec/LuceneOptimizedBlendedInfixSuggesterWithoutTermVectors.java b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/codec/LuceneOptimizedBlendedInfixSuggesterWithoutTermVectors.java index b3ecb10ac9..987549a8dc 100644 --- a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/codec/LuceneOptimizedBlendedInfixSuggesterWithoutTermVectors.java +++ b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/codec/LuceneOptimizedBlendedInfixSuggesterWithoutTermVectors.java @@ -23,6 +23,7 @@ import com.apple.foundationdb.record.RecordCoreArgumentException; import com.apple.foundationdb.record.lucene.LuceneLoggerInfoStream; import com.apple.foundationdb.record.lucene.LuceneRecordContextProperties; +import com.apple.foundationdb.record.lucene.directory.FDBDirectoryManager; import com.apple.foundationdb.record.provider.foundationdb.IndexMaintainerState; import com.apple.foundationdb.tuple.Tuple; import org.apache.lucene.analysis.Analyzer; @@ -35,6 +36,7 @@ import org.apache.lucene.index.ConcurrentMergeScheduler; import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.MergePolicy; import org.apache.lucene.index.MergeTrigger; import org.apache.lucene.index.MultiDocValues; import org.apache.lucene.index.Term; @@ -79,6 +81,7 @@ import java.util.NavigableSet; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.ThreadLocalRandom; /** * Optimized {@link BlendedInfixSuggester} that does not rely on term vectors persisted in DB. @@ -120,18 +123,21 @@ public class LuceneOptimizedBlendedInfixSuggesterWithoutTermVectors extends Anal */ private final int minPrefixCharsCopy; + private final int mergeDirectoryCount; + private Double exponent = 2.0; @SuppressWarnings("squid:S107") LuceneOptimizedBlendedInfixSuggesterWithoutTermVectors(@Nonnull IndexMaintainerState state, @Nonnull Directory dir, @Nonnull Analyzer indexAnalyzer, @Nonnull Analyzer queryAnalyzer, int minPrefixChars, BlendedInfixSuggester.BlenderType blenderType, int numFactor, - @Nullable Double exponent, boolean highlight, @Nonnull IndexOptions indexOptions) throws IOException { + @Nullable Double exponent, boolean highlight, @Nonnull IndexOptions indexOptions, int mergeDirectoryCount) throws IOException { super(dir, indexAnalyzer, queryAnalyzer, minPrefixChars, false, true, highlight); this.state = state; this.blenderType = blenderType; this.indexOptions = indexOptions; this.numFactor = numFactor; this.minPrefixCharsCopy = minPrefixChars; + this.mergeDirectoryCount = mergeDirectoryCount; if (exponent != null) { this.exponent = exponent; } @@ -260,8 +266,31 @@ protected IndexWriterConfig getIndexWriterConfig(Analyzer indexAnalyzer, IndexWr @Override public synchronized void merge(final MergeSource mergeSource, final MergeTrigger trigger) throws IOException { - LOGGER.trace("Auto-complete index mergeSource={}", mergeSource); - super.merge(mergeSource, trigger); + if (state.context.getPropertyStorage().getPropertyValue(LuceneRecordContextProperties.LUCENE_MULTIPLE_MERGE_OPTIMIZATION_ENABLED) && trigger == MergeTrigger.FULL_FLUSH) { + if (ThreadLocalRandom.current().nextInt(mergeDirectoryCount) == 0) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(FDBDirectoryManager.getMergeLogMessage(mergeSource, trigger, state, "Auto-complete index merge based on probability")); + } + super.merge(mergeSource, trigger); + } else { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(FDBDirectoryManager.getMergeLogMessage(mergeSource, trigger, state, "Auto-complete index merge aborted based on probability")); + } + synchronized (mergeSource) { + MergePolicy.OneMerge nextMerge = mergeSource.getNextMerge(); + while (nextMerge != null) { + nextMerge.setAborted(); + mergeSource.onMergeFinished(nextMerge); + nextMerge = mergeSource.getNextMerge(); + } + } + } + } else { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(FDBDirectoryManager.getMergeLogMessage(mergeSource, trigger, state, "Auto-complete index merge")); + } + super.merge(mergeSource, trigger); + } } }); iwc.setCodec(new LuceneOptimizedCodec()); diff --git a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/codec/LuceneOptimizedWrappedBlendedInfixSuggester.java b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/codec/LuceneOptimizedWrappedBlendedInfixSuggester.java index f9b55eae56..14df9c0a66 100644 --- a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/codec/LuceneOptimizedWrappedBlendedInfixSuggester.java +++ b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/codec/LuceneOptimizedWrappedBlendedInfixSuggester.java @@ -25,11 +25,13 @@ import com.apple.foundationdb.record.lucene.LuceneIndexOptions; import com.apple.foundationdb.record.lucene.LuceneLoggerInfoStream; import com.apple.foundationdb.record.lucene.LuceneRecordContextProperties; +import com.apple.foundationdb.record.lucene.directory.FDBDirectoryManager; import com.apple.foundationdb.record.provider.foundationdb.IndexMaintainerState; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.index.ConcurrentMergeScheduler; import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.MergePolicy; import org.apache.lucene.index.MergeTrigger; import org.apache.lucene.index.TieredMergePolicy; import org.apache.lucene.search.suggest.analyzing.AnalyzingInfixSuggester; @@ -41,6 +43,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; +import java.util.concurrent.ThreadLocalRandom; /** * Optimized suggester based on {@link BlendedInfixSuggester} to override the {@link IndexWriterConfig} for index writer. @@ -53,12 +56,15 @@ public class LuceneOptimizedWrappedBlendedInfixSuggester extends BlendedInfixSug @Nonnull private final IndexMaintainerState state; + private final int mergeDirectoryCount; + @SuppressWarnings("squid:S107") private LuceneOptimizedWrappedBlendedInfixSuggester(@Nonnull IndexMaintainerState state, @Nonnull Directory dir, @Nonnull Analyzer indexAnalyzer, @Nonnull Analyzer queryAnalyzer, int minPrefixChars, BlenderType blenderType, int numFactor, - @Nullable Double exponent, boolean highlight) throws IOException { + @Nullable Double exponent, boolean highlight, int mergeDirectoryCount) throws IOException { super(dir, indexAnalyzer, queryAnalyzer, minPrefixChars, blenderType, numFactor, exponent, false, true, highlight); this.state = state; + this.mergeDirectoryCount = mergeDirectoryCount; } @Override @@ -73,8 +79,31 @@ protected IndexWriterConfig getIndexWriterConfig(Analyzer indexAnalyzer, IndexWr @Override public synchronized void merge(final MergeSource mergeSource, final MergeTrigger trigger) throws IOException { - LOGGER.trace("Auto-complete index mergeSource={}", mergeSource); - super.merge(mergeSource, trigger); + if (state.context.getPropertyStorage().getPropertyValue(LuceneRecordContextProperties.LUCENE_MULTIPLE_MERGE_OPTIMIZATION_ENABLED) && trigger == MergeTrigger.FULL_FLUSH) { + if (ThreadLocalRandom.current().nextInt(mergeDirectoryCount) == 0) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(FDBDirectoryManager.getMergeLogMessage(mergeSource, trigger, state, "Auto-complete index merge based on probability")); + } + super.merge(mergeSource, trigger); + } else { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(FDBDirectoryManager.getMergeLogMessage(mergeSource, trigger, state, "Auto-complete index merge aborted based on probability")); + } + synchronized (mergeSource) { + MergePolicy.OneMerge nextMerge = mergeSource.getNextMerge(); + while (nextMerge != null) { + nextMerge.setAborted(); + mergeSource.onMergeFinished(nextMerge); + nextMerge = mergeSource.getNextMerge(); + } + } + } + } else { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(FDBDirectoryManager.getMergeLogMessage(mergeSource, trigger, state, "Auto-complete index merge")); + } + super.merge(mergeSource, trigger); + } } }); iwc.setCodec(new LuceneOptimizedCodec()); @@ -85,7 +114,7 @@ public synchronized void merge(final MergeSource mergeSource, final MergeTrigger @Nonnull public static AnalyzingInfixSuggester getSuggester(@Nonnull IndexMaintainerState state, @Nonnull Directory dir, @Nonnull Analyzer indexAnalyzer, @Nonnull Analyzer queryAnalyzer, - boolean highlight, @Nonnull IndexOptions indexOptions) { + boolean highlight, @Nonnull IndexOptions indexOptions, int mergeDirectoryCount) { final String autoCompleteBlenderType = state.index.getOption(LuceneIndexOptions.AUTO_COMPLETE_BLENDER_TYPE); final String autoCompleteBlenderNumFactor = state.index.getOption(LuceneIndexOptions.AUTO_COMPLETE_BLENDER_NUM_FACTOR); final String autoCompleteMinPrefixSize = state.index.getOption(LuceneIndexOptions.AUTO_COMPLETE_MIN_PREFIX_SIZE); @@ -99,9 +128,9 @@ public static AnalyzingInfixSuggester getSuggester(@Nonnull IndexMaintainerState try { return useTermVectors - ? new LuceneOptimizedWrappedBlendedInfixSuggester(state, dir, indexAnalyzer, queryAnalyzer, minPrefixChars, blenderType, numFactor, exponent, highlight) + ? new LuceneOptimizedWrappedBlendedInfixSuggester(state, dir, indexAnalyzer, queryAnalyzer, minPrefixChars, blenderType, numFactor, exponent, highlight, mergeDirectoryCount) : new LuceneOptimizedBlendedInfixSuggesterWithoutTermVectors(state, dir, indexAnalyzer, queryAnalyzer, minPrefixChars, blenderType, - numFactor, exponent, highlight, indexOptions); + numFactor, exponent, highlight, indexOptions, mergeDirectoryCount); } catch (IllegalArgumentException iae) { throw new RecordCoreArgumentException("Invalid parameter for auto complete suggester", iae) .addLogInfo(LogMessageKeys.INDEX_NAME, state.index.getName()); diff --git a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/directory/FDBDirectoryManager.java b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/directory/FDBDirectoryManager.java index 23224ef230..a05cebc31e 100644 --- a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/directory/FDBDirectoryManager.java +++ b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/directory/FDBDirectoryManager.java @@ -23,7 +23,12 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.async.AsyncUtil; import com.apple.foundationdb.record.RecordCoreStorageException; +import com.apple.foundationdb.record.logging.KeyValueLogMessage; +import com.apple.foundationdb.record.logging.LogMessageKeys; import com.apple.foundationdb.record.lucene.LuceneAnalyzerWrapper; +import com.apple.foundationdb.record.lucene.LuceneIndexOptions; +import com.apple.foundationdb.record.lucene.LuceneIndexTypes; +import com.apple.foundationdb.record.lucene.LuceneLogMessageKeys; import com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext; import com.apple.foundationdb.record.provider.foundationdb.IndexMaintainerState; import com.apple.foundationdb.subspace.Subspace; @@ -33,6 +38,8 @@ import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.MergeScheduler; +import org.apache.lucene.index.MergeTrigger; import org.apache.lucene.search.suggest.analyzing.AnalyzingInfixSuggester; import javax.annotation.Nonnull; @@ -41,6 +48,7 @@ import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; /** * A transaction-scoped manager of {@link FDBDirectory} objects. For a single transaction, all {@link FDBDirectory} @@ -58,10 +66,12 @@ public class FDBDirectoryManager implements AutoCloseable { private final IndexMaintainerState state; @Nonnull private final Map createdDirectories; + private final int mergeDirectoryCount; private FDBDirectoryManager(@Nonnull IndexMaintainerState state) { this.state = state; this.createdDirectories = new ConcurrentHashMap<>(); + this.mergeDirectoryCount = getMergeDirectoryCount(state); } @Override @@ -96,7 +106,7 @@ private FDBDirectoryWrapper getDirectoryWrapper(@Nullable Tuple groupingKey) { final Tuple mapKey = groupingKey == null ? TupleHelpers.EMPTY : groupingKey; return createdDirectories.computeIfAbsent(mapKey, key -> { final Subspace directorySubspace = state.indexSubspace.subspace(key); - return new FDBDirectoryWrapper(state, new FDBDirectory(directorySubspace, state.context)); + return new FDBDirectoryWrapper(state, new FDBDirectory(directorySubspace, state.context), mergeDirectoryCount); }); } @@ -149,4 +159,26 @@ public static FDBDirectoryManager getManager(@Nonnull IndexMaintainerState state return newManager; } } + + private int getMergeDirectoryCount(@Nonnull IndexMaintainerState state) { + final AtomicInteger luceneMergeCount = new AtomicInteger(); + state.store.getRecordMetaData().getAllIndexes().stream().filter(i -> i.getType().equals(LuceneIndexTypes.LUCENE)).forEach(i -> { + if (i.getBooleanOption(LuceneIndexOptions.AUTO_COMPLETE_ENABLED, false)) { + // Auto-complete has its separate directory to merge + luceneMergeCount.getAndAdd(2); + } else { + luceneMergeCount.incrementAndGet(); + } + }); + return luceneMergeCount.get(); + } + + public static String getMergeLogMessage(@Nonnull MergeScheduler.MergeSource mergeSource, @Nonnull MergeTrigger trigger, + @Nonnull IndexMaintainerState state, @Nonnull String logMessage) { + return KeyValueLogMessage.of(logMessage, + LuceneLogMessageKeys.MERGE_SOURCE, mergeSource, + LuceneLogMessageKeys.MERGE_TRIGGER, trigger, + LogMessageKeys.INDEX_NAME, state.index.getName(), + LogMessageKeys.INDEX_SUBSPACE, state.indexSubspace); + } } diff --git a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/directory/FDBDirectoryWrapper.java b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/directory/FDBDirectoryWrapper.java index c53fe62ec9..cd5c29c5a2 100644 --- a/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/directory/FDBDirectoryWrapper.java +++ b/fdb-record-layer-lucene/src/main/java/com/apple/foundationdb/record/lucene/directory/FDBDirectoryWrapper.java @@ -32,6 +32,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.MergePolicy; import org.apache.lucene.index.MergeTrigger; import org.apache.lucene.index.TieredMergePolicy; import org.apache.lucene.search.suggest.analyzing.AnalyzingInfixSuggester; @@ -41,6 +42,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; +import java.util.concurrent.ThreadLocalRandom; /** * Wrapper containing an {@link FDBDirectory} and cached accessor objects (like {@link IndexWriter}s). This object @@ -53,6 +55,7 @@ class FDBDirectoryWrapper implements AutoCloseable { private final IndexMaintainerState state; private final FDBDirectory directory; + private final int mergeDirectoryCount; @SuppressWarnings({"squid:S3077"}) // object is thread safe, so use of volatile to control instance creation is correct private volatile IndexWriter writer; @SuppressWarnings({"squid:S3077"}) // object is thread safe, so use of volatile to control instance creation is correct @@ -66,9 +69,10 @@ class FDBDirectoryWrapper implements AutoCloseable { @SuppressWarnings({"squid:S3077"}) // object is thread safe, so use of volatile to control instance creation is correct private volatile IndexOptions suggesterFieldIndexOptions; - FDBDirectoryWrapper(IndexMaintainerState state, FDBDirectory directory) { + FDBDirectoryWrapper(IndexMaintainerState state, FDBDirectory directory, int mergeDirectoryCount) { this.state = state; this.directory = directory; + this.mergeDirectoryCount = mergeDirectoryCount; } public FDBDirectory getDirectory() { @@ -98,8 +102,31 @@ public IndexWriter getWriter(LuceneAnalyzerWrapper analyzerWrapper) throws IOExc .setMergeScheduler(new ConcurrentMergeScheduler() { @Override public synchronized void merge(final MergeSource mergeSource, final MergeTrigger trigger) throws IOException { - LOGGER.trace("mergeSource={}", mergeSource); - super.merge(mergeSource, trigger); + if (state.context.getPropertyStorage().getPropertyValue(LuceneRecordContextProperties.LUCENE_MULTIPLE_MERGE_OPTIMIZATION_ENABLED) && trigger == MergeTrigger.FULL_FLUSH) { + if (ThreadLocalRandom.current().nextInt(mergeDirectoryCount) == 0) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(FDBDirectoryManager.getMergeLogMessage(mergeSource, trigger, state, "Basic Lucene index merge based on probability")); + } + super.merge(mergeSource, trigger); + } else { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(FDBDirectoryManager.getMergeLogMessage(mergeSource, trigger, state, "Basic Lucene index merge aborted based on probability")); + } + synchronized (mergeSource) { + MergePolicy.OneMerge nextMerge = mergeSource.getNextMerge(); + while (nextMerge != null) { + nextMerge.setAborted(); + mergeSource.onMergeFinished(nextMerge); + nextMerge = mergeSource.getNextMerge(); + } + } + } + } else { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(FDBDirectoryManager.getMergeLogMessage(mergeSource, trigger, state, "Basic Lucene index merge")); + } + super.merge(mergeSource, trigger); + } } }) .setCodec(new LuceneOptimizedCodec()) @@ -131,7 +158,8 @@ public AnalyzingInfixSuggester getAutocompleteSuggester(@Nonnull LuceneAnalyzerW suggester = LuceneOptimizedWrappedBlendedInfixSuggester.getSuggester(state, directory, indexAnalyzerWrapper.getAnalyzer(), queryAnalyzerWrapper.getAnalyzer(), - highlight, indexOptions == null ? suggesterFieldIndexOptions : indexOptions); + highlight, indexOptions == null ? suggesterFieldIndexOptions : indexOptions, + mergeDirectoryCount); suggesterIndexAnalyzerId = indexAnalyzerWrapper.getUniqueIdentifier(); suggesterQueryAnalyzerId = queryAnalyzerWrapper.getUniqueIdentifier(); if (indexOptions != null) {