40
40
import org .elasticsearch .Version ;
41
41
import org .elasticsearch .common .collect .Tuple ;
42
42
import org .elasticsearch .common .lucene .search .Queries ;
43
+ import org .elasticsearch .common .settings .Settings ;
43
44
import org .elasticsearch .index .mapper .IdFieldMapper ;
44
45
import org .elasticsearch .index .mapper .KeywordFieldMapper ;
45
46
import org .elasticsearch .index .mapper .MappedFieldType ;
48
49
import org .elasticsearch .index .mapper .TypeFieldMapper ;
49
50
import org .elasticsearch .index .mapper .Uid ;
50
51
import org .elasticsearch .index .query .MatchAllQueryBuilder ;
52
+ import org .elasticsearch .script .MockScriptEngine ;
53
+ import org .elasticsearch .script .Script ;
54
+ import org .elasticsearch .script .ScriptEngine ;
55
+ import org .elasticsearch .script .ScriptModule ;
56
+ import org .elasticsearch .script .ScriptService ;
57
+ import org .elasticsearch .script .ScriptType ;
51
58
import org .elasticsearch .search .aggregations .AggregatorTestCase ;
52
59
import org .elasticsearch .search .aggregations .BucketOrder ;
53
60
import org .elasticsearch .search .aggregations .InternalAggregation ;
54
61
import org .elasticsearch .search .aggregations .bucket .filter .Filter ;
55
62
import org .elasticsearch .search .aggregations .bucket .filter .FilterAggregationBuilder ;
63
+ import org .elasticsearch .search .aggregations .bucket .terms .InternalTerms ;
64
+ import org .elasticsearch .search .aggregations .bucket .terms .LongTerms ;
56
65
import org .elasticsearch .search .aggregations .bucket .terms .StringTerms ;
57
66
import org .elasticsearch .search .aggregations .bucket .terms .Terms ;
58
67
import org .elasticsearch .search .aggregations .bucket .terms .TermsAggregationBuilder ;
63
72
import org .elasticsearch .search .aggregations .metrics .MinAggregationBuilder ;
64
73
import org .elasticsearch .search .aggregations .metrics .InternalSum ;
65
74
import org .elasticsearch .search .aggregations .metrics .SumAggregationBuilder ;
75
+ import org .elasticsearch .search .aggregations .pipeline .BucketScriptPipelineAggregationBuilder ;
76
+ import org .elasticsearch .search .aggregations .pipeline .InternalSimpleValue ;
66
77
import org .elasticsearch .search .aggregations .support .AggregationInspectionHelper ;
67
78
import org .elasticsearch .search .aggregations .support .ValueType ;
68
79
import org .elasticsearch .test .VersionUtils ;
69
80
70
81
import java .io .IOException ;
71
82
import java .util .ArrayList ;
72
83
import java .util .Arrays ;
84
+ import java .util .Collections ;
85
+ import java .util .HashMap ;
73
86
import java .util .List ;
74
87
import java .util .Locale ;
75
88
import java .util .Map ;
@@ -88,6 +101,7 @@ public class NestedAggregatorTests extends AggregatorTestCase {
88
101
private static final String NESTED_AGG = "nestedAgg" ;
89
102
private static final String MAX_AGG_NAME = "maxAgg" ;
90
103
private static final String SUM_AGG_NAME = "sumAgg" ;
104
+ private static final String INVERSE_SCRIPT = "inverse" ;
91
105
92
106
private final SeqNoFieldMapper .SequenceIDFields sequenceIDFields = SeqNoFieldMapper .SequenceIDFields .emptySeqID ();
93
107
@@ -101,6 +115,18 @@ protected Map<String, MappedFieldType> getFieldAliases(MappedFieldType... fieldT
101
115
Function .identity ()));
102
116
}
103
117
118
+ @ Override
119
+ protected ScriptService getMockScriptService () {
120
+ Map <String , Function <Map <String , Object >, Object >> scripts = new HashMap <>();
121
+ scripts .put (INVERSE_SCRIPT , vars -> -((Number ) vars .get ("_value" )).doubleValue ());
122
+ MockScriptEngine scriptEngine = new MockScriptEngine (MockScriptEngine .NAME ,
123
+ scripts ,
124
+ Collections .emptyMap ());
125
+ Map <String , ScriptEngine > engines = Collections .singletonMap (scriptEngine .getType (), scriptEngine );
126
+
127
+ return new ScriptService (Settings .EMPTY , engines , ScriptModule .CORE_CONTEXTS );
128
+ }
129
+
104
130
public void testNoDocs () throws IOException {
105
131
try (Directory directory = newDirectory ()) {
106
132
try (RandomIndexWriter iw = new RandomIndexWriter (random (), directory )) {
@@ -711,6 +737,66 @@ public void testFieldAlias() throws IOException {
711
737
}
712
738
}
713
739
740
+ /**
741
+ * This tests to make sure pipeline aggs embedded under a SingleBucket agg (like nested)
742
+ * are properly reduced
743
+ */
744
+ public void testNestedWithPipeline () throws IOException {
745
+ int numRootDocs = randomIntBetween (1 , 20 );
746
+ int expectedNestedDocs = 0 ;
747
+ double expectedMaxValue = Double .NEGATIVE_INFINITY ;
748
+ try (Directory directory = newDirectory ()) {
749
+ try (RandomIndexWriter iw = new RandomIndexWriter (random (), directory )) {
750
+ for (int i = 0 ; i < numRootDocs ; i ++) {
751
+ List <Document > documents = new ArrayList <>();
752
+ expectedMaxValue = Math .max (expectedMaxValue ,
753
+ generateMaxDocs (documents , 1 , i , NESTED_OBJECT , VALUE_FIELD_NAME ));
754
+ expectedNestedDocs += 1 ;
755
+
756
+ Document document = new Document ();
757
+ document .add (new Field (IdFieldMapper .NAME , Uid .encodeId (Integer .toString (i )), IdFieldMapper .Defaults .FIELD_TYPE ));
758
+ document .add (new Field (TypeFieldMapper .NAME , "test" ,
759
+ TypeFieldMapper .Defaults .FIELD_TYPE ));
760
+ document .add (sequenceIDFields .primaryTerm );
761
+ documents .add (document );
762
+ iw .addDocuments (documents );
763
+ }
764
+ iw .commit ();
765
+ }
766
+ try (IndexReader indexReader = wrap (DirectoryReader .open (directory ))) {
767
+ NestedAggregationBuilder nestedBuilder = new NestedAggregationBuilder (NESTED_AGG , NESTED_OBJECT )
768
+ .subAggregation (new TermsAggregationBuilder ("terms" , ValueType .NUMERIC ).field (VALUE_FIELD_NAME )
769
+ .subAggregation (new MaxAggregationBuilder (MAX_AGG_NAME ).field (VALUE_FIELD_NAME ))
770
+ .subAggregation (new BucketScriptPipelineAggregationBuilder ("bucketscript" ,
771
+ Collections .singletonMap ("_value" , MAX_AGG_NAME ),
772
+ new Script (ScriptType .INLINE , MockScriptEngine .NAME , INVERSE_SCRIPT , Collections .emptyMap ()))));
773
+
774
+ MappedFieldType fieldType = new NumberFieldMapper .NumberFieldType (NumberFieldMapper .NumberType .LONG );
775
+ fieldType .setName (VALUE_FIELD_NAME );
776
+
777
+ InternalNested nested = searchAndReduce (newSearcher (indexReader , false , true ),
778
+ new MatchAllDocsQuery (), nestedBuilder , fieldType );
779
+
780
+ assertEquals (expectedNestedDocs , nested .getDocCount ());
781
+ assertEquals (NESTED_AGG , nested .getName ());
782
+ assertEquals (expectedNestedDocs , nested .getDocCount ());
783
+
784
+ InternalTerms <?, LongTerms .Bucket > terms = (InternalTerms ) nested .getProperty ("terms" );
785
+ assertNotNull (terms );
786
+
787
+ for (LongTerms .Bucket bucket : terms .getBuckets ()) {
788
+ InternalMax max = (InternalMax ) bucket .getAggregations ().asMap ().get (MAX_AGG_NAME );
789
+ InternalSimpleValue bucketScript = (InternalSimpleValue ) bucket .getAggregations ().asMap ().get ("bucketscript" );
790
+ assertNotNull (max );
791
+ assertNotNull (bucketScript );
792
+ assertEquals (max .getValue (), -bucketScript .getValue (), Double .MIN_VALUE );
793
+ }
794
+
795
+ assertTrue (AggregationInspectionHelper .hasValue (nested ));
796
+ }
797
+ }
798
+ }
799
+
714
800
private double generateMaxDocs (List <Document > documents , int numNestedDocs , int id , String path , String fieldName ) {
715
801
return DoubleStream .of (generateDocuments (documents , numNestedDocs , id , path , fieldName ))
716
802
.max ().orElse (Double .NEGATIVE_INFINITY );
0 commit comments