Skip to content

Commit a92dda2

Browse files
authored
Move CompletionStats into the Engine (#33847)
By moving CompletionStats into the engine we can easily cache the stats for read-only engines if necessary. It also moves the responsibiltiy out of IndexShard which has quiet some complexity already. Relates to #33835
1 parent 0fa5758 commit a92dda2

File tree

4 files changed

+59
-75
lines changed

4 files changed

+59
-75
lines changed

server/src/main/java/org/elasticsearch/index/engine/Engine.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919

2020
package org.elasticsearch.index.engine;
2121

22+
import com.carrotsearch.hppc.ObjectLongHashMap;
2223
import org.apache.logging.log4j.Logger;
2324
import org.apache.logging.log4j.message.ParameterizedMessage;
2425
import org.apache.lucene.index.DirectoryReader;
26+
import org.apache.lucene.index.FieldInfo;
2527
import org.apache.lucene.index.IndexCommit;
2628
import org.apache.lucene.index.IndexFileNames;
2729
import org.apache.lucene.index.IndexReader;
@@ -32,8 +34,10 @@
3234
import org.apache.lucene.index.SegmentInfos;
3335
import org.apache.lucene.index.SegmentReader;
3436
import org.apache.lucene.index.Term;
37+
import org.apache.lucene.index.Terms;
3538
import org.apache.lucene.search.IndexSearcher;
3639
import org.apache.lucene.search.ReferenceManager;
40+
import org.apache.lucene.search.suggest.document.CompletionTerms;
3741
import org.apache.lucene.store.AlreadyClosedException;
3842
import org.apache.lucene.store.Directory;
3943
import org.apache.lucene.store.IOContext;
@@ -42,6 +46,7 @@
4246
import org.apache.lucene.util.SetOnce;
4347
import org.elasticsearch.ExceptionsHelper;
4448
import org.elasticsearch.common.CheckedRunnable;
49+
import org.elasticsearch.common.FieldMemoryStats;
4550
import org.elasticsearch.common.Nullable;
4651
import org.elasticsearch.common.bytes.BytesReference;
4752
import org.elasticsearch.common.collect.ImmutableOpenMap;
@@ -56,6 +61,7 @@
5661
import org.elasticsearch.common.lucene.uid.VersionsAndSeqNoResolver;
5762
import org.elasticsearch.common.lucene.uid.VersionsAndSeqNoResolver.DocIdAndVersion;
5863
import org.elasticsearch.common.metrics.CounterMetric;
64+
import org.elasticsearch.common.regex.Regex;
5965
import org.elasticsearch.common.unit.TimeValue;
6066
import org.elasticsearch.common.util.concurrent.ReleasableLock;
6167
import org.elasticsearch.index.VersionType;
@@ -71,6 +77,7 @@
7177
import org.elasticsearch.index.store.Store;
7278
import org.elasticsearch.index.translog.Translog;
7379
import org.elasticsearch.index.translog.TranslogStats;
80+
import org.elasticsearch.search.suggest.completion.CompletionStats;
7481

7582
import java.io.Closeable;
7683
import java.io.FileNotFoundException;
@@ -176,6 +183,34 @@ public MergeStats getMergeStats() {
176183
/** Returns how many bytes we are currently moving from heap to disk */
177184
public abstract long getWritingBytes();
178185

186+
/**
187+
* Returns the {@link CompletionStats} for this engine
188+
*/
189+
public CompletionStats completionStats(String... fieldNamePatterns) throws IOException {
190+
try (Engine.Searcher currentSearcher = acquireSearcher("completion_stats", SearcherScope.INTERNAL)) {
191+
long sizeInBytes = 0;
192+
ObjectLongHashMap<String> completionFields = null;
193+
if (fieldNamePatterns != null && fieldNamePatterns.length > 0) {
194+
completionFields = new ObjectLongHashMap<>(fieldNamePatterns.length);
195+
}
196+
for (LeafReaderContext atomicReaderContext : currentSearcher.reader().leaves()) {
197+
LeafReader atomicReader = atomicReaderContext.reader();
198+
for (FieldInfo info : atomicReader.getFieldInfos()) {
199+
Terms terms = atomicReader.terms(info.name);
200+
if (terms instanceof CompletionTerms) {
201+
// TODO: currently we load up the suggester for reporting its size
202+
long fstSize = ((CompletionTerms) terms).suggester().ramBytesUsed();
203+
if (Regex.simpleMatch(fieldNamePatterns, info.name)) {
204+
completionFields.addTo(info.name, fstSize);
205+
}
206+
sizeInBytes += fstSize;
207+
}
208+
}
209+
}
210+
return new CompletionStats(sizeInBytes, completionFields == null ? null : new FieldMemoryStats(completionFields));
211+
}
212+
}
213+
179214
/**
180215
* Returns the {@link DocsStats} for this engine
181216
*/

server/src/main/java/org/elasticsearch/index/shard/IndexShard.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,13 @@
128128
import org.elasticsearch.repositories.RepositoriesService;
129129
import org.elasticsearch.repositories.Repository;
130130
import org.elasticsearch.rest.RestStatus;
131-
import org.elasticsearch.search.suggest.completion.CompletionFieldStats;
132131
import org.elasticsearch.search.suggest.completion.CompletionStats;
133132
import org.elasticsearch.threadpool.ThreadPool;
134133

135134
import java.io.Closeable;
136135
import java.io.IOException;
137136
import java.io.PrintStream;
137+
import java.io.UncheckedIOException;
138138
import java.nio.channels.ClosedByInterruptException;
139139
import java.nio.charset.StandardCharsets;
140140
import java.util.ArrayList;
@@ -955,14 +955,16 @@ public TranslogStats translogStats() {
955955
}
956956

957957
public CompletionStats completionStats(String... fields) {
958-
CompletionStats completionStats = new CompletionStats();
959-
try (Engine.Searcher currentSearcher = acquireSearcher("completion_stats")) {
958+
readAllowed();
959+
try {
960+
CompletionStats stats = getEngine().completionStats(fields);
960961
// we don't wait for a pending refreshes here since it's a stats call instead we mark it as accessed only which will cause
961962
// the next scheduled refresh to go through and refresh the stats as well
962963
markSearcherAccessed();
963-
completionStats.add(CompletionFieldStats.completionStats(currentSearcher.reader(), fields));
964+
return stats;
965+
} catch (IOException e) {
966+
throw new UncheckedIOException(e);
964967
}
965-
return completionStats;
966968
}
967969

968970
public Engine.SyncedFlushResult syncFlush(String syncId, Engine.CommitId expectedCommitId) {

server/src/main/java/org/elasticsearch/search/suggest/completion/CompletionFieldStats.java

Lines changed: 0 additions & 70 deletions
This file was deleted.

server/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,6 +2438,23 @@ public void testRecoverFromLocalShard() throws IOException {
24382438
closeShards(sourceShard, targetShard);
24392439
}
24402440

2441+
public void testCompletionStatsMarksSearcherAccessed() throws Exception {
2442+
IndexShard indexShard = null;
2443+
try {
2444+
indexShard = newStartedShard();
2445+
IndexShard shard = indexShard;
2446+
assertBusy(() -> {
2447+
ThreadPool threadPool = shard.getThreadPool();
2448+
assertThat(threadPool.relativeTimeInMillis(), greaterThan(shard.getLastSearcherAccess()));
2449+
});
2450+
long prevAccessTime = shard.getLastSearcherAccess();
2451+
indexShard.completionStats();
2452+
assertThat("searcher was not marked as accessed", shard.getLastSearcherAccess(), greaterThan(prevAccessTime));
2453+
} finally {
2454+
closeShards(indexShard);
2455+
}
2456+
}
2457+
24412458
public void testDocStats() throws Exception {
24422459
IndexShard indexShard = null;
24432460
try {

0 commit comments

Comments
 (0)