25
25
import org .apache .lucene .index .*;
26
26
import org .apache .lucene .index .memory .MemoryIndex ;
27
27
import org .apache .lucene .search .IndexSearcher ;
28
+ import org .apache .lucene .util .CloseableThreadLocal ;
28
29
import org .elasticsearch .ElasticsearchException ;
29
30
import org .elasticsearch .index .engine .Engine ;
30
31
import org .elasticsearch .index .mapper .ParseContext ;
31
32
import org .elasticsearch .index .mapper .ParsedDocument ;
32
33
import org .elasticsearch .index .mapper .internal .UidFieldMapper ;
33
34
34
35
import java .io .IOException ;
36
+ import java .util .List ;
35
37
36
38
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
+ */
38
43
class MultiDocumentPercolatorIndex implements PercolatorIndex {
39
44
40
- public MultiDocumentPercolatorIndex () {
45
+ private final CloseableThreadLocal <MemoryIndex > cache ;
46
+
47
+ MultiDocumentPercolatorIndex (CloseableThreadLocal <MemoryIndex > cache ) {
48
+ this .cache = cache ;
41
49
}
42
50
43
51
@ Override
44
52
public void prepare (PercolateContext context , ParsedDocument parsedDocument ) {
45
- int docCounter = 0 ;
46
53
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 ();
50
69
}
51
70
MultiReader mReader = new MultiReader (memoryIndices , true );
52
71
try {
53
72
AtomicReader slowReader = SlowCompositeReaderWrapper .wrap (mReader );
54
- DocSearcher docSearcher = new DocSearcher (new IndexSearcher (slowReader ));
73
+ DocSearcher docSearcher = new DocSearcher (new IndexSearcher (slowReader ), rootDocMemoryIndex );
55
74
context .initialize (docSearcher , parsedDocument );
56
75
} catch (IOException e ) {
57
76
throw new ElasticsearchException ("Failed to create index for percolator with nested document " , e );
58
77
}
59
78
}
60
79
61
- MemoryIndex indexDoc (ParseContext .Document d , Analyzer analyzer ) {
62
- MemoryIndex memoryIndex = new MemoryIndex (true );
80
+ MemoryIndex indexDoc (ParseContext .Document d , Analyzer analyzer , MemoryIndex memoryIndex ) {
63
81
for (IndexableField field : d .getFields ()) {
64
82
if (!field .fieldType ().indexed () && field .name ().equals (UidFieldMapper .NAME )) {
65
83
continue ;
@@ -76,17 +94,14 @@ MemoryIndex indexDoc(ParseContext.Document d, Analyzer analyzer) {
76
94
return memoryIndex ;
77
95
}
78
96
79
- @ Override
80
- public void clean () {
81
- // noop
82
- }
83
-
84
97
private class DocSearcher implements Engine .Searcher {
85
98
86
99
private final IndexSearcher searcher ;
100
+ private final MemoryIndex rootDocMemoryIndex ;
87
101
88
- private DocSearcher (IndexSearcher searcher ) {
102
+ private DocSearcher (IndexSearcher searcher , MemoryIndex rootDocMemoryIndex ) {
89
103
this .searcher = searcher ;
104
+ this .rootDocMemoryIndex = rootDocMemoryIndex ;
90
105
}
91
106
92
107
@ Override
@@ -108,6 +123,7 @@ public IndexSearcher searcher() {
108
123
public boolean release () throws ElasticsearchException {
109
124
try {
110
125
searcher .getIndexReader ().close ();
126
+ rootDocMemoryIndex .reset ();
111
127
} catch (IOException e ) {
112
128
throw new ElasticsearchException ("failed to close IndexReader in percolator with nested doc" , e );
113
129
}
0 commit comments