1212import org .elasticsearch .index .mapper .OnScriptError ;
1313import org .elasticsearch .plugins .Plugin ;
1414import org .elasticsearch .plugins .ScriptPlugin ;
15+ import org .elasticsearch .script .DoubleFieldScript ;
1516import org .elasticsearch .script .LongFieldScript ;
1617import org .elasticsearch .script .ScriptContext ;
1718import org .elasticsearch .script .ScriptEngine ;
19+ import org .elasticsearch .script .StringFieldScript ;
1820import org .elasticsearch .search .lookup .SearchLookup ;
1921import org .elasticsearch .test .ESIntegTestCase ;
2022import org .elasticsearch .xcontent .XContentBuilder ;
3739 */
3840@ ESIntegTestCase .ClusterScope (scope = SUITE , numDataNodes = 1 , numClientNodes = 0 , supportsDedicatedMasters = false ) // ESQL is single node
3941public class EsqlActionRuntimeFieldIT extends ESIntegTestCase {
42+ private static final int SIZE = 5000 ;
43+
4044 @ Override
4145 protected Collection <Class <? extends Plugin >> nodePlugins () {
42- return List .of (EsqlPlugin .class , PausableFieldPlugin .class );
46+ return List .of (EsqlPlugin .class , TestRuntimeFieldPlugin .class );
47+ }
48+
49+ public void testLong () throws InterruptedException , IOException {
50+ createIndexWithConstRuntimeField ("long" );
51+ EsqlQueryResponse response = EsqlActionIT .run ("from test | stats sum(const)" , Settings .EMPTY );
52+ assertThat (response .values (), equalTo (List .of (List .of ((long ) SIZE ))));
53+ }
54+
55+ public void testDouble () throws InterruptedException , IOException {
56+ createIndexWithConstRuntimeField ("double" );
57+ EsqlQueryResponse response = EsqlActionIT .run ("from test | stats sum(const)" , Settings .EMPTY );
58+ assertThat (response .values (), equalTo (List .of (List .of ((double ) SIZE ))));
59+ }
60+
61+ public void testKeyword () throws InterruptedException , IOException {
62+ createIndexWithConstRuntimeField ("keyword" );
63+ EsqlQueryResponse response = EsqlActionIT .run ("from test | project const | limit 1" , Settings .EMPTY );
64+ assertThat (response .values (), equalTo (List .of (List .of ("const" ))));
65+ }
66+
67+ /**
68+ * Test grouping by runtime keyword which requires disabling the ordinals
69+ * optimization available to more keyword fields.
70+ */
71+ public void testKeywordBy () throws InterruptedException , IOException {
72+ createIndexWithConstRuntimeField ("keyword" );
73+ EsqlQueryResponse response = EsqlActionIT .run ("from test | stats max(foo) by const" , Settings .EMPTY );
74+ assertThat (response .values (), equalTo (List .of (List .of (SIZE - 1L , "const" ))));
4375 }
4476
45- public void testTask ( ) throws InterruptedException , IOException {
77+ private void createIndexWithConstRuntimeField ( String type ) throws InterruptedException , IOException {
4678 XContentBuilder mapping = JsonXContent .contentBuilder ().startObject ();
4779 mapping .startObject ("runtime" );
4880 {
49- mapping .startObject ("pause_me " );
81+ mapping .startObject ("const " );
5082 {
51- mapping .field ("type" , "long" );
83+ mapping .field ("type" , type );
5284 mapping .startObject ("script" ).field ("source" , "" ).field ("lang" , "dummy" ).endObject ();
5385 }
5486 mapping .endObject ();
@@ -61,11 +93,9 @@ public void testTask() throws InterruptedException, IOException {
6193 indexRequests .add (client ().prepareIndex ("test" ).setId (Integer .toString (i )).setSource ("foo" , i ));
6294 }
6395 indexRandom (true , indexRequests );
64- EsqlQueryResponse response = EsqlActionIT .run ("from test | stats sum(pause_me)" , Settings .EMPTY );
65- assertThat (response .values (), equalTo (List .of (List .of (5000L ))));
6696 }
6797
68- public static class PausableFieldPlugin extends Plugin implements ScriptPlugin {
98+ public static class TestRuntimeFieldPlugin extends Plugin implements ScriptPlugin {
6999 @ Override
70100 public ScriptEngine getScriptEngine (Settings settings , Collection <ScriptContext <?>> contexts ) {
71101 return new ScriptEngine () {
@@ -82,22 +112,61 @@ public <FactoryType> FactoryType compile(
82112 ScriptContext <FactoryType > context ,
83113 Map <String , String > params
84114 ) {
85- return (FactoryType ) new LongFieldScript .Factory () {
86- @ Override
87- public LongFieldScript .LeafFactory newFactory (
88- String fieldName ,
89- Map <String , Object > params ,
90- SearchLookup searchLookup ,
91- OnScriptError onScriptError
92- ) {
93- return ctx -> new LongFieldScript (fieldName , params , searchLookup , onScriptError , ctx ) {
94- @ Override
95- public void execute () {
96- emit (1 );
97- }
98- };
99- }
100- };
115+ if (context == LongFieldScript .CONTEXT ) {
116+ return (FactoryType ) new LongFieldScript .Factory () {
117+ @ Override
118+ public LongFieldScript .LeafFactory newFactory (
119+ String fieldName ,
120+ Map <String , Object > params ,
121+ SearchLookup searchLookup ,
122+ OnScriptError onScriptError
123+ ) {
124+ return ctx -> new LongFieldScript (fieldName , params , searchLookup , onScriptError , ctx ) {
125+ @ Override
126+ public void execute () {
127+ emit (1 );
128+ }
129+ };
130+ }
131+ };
132+ }
133+ if (context == DoubleFieldScript .CONTEXT ) {
134+ return (FactoryType ) new DoubleFieldScript .Factory () {
135+ @ Override
136+ public DoubleFieldScript .LeafFactory newFactory (
137+ String fieldName ,
138+ Map <String , Object > params ,
139+ SearchLookup searchLookup ,
140+ OnScriptError onScriptError
141+ ) {
142+ return ctx -> new DoubleFieldScript (fieldName , params , searchLookup , onScriptError , ctx ) {
143+ @ Override
144+ public void execute () {
145+ emit (1.0 );
146+ }
147+ };
148+ }
149+ };
150+ }
151+ if (context == StringFieldScript .CONTEXT ) {
152+ return (FactoryType ) new StringFieldScript .Factory () {
153+ @ Override
154+ public StringFieldScript .LeafFactory newFactory (
155+ String fieldName ,
156+ Map <String , Object > params ,
157+ SearchLookup searchLookup ,
158+ OnScriptError onScriptError
159+ ) {
160+ return ctx -> new StringFieldScript (fieldName , params , searchLookup , onScriptError , ctx ) {
161+ @ Override
162+ public void execute () {
163+ emit ("const" );
164+ }
165+ };
166+ }
167+ };
168+ }
169+ throw new IllegalArgumentException ("unsupported context " + context );
101170 }
102171
103172 @ Override
0 commit comments