Skip to content

Commit 9479ec1

Browse files
authored
Make parent and child aggregator more obvious (#57490)
Pulls the way that the `ParentJoinAggregator` collects global ordinals into a strategy object so it is a little simpler to reason about and it'll be simpler to save memory by removing `asMultiBucketAggregator` in the future. Relates to #56487
1 parent 94cb1e2 commit 9479ec1

File tree

1 file changed

+79
-25
lines changed

1 file changed

+79
-25
lines changed

modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ParentJoinAggregator.java

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
import org.apache.lucene.search.Scorer;
2929
import org.apache.lucene.search.Weight;
3030
import org.apache.lucene.util.Bits;
31+
import org.elasticsearch.common.lease.Releasable;
3132
import org.elasticsearch.common.lease.Releasables;
3233
import org.elasticsearch.common.lucene.Lucene;
34+
import org.elasticsearch.common.util.BigArrays;
3335
import org.elasticsearch.common.util.BitArray;
3436
import org.elasticsearch.common.util.LongHash;
3537
import org.elasticsearch.search.aggregations.Aggregator;
@@ -52,16 +54,11 @@ public abstract class ParentJoinAggregator extends BucketsAggregator implements
5254
private final Weight inFilter;
5355
private final Weight outFilter;
5456
private final ValuesSource.Bytes.WithOrdinals valuesSource;
55-
private final boolean singleAggregator;
5657

5758
/**
58-
* If this aggregator is nested under another aggregator we allocate a long hash per bucket.
59+
* Strategy for collecting results.
5960
*/
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;
6562

6663
public ParentJoinAggregator(String name,
6764
AggregatorFactories factories,
@@ -83,21 +80,9 @@ public ParentJoinAggregator(String name,
8380
this.inFilter = context.searcher().createWeight(context.searcher().rewrite(inFilter), ScoreMode.COMPLETE_NO_SCORES, 1f);
8481
this.outFilter = context.searcher().createWeight(context.searcher().rewrite(outFilter), ScoreMode.COMPLETE_NO_SCORES, 1f);
8582
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());
10186
}
10287

10388
@Override
@@ -115,7 +100,7 @@ public void collect(int docId, long bucket) throws IOException {
115100
if (parentDocs.get(docId) && globalOrdinals.advanceExact(docId)) {
116101
int globalOrdinal = (int) globalOrdinals.nextOrd();
117102
assert globalOrdinal != -1 && globalOrdinals.nextOrd() == SortedSetDocValues.NO_MORE_ORDS;
118-
addGlobalOrdinal(globalOrdinal);
103+
collectionStrategy.addGlobalOrdinal(globalOrdinal);
119104
}
120105
}
121106
};
@@ -155,7 +140,7 @@ public int docID() {
155140
if (globalOrdinals.advanceExact(docId)) {
156141
int globalOrdinal = (int) globalOrdinals.nextOrd();
157142
assert globalOrdinal != -1 && globalOrdinals.nextOrd() == SortedSetDocValues.NO_MORE_ORDS;
158-
if (existsGlobalOrdinal(globalOrdinal)) {
143+
if (collectionStrategy.existsGlobalOrdinal(globalOrdinal)) {
159144
collectBucket(sub, docId, 0);
160145
}
161146
}
@@ -165,6 +150,75 @@ public int docID() {
165150

166151
@Override
167152
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+
}
169223
}
170224
}

0 commit comments

Comments
 (0)