28
28
import org .apache .lucene .search .Scorer ;
29
29
import org .apache .lucene .search .Weight ;
30
30
import org .apache .lucene .util .Bits ;
31
+ import org .elasticsearch .common .lease .Releasable ;
31
32
import org .elasticsearch .common .lease .Releasables ;
32
33
import org .elasticsearch .common .lucene .Lucene ;
34
+ import org .elasticsearch .common .util .BigArrays ;
33
35
import org .elasticsearch .common .util .BitArray ;
34
36
import org .elasticsearch .common .util .LongHash ;
35
37
import org .elasticsearch .search .aggregations .Aggregator ;
@@ -52,16 +54,11 @@ public abstract class ParentJoinAggregator extends BucketsAggregator implements
52
54
private final Weight inFilter ;
53
55
private final Weight outFilter ;
54
56
private final ValuesSource .Bytes .WithOrdinals valuesSource ;
55
- private final boolean singleAggregator ;
56
57
57
58
/**
58
- * If this aggregator is nested under another aggregator we allocate a long hash per bucket .
59
+ * Strategy for collecting results .
59
60
*/
60
- private final LongHash ordsHash ;
61
- /**
62
- * Otherwise we use a dense bit array to record the global ordinals.
63
- */
64
- private final BitArray ordsBit ;
61
+ private final CollectionStrategy collectionStrategy ;
65
62
66
63
public ParentJoinAggregator (String name ,
67
64
AggregatorFactories factories ,
@@ -83,21 +80,9 @@ public ParentJoinAggregator(String name,
83
80
this .inFilter = context .searcher ().createWeight (context .searcher ().rewrite (inFilter ), ScoreMode .COMPLETE_NO_SCORES , 1f );
84
81
this .outFilter = context .searcher ().createWeight (context .searcher ().rewrite (outFilter ), ScoreMode .COMPLETE_NO_SCORES , 1f );
85
82
this .valuesSource = valuesSource ;
86
- this .singleAggregator = parent == null ;
87
- this .ordsBit = singleAggregator ? new BitArray ((int ) maxOrd , context .bigArrays ()) : null ;
88
- this .ordsHash = singleAggregator ? null : new LongHash (1 , context .bigArrays ());
89
- }
90
-
91
- private void addGlobalOrdinal (int globalOrdinal ) {
92
- if (singleAggregator ) {
93
- ordsBit .set (globalOrdinal );
94
- } else {
95
- ordsHash .add (globalOrdinal );
96
- }
97
- }
98
-
99
- private boolean existsGlobalOrdinal (int globalOrdinal ) {
100
- return singleAggregator ? ordsBit .get (globalOrdinal ): ordsHash .find (globalOrdinal ) >= 0 ;
83
+ boolean singleAggregator = parent == null ;
84
+ collectionStrategy = singleAggregator ?
85
+ new DenseCollectionStrategy (maxOrd , context .bigArrays ()) : new SparseCollectionStrategy (context .bigArrays ());
101
86
}
102
87
103
88
@ Override
@@ -115,7 +100,7 @@ public void collect(int docId, long bucket) throws IOException {
115
100
if (parentDocs .get (docId ) && globalOrdinals .advanceExact (docId )) {
116
101
int globalOrdinal = (int ) globalOrdinals .nextOrd ();
117
102
assert globalOrdinal != -1 && globalOrdinals .nextOrd () == SortedSetDocValues .NO_MORE_ORDS ;
118
- addGlobalOrdinal (globalOrdinal );
103
+ collectionStrategy . addGlobalOrdinal (globalOrdinal );
119
104
}
120
105
}
121
106
};
@@ -155,7 +140,7 @@ public int docID() {
155
140
if (globalOrdinals .advanceExact (docId )) {
156
141
int globalOrdinal = (int ) globalOrdinals .nextOrd ();
157
142
assert globalOrdinal != -1 && globalOrdinals .nextOrd () == SortedSetDocValues .NO_MORE_ORDS ;
158
- if (existsGlobalOrdinal (globalOrdinal )) {
143
+ if (collectionStrategy . existsGlobalOrdinal (globalOrdinal )) {
159
144
collectBucket (sub , docId , 0 );
160
145
}
161
146
}
@@ -165,6 +150,75 @@ public int docID() {
165
150
166
151
@ Override
167
152
protected void doClose () {
168
- Releasables .close (ordsBit , ordsHash );
153
+ Releasables .close (collectionStrategy );
154
+ }
155
+
156
+ /**
157
+ * Strategy for collecting the global ordinals of the join field in for all
158
+ * docs that match the {@code ParentJoinAggregator#inFilter} and then
159
+ * checking if which of the docs in the
160
+ * {@code ParentJoinAggregator#outFilter} also have the ordinal.
161
+ */
162
+ protected interface CollectionStrategy extends Releasable {
163
+ void addGlobalOrdinal (int globalOrdinal );
164
+ boolean existsGlobalOrdinal (int globalOrdinal );
165
+ }
166
+
167
+ /**
168
+ * Uses a dense, bit per ordinal representation of the join field in the
169
+ * docs that match {@code ParentJoinAggregator#inFilter}. Its memory usage
170
+ * is proportional to the maximum ordinal so it is only a good choice if
171
+ * most docs match.
172
+ */
173
+ protected class DenseCollectionStrategy implements CollectionStrategy {
174
+ private final BitArray ordsBits ;
175
+
176
+ public DenseCollectionStrategy (long maxOrd , BigArrays bigArrays ) {
177
+ ordsBits = new BitArray ((int ) maxOrd , context .bigArrays ());
178
+ }
179
+
180
+ @ Override
181
+ public void addGlobalOrdinal (int globalOrdinal ) {
182
+ ordsBits .set (globalOrdinal );
183
+ }
184
+
185
+ @ Override
186
+ public boolean existsGlobalOrdinal (int globalOrdinal ) {
187
+ return ordsBits .get (globalOrdinal );
188
+ }
189
+
190
+ @ Override
191
+ public void close () {
192
+ ordsBits .close ();
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Uses a hashed representation of whether of the join field in the docs
198
+ * that match {@code ParentJoinAggregator#inFilter}. Its memory usage is
199
+ * proportional to the number of matching global ordinals so it is used
200
+ * when only some docs might match.
201
+ */
202
+ protected class SparseCollectionStrategy implements CollectionStrategy {
203
+ private final LongHash ordsHash ;
204
+
205
+ public SparseCollectionStrategy (BigArrays bigArrays ) {
206
+ ordsHash = new LongHash (1 , bigArrays );
207
+ }
208
+
209
+ @ Override
210
+ public void addGlobalOrdinal (int globalOrdinal ) {
211
+ ordsHash .add (globalOrdinal );
212
+ }
213
+
214
+ @ Override
215
+ public boolean existsGlobalOrdinal (int globalOrdinal ) {
216
+ return ordsHash .find (globalOrdinal ) >= 0 ;
217
+ }
218
+
219
+ @ Override
220
+ public void close () {
221
+ ordsHash .close ();
222
+ }
169
223
}
170
224
}
0 commit comments