18
18
*/
19
19
package org .elasticsearch .join .aggregations ;
20
20
21
- import org .apache .lucene .index .IndexReader ;
22
- import org .apache .lucene .index .LeafReaderContext ;
23
- import org .apache .lucene .index .SortedSetDocValues ;
24
- import org .apache .lucene .search .ConstantScoreScorer ;
25
- import org .apache .lucene .search .DocIdSetIterator ;
26
21
import org .apache .lucene .search .Query ;
27
- import org .apache .lucene .search .Scorer ;
28
- import org .apache .lucene .search .Weight ;
29
- import org .apache .lucene .util .Bits ;
30
22
import org .elasticsearch .common .ParseField ;
31
- import org .elasticsearch .common .lease .Releasables ;
32
- import org .elasticsearch .common .lucene .Lucene ;
33
- import org .elasticsearch .common .util .LongArray ;
34
- import org .elasticsearch .common .util .LongObjectPagedHashMap ;
35
23
import org .elasticsearch .search .aggregations .Aggregator ;
36
24
import org .elasticsearch .search .aggregations .AggregatorFactories ;
37
25
import org .elasticsearch .search .aggregations .InternalAggregation ;
38
- import org .elasticsearch .search .aggregations .LeafBucketCollector ;
39
- import org .elasticsearch .search .aggregations .bucket .BucketsAggregator ;
40
- import org .elasticsearch .search .aggregations .bucket .SingleBucketAggregator ;
41
26
import org .elasticsearch .search .aggregations .pipeline .PipelineAggregator ;
42
27
import org .elasticsearch .search .aggregations .support .ValuesSource ;
43
28
import org .elasticsearch .search .internal .SearchContext ;
44
29
45
30
import java .io .IOException ;
46
- import java .util .Arrays ;
47
31
import java .util .List ;
48
32
import java .util .Map ;
49
33
50
- // The RecordingPerReaderBucketCollector assumes per segment recording which isn't the case for this
51
- // aggregation, for this reason that collector can't be used
52
- public class ParentToChildrenAggregator extends BucketsAggregator implements SingleBucketAggregator {
34
+ public class ParentToChildrenAggregator extends ParentJoinAggregator {
53
35
54
36
static final ParseField TYPE_FIELD = new ParseField ("type" );
55
37
56
- private final Weight childFilter ;
57
- private final Weight parentFilter ;
58
- private final ValuesSource .Bytes .WithOrdinals valuesSource ;
59
-
60
- // Maybe use PagedGrowableWriter? This will be less wasteful than LongArray,
61
- // but then we don't have the reuse feature of BigArrays.
62
- // Also if we know the highest possible value that a parent agg will create
63
- // then we store multiple values into one slot
64
- private final LongArray parentOrdToBuckets ;
65
-
66
- // Only pay the extra storage price if the a parentOrd has multiple buckets
67
- // Most of the times a parent doesn't have multiple buckets, since there is
68
- // only one document per parent ord,
69
- // only in the case of terms agg if a parent doc has multiple terms per
70
- // field this is needed:
71
- private final LongObjectPagedHashMap <long []> parentOrdToOtherBuckets ;
72
- private boolean multipleBucketsPerParentOrd = false ;
73
-
74
38
public ParentToChildrenAggregator (String name , AggregatorFactories factories ,
75
39
SearchContext context , Aggregator parent , Query childFilter ,
76
40
Query parentFilter , ValuesSource .Bytes .WithOrdinals valuesSource ,
77
- long maxOrd , List <PipelineAggregator > pipelineAggregators , Map <String , Object > metaData )
78
- throws IOException {
79
- super (name , factories , context , parent , pipelineAggregators , metaData );
80
- // these two filters are cached in the parser
81
- this .childFilter = context .searcher ().createNormalizedWeight (childFilter , false );
82
- this .parentFilter = context .searcher ().createNormalizedWeight (parentFilter , false );
83
- this .parentOrdToBuckets = context .bigArrays ().newLongArray (maxOrd , false );
84
- this .parentOrdToBuckets .fill (0 , maxOrd , -1 );
85
- this .parentOrdToOtherBuckets = new LongObjectPagedHashMap <>(context .bigArrays ());
86
- this .valuesSource = valuesSource ;
41
+ long maxOrd , List <PipelineAggregator > pipelineAggregators , Map <String , Object > metaData ) throws IOException {
42
+ super (name , factories , context , parent , parentFilter , childFilter , valuesSource , maxOrd , pipelineAggregators , metaData );
87
43
}
88
44
89
45
@ Override
@@ -97,87 +53,4 @@ public InternalAggregation buildEmptyAggregation() {
97
53
return new InternalChildren (name , 0 , buildEmptySubAggregations (), pipelineAggregators (),
98
54
metaData ());
99
55
}
100
-
101
- @ Override
102
- public LeafBucketCollector getLeafCollector (LeafReaderContext ctx ,
103
- final LeafBucketCollector sub ) throws IOException {
104
- if (valuesSource == null ) {
105
- return LeafBucketCollector .NO_OP_COLLECTOR ;
106
- }
107
- final SortedSetDocValues globalOrdinals = valuesSource .globalOrdinalsValues (ctx );
108
- final Bits parentDocs = Lucene .asSequentialAccessBits (ctx .reader ().maxDoc (), parentFilter .scorerSupplier (ctx ));
109
- return new LeafBucketCollector () {
110
-
111
- @ Override
112
- public void collect (int docId , long bucket ) throws IOException {
113
- if (parentDocs .get (docId ) && globalOrdinals .advanceExact (docId )) {
114
- long globalOrdinal = globalOrdinals .nextOrd ();
115
- assert globalOrdinals .nextOrd () == SortedSetDocValues .NO_MORE_ORDS ;
116
- if (globalOrdinal != -1 ) {
117
- if (parentOrdToBuckets .get (globalOrdinal ) == -1 ) {
118
- parentOrdToBuckets .set (globalOrdinal , bucket );
119
- } else {
120
- long [] bucketOrds = parentOrdToOtherBuckets .get (globalOrdinal );
121
- if (bucketOrds != null ) {
122
- bucketOrds = Arrays .copyOf (bucketOrds , bucketOrds .length + 1 );
123
- bucketOrds [bucketOrds .length - 1 ] = bucket ;
124
- parentOrdToOtherBuckets .put (globalOrdinal , bucketOrds );
125
- } else {
126
- parentOrdToOtherBuckets .put (globalOrdinal , new long [] { bucket });
127
- }
128
- multipleBucketsPerParentOrd = true ;
129
- }
130
- }
131
- }
132
- }
133
- };
134
- }
135
-
136
- @ Override
137
- protected void doPostCollection () throws IOException {
138
- IndexReader indexReader = context ().searcher ().getIndexReader ();
139
- for (LeafReaderContext ctx : indexReader .leaves ()) {
140
- Scorer childDocsScorer = childFilter .scorer (ctx );
141
- if (childDocsScorer == null ) {
142
- continue ;
143
- }
144
- DocIdSetIterator childDocsIter = childDocsScorer .iterator ();
145
-
146
- final LeafBucketCollector sub = collectableSubAggregators .getLeafCollector (ctx );
147
-
148
- final SortedSetDocValues globalOrdinals = valuesSource .globalOrdinalsValues (ctx );
149
- // Set the scorer, since we now replay only the child docIds
150
- sub .setScorer (new ConstantScoreScorer (null , 1f , childDocsIter ));
151
-
152
- final Bits liveDocs = ctx .reader ().getLiveDocs ();
153
- for (int docId = childDocsIter
154
- .nextDoc (); docId != DocIdSetIterator .NO_MORE_DOCS ; docId = childDocsIter
155
- .nextDoc ()) {
156
- if (liveDocs != null && liveDocs .get (docId ) == false ) {
157
- continue ;
158
- }
159
- if (globalOrdinals .advanceExact (docId )) {
160
- long globalOrdinal = globalOrdinals .nextOrd ();
161
- assert globalOrdinals .nextOrd () == SortedSetDocValues .NO_MORE_ORDS ;
162
- long bucketOrd = parentOrdToBuckets .get (globalOrdinal );
163
- if (bucketOrd != -1 ) {
164
- collectBucket (sub , docId , bucketOrd );
165
- if (multipleBucketsPerParentOrd ) {
166
- long [] otherBucketOrds = parentOrdToOtherBuckets .get (globalOrdinal );
167
- if (otherBucketOrds != null ) {
168
- for (long otherBucketOrd : otherBucketOrds ) {
169
- collectBucket (sub , docId , otherBucketOrd );
170
- }
171
- }
172
- }
173
- }
174
- }
175
- }
176
- }
177
- }
178
-
179
- @ Override
180
- protected void doClose () {
181
- Releasables .close (parentOrdToBuckets , parentOrdToOtherBuckets );
182
- }
183
56
}
0 commit comments