3333import org .elasticsearch .common .util .IntArray ;
3434import org .elasticsearch .common .util .LongHash ;
3535import org .elasticsearch .common .xcontent .XContentBuilder ;
36- import org .elasticsearch .index .fielddata .AbstractSortedSetDocValues ;
3736import org .elasticsearch .search .DocValueFormat ;
3837import org .elasticsearch .search .aggregations .Aggregator ;
3938import org .elasticsearch .search .aggregations .AggregatorFactories ;
@@ -73,6 +72,8 @@ public class GlobalOrdinalsStringTermsAggregator extends AbstractStringTermsAggr
7372 private final long valueCount ;
7473 private final GlobalOrdLookupFunction lookupGlobalOrd ;
7574 protected final CollectionStrategy collectionStrategy ;
75+ protected int segmentsWithSingleValuedOrds = 0 ;
76+ protected int segmentsWithMultiValuedOrds = 0 ;
7677
7778 public interface GlobalOrdLookupFunction {
7879 BytesRef apply (long ord ) throws IOException ;
@@ -102,32 +103,68 @@ public GlobalOrdinalsStringTermsAggregator(
102103 valuesSource .globalOrdinalsValues (context .searcher ().getIndexReader ().leaves ().get (0 )) : DocValues .emptySortedSet ();
103104 this .valueCount = values .getValueCount ();
104105 this .lookupGlobalOrd = values ::lookupOrd ;
105- this .acceptedGlobalOrdinals = includeExclude == null ? l -> true : includeExclude .acceptedGlobalOrdinals (values )::get ;
106+ this .acceptedGlobalOrdinals = includeExclude == null ? ALWAYS_TRUE : includeExclude .acceptedGlobalOrdinals (values )::get ;
106107 this .collectionStrategy = remapGlobalOrds ? new RemapGlobalOrds () : new DenseGlobalOrds ();
107108 }
108109
109110 String descriptCollectionStrategy () {
110111 return collectionStrategy .describe ();
111112 }
112113
113- private SortedSetDocValues getGlobalOrds (LeafReaderContext ctx ) throws IOException {
114- return acceptedGlobalOrdinals == null ?
115- valuesSource .globalOrdinalsValues (ctx ) : new FilteredOrdinals (valuesSource .globalOrdinalsValues (ctx ), acceptedGlobalOrdinals );
116- }
117-
118114 @ Override
119115 public LeafBucketCollector getLeafCollector (LeafReaderContext ctx , LeafBucketCollector sub ) throws IOException {
120- SortedSetDocValues globalOrds = getGlobalOrds (ctx );
116+ SortedSetDocValues globalOrds = valuesSource . globalOrdinalsValues (ctx );
121117 collectionStrategy .globalOrdsReady (globalOrds );
122118 SortedDocValues singleValues = DocValues .unwrapSingleton (globalOrds );
123119 if (singleValues != null ) {
120+ segmentsWithSingleValuedOrds ++;
121+ if (acceptedGlobalOrdinals == ALWAYS_TRUE ) {
122+ /*
123+ * Optimize when there isn't a filter because that is very
124+ * common and marginally faster.
125+ */
126+ return resultStrategy .wrapCollector (new LeafBucketCollectorBase (sub , globalOrds ) {
127+ @ Override
128+ public void collect (int doc , long owningBucketOrd ) throws IOException {
129+ assert owningBucketOrd == 0 ;
130+ if (false == singleValues .advanceExact (doc )) {
131+ return ;
132+ }
133+ int globalOrd = singleValues .ordValue ();
134+ collectionStrategy .collectGlobalOrd (doc , globalOrd , sub );
135+ }
136+ });
137+ }
124138 return resultStrategy .wrapCollector (new LeafBucketCollectorBase (sub , globalOrds ) {
125139 @ Override
126140 public void collect (int doc , long owningBucketOrd ) throws IOException {
127141 assert owningBucketOrd == 0 ;
128- if (singleValues .advanceExact (doc )) {
129- int ord = singleValues .ordValue ();
130- collectionStrategy .collectGlobalOrd (doc , ord , sub );
142+ if (false == singleValues .advanceExact (doc )) {
143+ return ;
144+ }
145+ int globalOrd = singleValues .ordValue ();
146+ if (false == acceptedGlobalOrdinals .test (globalOrd )) {
147+ return ;
148+ }
149+ collectionStrategy .collectGlobalOrd (doc , globalOrd , sub );
150+ }
151+ });
152+ }
153+ segmentsWithMultiValuedOrds ++;
154+ if (acceptedGlobalOrdinals == ALWAYS_TRUE ) {
155+ /*
156+ * Optimize when there isn't a filter because that is very
157+ * common and marginally faster.
158+ */
159+ return resultStrategy .wrapCollector (new LeafBucketCollectorBase (sub , globalOrds ) {
160+ @ Override
161+ public void collect (int doc , long owningBucketOrd ) throws IOException {
162+ assert owningBucketOrd == 0 ;
163+ if (false == globalOrds .advanceExact (doc )) {
164+ return ;
165+ }
166+ for (long globalOrd = globalOrds .nextOrd (); globalOrd != NO_MORE_ORDS ; globalOrd = globalOrds .nextOrd ()) {
167+ collectionStrategy .collectGlobalOrd (doc , globalOrd , sub );
131168 }
132169 }
133170 });
@@ -136,10 +173,14 @@ public void collect(int doc, long owningBucketOrd) throws IOException {
136173 @ Override
137174 public void collect (int doc , long owningBucketOrd ) throws IOException {
138175 assert owningBucketOrd == 0 ;
139- if (globalOrds .advanceExact (doc )) {
140- for (long globalOrd = globalOrds .nextOrd (); globalOrd != NO_MORE_ORDS ; globalOrd = globalOrds .nextOrd ()) {
141- collectionStrategy .collectGlobalOrd (doc , globalOrd , sub );
176+ if (false == globalOrds .advanceExact (doc )) {
177+ return ;
178+ }
179+ for (long globalOrd = globalOrds .nextOrd (); globalOrd != NO_MORE_ORDS ; globalOrd = globalOrds .nextOrd ()) {
180+ if (false == acceptedGlobalOrdinals .test (globalOrd )) {
181+ continue ;
142182 }
183+ collectionStrategy .collectGlobalOrd (doc , globalOrd , sub );
143184 }
144185 }
145186 });
@@ -160,6 +201,9 @@ public void collectDebugInfo(BiConsumer<String, Object> add) {
160201 super .collectDebugInfo (add );
161202 add .accept ("collection_strategy" , collectionStrategy .describe ());
162203 add .accept ("result_strategy" , resultStrategy .describe ());
204+ add .accept ("segments_with_single_valued_ords" , segmentsWithSingleValuedOrds );
205+ add .accept ("segments_with_multi_valued_ords" , segmentsWithMultiValuedOrds );
206+ add .accept ("has_filter" , acceptedGlobalOrdinals != ALWAYS_TRUE );
163207 }
164208
165209 /**
@@ -253,26 +297,31 @@ public LeafBucketCollector getLeafCollector(LeafReaderContext ctx, LeafBucketCol
253297 assert sub == LeafBucketCollector .NO_OP_COLLECTOR ;
254298 final SortedDocValues singleValues = DocValues .unwrapSingleton (segmentOrds );
255299 mapping = valuesSource .globalOrdinalsMapping (ctx );
300+ // Dense mode doesn't support include/exclude so we don't have to check it here.
256301 if (singleValues != null ) {
302+ segmentsWithSingleValuedOrds ++;
257303 return resultStrategy .wrapCollector (new LeafBucketCollectorBase (sub , segmentOrds ) {
258304 @ Override
259305 public void collect (int doc , long owningBucketOrd ) throws IOException {
260306 assert owningBucketOrd == 0 ;
261- if (singleValues .advanceExact (doc )) {
262- final int ord = singleValues .ordValue ();
263- segmentDocCounts .increment (ord + 1 , 1 );
307+ if (false == singleValues .advanceExact (doc )) {
308+ return ;
264309 }
310+ int ord = singleValues .ordValue ();
311+ segmentDocCounts .increment (ord + 1 , 1 );
265312 }
266313 });
267314 }
315+ segmentsWithMultiValuedOrds ++;
268316 return resultStrategy .wrapCollector (new LeafBucketCollectorBase (sub , segmentOrds ) {
269317 @ Override
270318 public void collect (int doc , long owningBucketOrd ) throws IOException {
271319 assert owningBucketOrd == 0 ;
272- if (segmentOrds .advanceExact (doc )) {
273- for (long segmentOrd = segmentOrds .nextOrd (); segmentOrd != NO_MORE_ORDS ; segmentOrd = segmentOrds .nextOrd ()) {
274- segmentDocCounts .increment (segmentOrd + 1 , 1 );
275- }
320+ if (false == segmentOrds .advanceExact (doc )) {
321+ return ;
322+ }
323+ for (long segmentOrd = segmentOrds .nextOrd (); segmentOrd != NO_MORE_ORDS ; segmentOrd = segmentOrds .nextOrd ()) {
324+ segmentDocCounts .increment (segmentOrd + 1 , 1 );
276325 }
277326 }
278327 });
@@ -306,52 +355,6 @@ private void mapSegmentCountsToGlobalCounts(LongUnaryOperator mapping) throws IO
306355 }
307356 }
308357
309- private static final class FilteredOrdinals extends AbstractSortedSetDocValues {
310-
311- private final SortedSetDocValues inner ;
312- private final LongPredicate accepted ;
313-
314- private FilteredOrdinals (SortedSetDocValues inner , LongPredicate accepted ) {
315- this .inner = inner ;
316- this .accepted = accepted ;
317- }
318-
319- @ Override
320- public long getValueCount () {
321- return inner .getValueCount ();
322- }
323-
324- @ Override
325- public BytesRef lookupOrd (long ord ) throws IOException {
326- return inner .lookupOrd (ord );
327- }
328-
329- @ Override
330- public long nextOrd () throws IOException {
331- for (long ord = inner .nextOrd (); ord != NO_MORE_ORDS ; ord = inner .nextOrd ()) {
332- if (accepted .test (ord )) {
333- return ord ;
334- }
335- }
336- return NO_MORE_ORDS ;
337- }
338-
339- @ Override
340- public boolean advanceExact (int target ) throws IOException {
341- if (inner .advanceExact (target )) {
342- for (long ord = inner .nextOrd (); ord != NO_MORE_ORDS ; ord = inner .nextOrd ()) {
343- if (accepted .test (ord )) {
344- // reset the iterator
345- boolean advanced = inner .advanceExact (target );
346- assert advanced ;
347- return true ;
348- }
349- }
350- }
351- return false ;
352- }
353- }
354-
355358 /**
356359 * Strategy for collecting global ordinals.
357360 * <p>
@@ -800,4 +803,9 @@ private void oversizedCopy(BytesRef from, BytesRef to) {
800803 System .arraycopy (from .bytes , from .offset , to .bytes , 0 , from .length );
801804 }
802805 }
806+
807+ /**
808+ * Predicate used for {@link #acceptedGlobalOrdinals} if there is no filter.
809+ */
810+ private static final LongPredicate ALWAYS_TRUE = l -> true ;
803811}
0 commit comments