2828import org .apache .lucene .tests .index .RandomIndexWriter ;
2929import org .apache .lucene .util .BytesRef ;
3030import org .elasticsearch .common .lucene .search .function .ScriptScoreQuery ;
31+ import org .elasticsearch .common .settings .Settings ;
3132import org .elasticsearch .index .IndexVersion ;
3233import org .elasticsearch .index .fielddata .DoubleScriptFieldData ;
3334import org .elasticsearch .index .fielddata .ScriptDocValues ;
4041import org .elasticsearch .script .ScriptFactory ;
4142import org .elasticsearch .script .ScriptType ;
4243import org .elasticsearch .search .MultiValueMode ;
44+ import org .elasticsearch .search .lookup .SearchLookup ;
4345
4446import java .io .IOException ;
4547import java .util .ArrayList ;
4648import java .util .List ;
4749import java .util .Map ;
4850
4951import static java .util .Collections .emptyMap ;
52+ import static org .elasticsearch .index .mapper .LongScriptFieldTypeTests .createDocumentWithIgnoredSource ;
5053import static org .hamcrest .Matchers .containsInAnyOrder ;
5154import static org .hamcrest .Matchers .equalTo ;
55+ import static org .hamcrest .Matchers .instanceOf ;
56+ import static org .hamcrest .Matchers .nullValue ;
5257
5358public class DoubleScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTestCase {
5459
@@ -269,6 +274,69 @@ public void testBlockLoader() throws IOException {
269274 }
270275 }
271276
277+ public void testBlockLoaderSourceOnlyRuntimeField () throws IOException {
278+ try (
279+ Directory directory = newDirectory ();
280+ RandomIndexWriter iw = new RandomIndexWriter (random (), directory , newIndexWriterConfig ().setMergePolicy (NoMergePolicy .INSTANCE ))
281+ ) {
282+ iw .addDocuments (
283+ List .of (
284+ List .of (new StoredField ("_source" , new BytesRef ("{\" test\" : [1.1]}" ))),
285+ List .of (new StoredField ("_source" , new BytesRef ("{\" test\" : [2.1]}" )))
286+ )
287+ );
288+ try (DirectoryReader reader = iw .getReader ()) {
289+ DoubleScriptFieldType fieldType = simpleSourceOnlyMappedFieldType ();
290+
291+ // Assert implementations:
292+ BlockLoader loader = fieldType .blockLoader (blContext (Settings .EMPTY , true ));
293+ assertThat (loader , instanceOf (DoubleScriptBlockDocValuesReader .DoubleScriptBlockLoader .class ));
294+ // ignored source doesn't support column at a time loading:
295+ var columnAtATimeLoader = loader .columnAtATimeReader (reader .leaves ().getFirst ());
296+ assertThat (columnAtATimeLoader , instanceOf (DoubleScriptBlockDocValuesReader .class ));
297+ var rowStrideReader = loader .rowStrideReader (reader .leaves ().getFirst ());
298+ assertThat (rowStrideReader , instanceOf (DoubleScriptBlockDocValuesReader .class ));
299+
300+ // Assert values:
301+ assertThat (blockLoaderReadValuesFromColumnAtATimeReader (reader , fieldType , 0 ), equalTo (List .of (1.1 , 2.1 )));
302+ assertThat (blockLoaderReadValuesFromColumnAtATimeReader (reader , fieldType , 1 ), equalTo (List .of (2.1 )));
303+ assertThat (blockLoaderReadValuesFromRowStrideReader (reader , fieldType ), equalTo (List .of (1.1 , 2.1 )));
304+ }
305+ }
306+ }
307+
308+ public void testBlockLoaderSourceOnlyRuntimeFieldWithSyntheticSource () throws IOException {
309+ var settings = Settings .builder ().put ("index.mapping.source.mode" , "synthetic" ).build ();
310+ try (
311+ Directory directory = newDirectory ();
312+ RandomIndexWriter iw = new RandomIndexWriter (random (), directory , newIndexWriterConfig ().setMergePolicy (NoMergePolicy .INSTANCE ))
313+ ) {
314+
315+ var document1 = createDocumentWithIgnoredSource ("[1.1]" );
316+ var document2 = createDocumentWithIgnoredSource ("[2.1]" );
317+
318+ iw .addDocuments (List .of (document1 , document2 ));
319+ try (DirectoryReader reader = iw .getReader ()) {
320+ DoubleScriptFieldType fieldType = simpleSourceOnlyMappedFieldType ();
321+
322+ // Assert implementations:
323+ BlockLoader loader = fieldType .blockLoader (blContext (settings , true ));
324+ assertThat (loader , instanceOf (FallbackSyntheticSourceBlockLoader .class ));
325+ // ignored source doesn't support column at a time loading:
326+ var columnAtATimeLoader = loader .columnAtATimeReader (reader .leaves ().getFirst ());
327+ assertThat (columnAtATimeLoader , nullValue ());
328+ var rowStrideReader = loader .rowStrideReader (reader .leaves ().getFirst ());
329+ assertThat (
330+ rowStrideReader .getClass ().getName (),
331+ equalTo ("org.elasticsearch.index.mapper.FallbackSyntheticSourceBlockLoader$IgnoredSourceRowStrideReader" )
332+ );
333+
334+ // Assert values:
335+ assertThat (blockLoaderReadValuesFromRowStrideReader (settings , reader , fieldType , true ), equalTo (List .of (1.1 , 2.1 )));
336+ }
337+ }
338+ }
339+
272340 @ Override
273341 protected Query randomTermsQuery (MappedFieldType ft , SearchExecutionContext ctx ) {
274342 return ft .termsQuery (List .of (randomLong ()), ctx );
@@ -279,6 +347,10 @@ protected DoubleScriptFieldType simpleMappedFieldType() {
279347 return build ("read_foo" , Map .of (), OnScriptError .FAIL );
280348 }
281349
350+ private DoubleScriptFieldType simpleSourceOnlyMappedFieldType () {
351+ return build ("read_test" , Map .of (), OnScriptError .FAIL );
352+ }
353+
282354 @ Override
283355 protected MappedFieldType loopFieldType () {
284356 return build ("loop" , Map .of (), OnScriptError .FAIL );
@@ -296,6 +368,31 @@ protected DoubleScriptFieldType build(String code, Map<String, Object> params, O
296368
297369 private static DoubleFieldScript .Factory factory (Script script ) {
298370 return switch (script .getIdOrCode ()) {
371+ case "read_test" -> new DoubleFieldScript .Factory () {
372+ @ Override
373+ public DoubleFieldScript .LeafFactory newFactory (
374+ String fieldName ,
375+ Map <String , Object > params ,
376+ SearchLookup lookup ,
377+ OnScriptError onScriptError
378+ ) {
379+ return (ctx ) -> new DoubleFieldScript (fieldName , params , lookup , onScriptError , ctx ) {
380+ @ Override
381+ @ SuppressWarnings ("unchecked" )
382+ public void execute () {
383+ Map <String , Object > source = (Map <String , Object >) this .getParams ().get ("_source" );
384+ for (Object foo : (List <?>) source .get ("test" )) {
385+ emit (((Number ) foo ).doubleValue ());
386+ }
387+ };
388+ };
389+ }
390+
391+ @ Override
392+ public boolean isParsedFromSource () {
393+ return true ;
394+ }
395+ };
299396 case "read_foo" -> (fieldName , params , lookup , onScriptError ) -> (ctx ) -> new DoubleFieldScript (
300397 fieldName ,
301398 params ,
0 commit comments