Skip to content

Commit 8bb6c00

Browse files
committed
Also make use of the thread local memory reuse for a document being percolated with nested objects.
The memory index will only be reused for the root doc, since most of the times that will be the biggest document.
1 parent 9f8f13d commit 8bb6c00

File tree

4 files changed

+57
-42
lines changed

4 files changed

+57
-42
lines changed

src/main/java/org/elasticsearch/percolator/MultiDocumentPercolatorIndex.java

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,41 +25,59 @@
2525
import org.apache.lucene.index.*;
2626
import org.apache.lucene.index.memory.MemoryIndex;
2727
import org.apache.lucene.search.IndexSearcher;
28+
import org.apache.lucene.util.CloseableThreadLocal;
2829
import org.elasticsearch.ElasticsearchException;
2930
import org.elasticsearch.index.engine.Engine;
3031
import org.elasticsearch.index.mapper.ParseContext;
3132
import org.elasticsearch.index.mapper.ParsedDocument;
3233
import org.elasticsearch.index.mapper.internal.UidFieldMapper;
3334

3435
import java.io.IOException;
36+
import java.util.List;
3537

3638

37-
39+
/**
40+
* Implementation of {@link PercolatorIndex} that can hold multiple Lucene documents by
41+
* opening multiple {@link MemoryIndex} based IndexReaders and wrapping them via a single top level reader.
42+
*/
3843
class MultiDocumentPercolatorIndex implements PercolatorIndex {
3944

40-
public MultiDocumentPercolatorIndex() {
45+
private final CloseableThreadLocal<MemoryIndex> cache;
46+
47+
MultiDocumentPercolatorIndex(CloseableThreadLocal<MemoryIndex> cache) {
48+
this.cache = cache;
4149
}
4250

4351
@Override
4452
public void prepare(PercolateContext context, ParsedDocument parsedDocument) {
45-
int docCounter = 0;
4653
IndexReader[] memoryIndices = new IndexReader[parsedDocument.docs().size()];
47-
for (ParseContext.Document d : parsedDocument.docs()) {
48-
memoryIndices[docCounter] = indexDoc(d, parsedDocument.analyzer()).createSearcher().getIndexReader();
49-
docCounter++;
54+
List<ParseContext.Document> docs = parsedDocument.docs();
55+
int rootDocIndex = docs.size() - 1;
56+
assert rootDocIndex > 0;
57+
MemoryIndex rootDocMemoryIndex = null;
58+
for (int i = 0; i < docs.size(); i++) {
59+
ParseContext.Document d = docs.get(i);
60+
MemoryIndex memoryIndex;
61+
if (rootDocIndex == i) {
62+
// the last doc is always the rootDoc, since that is usually the biggest document it make sense
63+
// to reuse the MemoryIndex it uses
64+
memoryIndex = rootDocMemoryIndex = cache.get();
65+
} else {
66+
memoryIndex = new MemoryIndex(true);
67+
}
68+
memoryIndices[i] = indexDoc(d, parsedDocument.analyzer(), memoryIndex).createSearcher().getIndexReader();
5069
}
5170
MultiReader mReader = new MultiReader(memoryIndices, true);
5271
try {
5372
AtomicReader slowReader = SlowCompositeReaderWrapper.wrap(mReader);
54-
DocSearcher docSearcher = new DocSearcher(new IndexSearcher(slowReader));
73+
DocSearcher docSearcher = new DocSearcher(new IndexSearcher(slowReader), rootDocMemoryIndex);
5574
context.initialize(docSearcher, parsedDocument);
5675
} catch (IOException e) {
5776
throw new ElasticsearchException("Failed to create index for percolator with nested document ", e);
5877
}
5978
}
6079

61-
MemoryIndex indexDoc(ParseContext.Document d, Analyzer analyzer) {
62-
MemoryIndex memoryIndex = new MemoryIndex(true);
80+
MemoryIndex indexDoc(ParseContext.Document d, Analyzer analyzer, MemoryIndex memoryIndex) {
6381
for (IndexableField field : d.getFields()) {
6482
if (!field.fieldType().indexed() && field.name().equals(UidFieldMapper.NAME)) {
6583
continue;
@@ -76,17 +94,14 @@ MemoryIndex indexDoc(ParseContext.Document d, Analyzer analyzer) {
7694
return memoryIndex;
7795
}
7896

79-
@Override
80-
public void clean() {
81-
// noop
82-
}
83-
8497
private class DocSearcher implements Engine.Searcher {
8598

8699
private final IndexSearcher searcher;
100+
private final MemoryIndex rootDocMemoryIndex;
87101

88-
private DocSearcher(IndexSearcher searcher) {
102+
private DocSearcher(IndexSearcher searcher, MemoryIndex rootDocMemoryIndex) {
89103
this.searcher = searcher;
104+
this.rootDocMemoryIndex = rootDocMemoryIndex;
90105
}
91106

92107
@Override
@@ -108,6 +123,7 @@ public IndexSearcher searcher() {
108123
public boolean release() throws ElasticsearchException {
109124
try {
110125
searcher.getIndexReader().close();
126+
rootDocMemoryIndex.reset();
111127
} catch (IOException e) {
112128
throw new ElasticsearchException("failed to close IndexReader in percolator with nested doc", e);
113129
}

src/main/java/org/elasticsearch/percolator/PercolatorIndex.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121

2222
import org.elasticsearch.index.mapper.ParsedDocument;
2323

24-
24+
/**
25+
* Abstraction on how to index the percolator document.
26+
*/
2527
interface PercolatorIndex {
2628

2729
/**
@@ -32,9 +34,4 @@ interface PercolatorIndex {
3234
* */
3335
void prepare(PercolateContext context, ParsedDocument document);
3436

35-
/**
36-
* Release resources
37-
* */
38-
void clean();
39-
4037
}

src/main/java/org/elasticsearch/percolator/PercolatorService.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@
2323
import com.google.common.collect.Lists;
2424
import org.apache.lucene.index.AtomicReaderContext;
2525
import org.apache.lucene.index.ReaderUtil;
26+
import org.apache.lucene.index.memory.ExtendedMemoryIndex;
27+
import org.apache.lucene.index.memory.MemoryIndex;
2628
import org.apache.lucene.search.*;
2729
import org.apache.lucene.util.BytesRef;
30+
import org.apache.lucene.util.CloseableThreadLocal;
2831
import org.elasticsearch.ElasticsearchException;
2932
import org.elasticsearch.ElasticsearchIllegalArgumentException;
3033
import org.elasticsearch.ElasticsearchParseException;
@@ -47,6 +50,8 @@
4750
import org.elasticsearch.common.text.BytesText;
4851
import org.elasticsearch.common.text.StringText;
4952
import org.elasticsearch.common.text.Text;
53+
import org.elasticsearch.common.unit.ByteSizeUnit;
54+
import org.elasticsearch.common.unit.ByteSizeValue;
5055
import org.elasticsearch.common.util.BigArrays;
5156
import org.elasticsearch.common.xcontent.XContentBuilder;
5257
import org.elasticsearch.common.xcontent.XContentFactory;
@@ -114,6 +119,8 @@ public class PercolatorService extends AbstractComponent {
114119
private final SortParseElement sortParseElement;
115120
private final ScriptService scriptService;
116121

122+
private final CloseableThreadLocal<MemoryIndex> cache;
123+
117124
@Inject
118125
public PercolatorService(Settings settings, IndicesService indicesService, CacheRecycler cacheRecycler,
119126
PageCacheRecycler pageCacheRecycler, BigArrays bigArrays,
@@ -131,8 +138,15 @@ public PercolatorService(Settings settings, IndicesService indicesService, Cache
131138
this.scriptService = scriptService;
132139
this.sortParseElement = new SortParseElement();
133140

134-
single = new SingleDocumentPercolatorIndex(settings);
135-
multi = new MultiDocumentPercolatorIndex();
141+
final long maxReuseBytes = settings.getAsBytesSize("indices.memory.memory_index.size_per_thread", new ByteSizeValue(1, ByteSizeUnit.MB)).bytes();
142+
cache = new CloseableThreadLocal<MemoryIndex>() {
143+
@Override
144+
protected MemoryIndex initialValue() {
145+
return new ExtendedMemoryIndex(true, maxReuseBytes);
146+
}
147+
};
148+
single = new SingleDocumentPercolatorIndex(cache);
149+
multi = new MultiDocumentPercolatorIndex(cache);
136150

137151
percolatorTypes = new ByteObjectOpenHashMap<PercolatorType>(6);
138152
percolatorTypes.put(countPercolator.id(), countPercolator);
@@ -385,8 +399,7 @@ private ParsedDocument parseFetchedDoc(PercolateContext context, BytesReference
385399
}
386400

387401
public void close() {
388-
single.clean();
389-
multi.clean();
402+
cache.close();;
390403
}
391404

392405
interface PercolatorType {

src/main/java/org/elasticsearch/percolator/SingleDocumentPercolatorIndex.java

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,26 @@
2323
import org.apache.lucene.analysis.TokenStream;
2424
import org.apache.lucene.index.IndexReader;
2525
import org.apache.lucene.index.IndexableField;
26-
import org.apache.lucene.index.memory.ExtendedMemoryIndex;
2726
import org.apache.lucene.index.memory.MemoryIndex;
2827
import org.apache.lucene.search.IndexSearcher;
2928
import org.apache.lucene.util.CloseableThreadLocal;
3029
import org.elasticsearch.ElasticsearchException;
31-
import org.elasticsearch.common.settings.Settings;
32-
import org.elasticsearch.common.unit.ByteSizeUnit;
33-
import org.elasticsearch.common.unit.ByteSizeValue;
3430
import org.elasticsearch.index.engine.Engine;
3531
import org.elasticsearch.index.mapper.ParsedDocument;
3632
import org.elasticsearch.index.mapper.internal.UidFieldMapper;
3733

3834
import java.io.IOException;
3935

36+
/**
37+
* Implementation of {@link PercolatorIndex} that can only hold a single Lucene document
38+
* and is optimized for that
39+
*/
4040
class SingleDocumentPercolatorIndex implements PercolatorIndex {
4141

4242
private final CloseableThreadLocal<MemoryIndex> cache;
4343

44-
public SingleDocumentPercolatorIndex(Settings settings) {
45-
final long maxReuseBytes = settings.getAsBytesSize("indices.memory.memory_index.size_per_thread", new ByteSizeValue(1, ByteSizeUnit.MB)).bytes();
46-
cache = new CloseableThreadLocal<MemoryIndex>() {
47-
@Override
48-
protected MemoryIndex initialValue() {
49-
return new ExtendedMemoryIndex(true, maxReuseBytes);
50-
}
51-
};
44+
SingleDocumentPercolatorIndex(CloseableThreadLocal<MemoryIndex> cache) {
45+
this.cache = cache;
5246
}
5347

5448
@Override
@@ -70,11 +64,6 @@ public void prepare(PercolateContext context, ParsedDocument parsedDocument) {
7064
context.initialize(new DocEngineSearcher(memoryIndex), parsedDocument);
7165
}
7266

73-
@Override
74-
public void clean() {
75-
cache.close();
76-
}
77-
7867
private class DocEngineSearcher implements Engine.Searcher {
7968

8069
private final IndexSearcher searcher;

0 commit comments

Comments
 (0)