27
27
import org .elasticsearch .search .aggregations .bucket .BucketsAggregator ;
28
28
import org .elasticsearch .search .aggregations .bucket .MultiBucketsAggregation ;
29
29
import org .elasticsearch .search .aggregations .bucket .SingleBucketAggregator ;
30
+ import org .elasticsearch .search .aggregations .bucket .terms .Terms .Bucket ;
30
31
import org .elasticsearch .search .aggregations .metrics .NumericMetricsAggregator ;
31
32
import org .elasticsearch .search .aggregations .support .OrderPath ;
32
33
33
34
import java .io .IOException ;
34
- import java .util .Comparator ;
35
+ import java .util .* ;
35
36
36
37
/**
37
38
*
38
39
*/
39
40
class InternalOrder extends Terms .Order {
40
41
42
+ private static final byte COUNT_DESC_ID = 1 ;
43
+ private static final byte COUNT_ASC_ID = 2 ;
44
+ private static final byte TERM_DESC_ID = 3 ;
45
+ private static final byte TERM_ASC_ID = 4 ;
46
+
41
47
/**
42
48
* Order by the (higher) count of each term.
43
49
*/
44
- public static final InternalOrder COUNT_DESC = new InternalOrder (( byte ) 1 , "_count" , false , new Comparator <Terms .Bucket >() {
50
+ public static final InternalOrder COUNT_DESC = new InternalOrder (COUNT_DESC_ID , "_count" , false , new Comparator <Terms .Bucket >() {
45
51
@ Override
46
52
public int compare (Terms .Bucket o1 , Terms .Bucket o2 ) {
47
- int cmp = - Long .compare (o1 .getDocCount (), o2 .getDocCount ());
48
- if (cmp == 0 ) {
49
- cmp = o1 .compareTerm (o2 );
50
- }
51
- return cmp ;
53
+ return Long .compare (o2 .getDocCount (), o1 .getDocCount ());
52
54
}
53
55
});
54
56
55
57
/**
56
58
* Order by the (lower) count of each term.
57
59
*/
58
- public static final InternalOrder COUNT_ASC = new InternalOrder (( byte ) 2 , "_count" , true , new Comparator <Terms .Bucket >() {
60
+ public static final InternalOrder COUNT_ASC = new InternalOrder (COUNT_ASC_ID , "_count" , true , new Comparator <Terms .Bucket >() {
59
61
60
62
@ Override
61
63
public int compare (Terms .Bucket o1 , Terms .Bucket o2 ) {
62
- int cmp = Long .compare (o1 .getDocCount (), o2 .getDocCount ());
63
- if (cmp == 0 ) {
64
- cmp = o1 .compareTerm (o2 );
65
- }
66
- return cmp ;
64
+ return Long .compare (o1 .getDocCount (), o2 .getDocCount ());
67
65
}
68
66
});
69
67
70
68
/**
71
69
* Order by the terms.
72
70
*/
73
- public static final InternalOrder TERM_DESC = new InternalOrder (( byte ) 3 , "_term" , false , new Comparator <Terms .Bucket >() {
71
+ public static final InternalOrder TERM_DESC = new InternalOrder (TERM_DESC_ID , "_term" , false , new Comparator <Terms .Bucket >() {
74
72
75
73
@ Override
76
74
public int compare (Terms .Bucket o1 , Terms .Bucket o2 ) {
77
- return - o1 .compareTerm (o2 );
75
+ return o2 .compareTerm (o1 );
78
76
}
79
77
});
80
78
81
79
/**
82
80
* Order by the terms.
83
81
*/
84
- public static final InternalOrder TERM_ASC = new InternalOrder (( byte ) 4 , "_term" , true , new Comparator <Terms .Bucket >() {
82
+ public static final InternalOrder TERM_ASC = new InternalOrder (TERM_ASC_ID , "_term" , true , new Comparator <Terms .Bucket >() {
85
83
86
84
@ Override
87
85
public int compare (Terms .Bucket o1 , Terms .Bucket o2 ) {
88
86
return o1 .compareTerm (o2 );
89
87
}
90
88
});
91
89
90
+ public static boolean isCountDesc (Terms .Order order ) {
91
+ if (order == COUNT_DESC ) {
92
+ return true ;
93
+ }else if (order instanceof CompoundOrder ) {
94
+ // check if its a compound order with count desc and the tie breaker (term asc)
95
+ CompoundOrder compoundOrder = (CompoundOrder ) order ;
96
+ if (compoundOrder .compoundOrder .size () == 2 && compoundOrder .compoundOrder .get (0 ) == COUNT_DESC && compoundOrder .compoundOrder .get (1 ) == TERM_ASC ) {
97
+ return true ;
98
+ }
99
+ }
100
+ return false ;
101
+ }
92
102
93
103
final byte id ;
94
104
final String key ;
@@ -116,8 +126,13 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
116
126
return builder .startObject ().field (key , asc ? "asc" : "desc" ).endObject ();
117
127
}
118
128
119
- public static InternalOrder validate (InternalOrder order , Aggregator termsAggregator ) {
120
- if (!(order instanceof Aggregation )) {
129
+ public static Terms .Order validate (Terms .Order order , Aggregator termsAggregator ) {
130
+ if (order instanceof CompoundOrder ) {
131
+ for (Terms .Order innerOrder : ((CompoundOrder )order ).compoundOrder ) {
132
+ validate (innerOrder , termsAggregator );
133
+ }
134
+ return order ;
135
+ } else if (!(order instanceof Aggregation )) {
121
136
return order ;
122
137
}
123
138
OrderPath path = ((Aggregation ) order ).path ();
@@ -199,12 +214,63 @@ public int compare(Terms.Bucket o1, Terms.Bucket o2) {
199
214
}
200
215
}
201
216
217
+ static class CompoundOrder extends Terms .Order {
218
+
219
+ static final byte ID = -1 ;
220
+
221
+ private final List <Terms .Order > compoundOrder ;
222
+
223
+ public CompoundOrder (List <Terms .Order > compoundOrder ) {
224
+ this .compoundOrder = new LinkedList <>(compoundOrder );
225
+ }
226
+
227
+ @ Override
228
+ byte id () {
229
+ return ID ;
230
+ }
231
+
232
+ @ Override
233
+ public XContentBuilder toXContent (XContentBuilder builder , Params params ) throws IOException {
234
+ builder .startArray ();
235
+ for (Terms .Order order : compoundOrder ) {
236
+ order .toXContent (builder , params );
237
+ }
238
+ return builder .endArray ();
239
+ }
240
+
241
+ @ Override
242
+ protected Comparator <Bucket > comparator (Aggregator aggregator ) {
243
+ return new CompoundOrderComparator (compoundOrder , aggregator );
244
+ }
245
+
246
+ public static class CompoundOrderComparator implements Comparator <Terms .Bucket > {
247
+
248
+ private List <Terms .Order > compoundOrder ;
249
+ private Aggregator aggregator ;
250
+
251
+ public CompoundOrderComparator (List <Terms .Order > compoundOrder , Aggregator aggregator ) {
252
+ this .compoundOrder = compoundOrder ;
253
+ this .aggregator = aggregator ;
254
+ }
255
+
256
+ @ Override
257
+ public int compare (Bucket o1 , Bucket o2 ) {
258
+ int result = 0 ;
259
+ for (Iterator <Terms .Order > itr = compoundOrder .iterator (); itr .hasNext () && result == 0 ;) {
260
+ result = itr .next ().comparator (aggregator ).compare (o1 , o2 );
261
+ }
262
+ return result ;
263
+ }
264
+ }
265
+ }
266
+
202
267
public static class Streams {
203
268
204
- public static void writeOrder (InternalOrder order , StreamOutput out ) throws IOException {
269
+ public static void writeOrder (Terms . Order order , StreamOutput out ) throws IOException {
205
270
out .writeByte (order .id ());
206
271
if (order instanceof Aggregation ) {
207
- out .writeBoolean (((MultiBucketsAggregation .Bucket .SubAggregationComparator ) order .comparator ).asc ());
272
+ Aggregation aggregationOrder = (Aggregation ) order ;
273
+ out .writeBoolean (((MultiBucketsAggregation .Bucket .SubAggregationComparator ) aggregationOrder .comparator ).asc ());
208
274
OrderPath path = ((Aggregation ) order ).path ();
209
275
if (out .getVersion ().onOrAfter (Version .V_1_1_0 )) {
210
276
out .writeString (path .toString ());
@@ -218,17 +284,23 @@ public static void writeOrder(InternalOrder order, StreamOutput out) throws IOEx
218
284
out .writeString (token .key );
219
285
}
220
286
}
287
+ } else if (order instanceof CompoundOrder ) {
288
+ CompoundOrder compoundOrder = (CompoundOrder ) order ;
289
+ out .writeVInt (compoundOrder .compoundOrder .size ());
290
+ for (Terms .Order innerOrder : compoundOrder .compoundOrder ) {
291
+ Streams .writeOrder (innerOrder , out );
292
+ }
221
293
}
222
294
}
223
295
224
- public static InternalOrder readOrder (StreamInput in ) throws IOException {
296
+ public static Terms . Order readOrder (StreamInput in ) throws IOException {
225
297
byte id = in .readByte ();
226
298
switch (id ) {
227
- case 1 : return InternalOrder .COUNT_DESC ;
228
- case 2 : return InternalOrder .COUNT_ASC ;
229
- case 3 : return InternalOrder .TERM_DESC ;
230
- case 4 : return InternalOrder .TERM_ASC ;
231
- case 0 :
299
+ case COUNT_DESC_ID : return InternalOrder .COUNT_DESC ;
300
+ case COUNT_ASC_ID : return InternalOrder .COUNT_ASC ;
301
+ case TERM_DESC_ID : return InternalOrder .TERM_DESC ;
302
+ case TERM_ASC_ID : return InternalOrder .TERM_ASC ;
303
+ case Aggregation . ID :
232
304
boolean asc = in .readBoolean ();
233
305
String key = in .readString ();
234
306
if (in .getVersion ().onOrAfter (Version .V_1_1_0 )) {
@@ -239,6 +311,13 @@ public static InternalOrder readOrder(StreamInput in) throws IOException {
239
311
return new InternalOrder .Aggregation (key + "." + in .readString (), asc );
240
312
}
241
313
return new InternalOrder .Aggregation (key , asc );
314
+ case CompoundOrder .ID :
315
+ int size = in .readVInt ();
316
+ List <Terms .Order > compoundOrder = new ArrayList <>(size );
317
+ for (int i = 0 ; i < size ; i ++) {
318
+ compoundOrder .add (Streams .readOrder (in ));
319
+ }
320
+ return new CompoundOrder (compoundOrder );
242
321
default :
243
322
throw new RuntimeException ("unknown terms order" );
244
323
}
0 commit comments