Runtime fields to optionally ignore script errors (#92380)

Currently Elasticsearch always returns a shard failure once a runtime error arises from using a runtime field, the exception being script-less runtime fields. This also means that execution of the query for that shard stops, which is okay for development and exploration. In a production scenario, however, it is often desirable to ignore runtime errors and continue with the query execution.

This change adds a new a new on_script_error parameter to runtime field definitions similar to the already existing
parameter for index-time scripted fields. When `on_script_error` is set to `continue`, errors from script execution are effectively ignored. This means affected documents don't show up in query results, but also don't prevent other matches from the same shard. Runtime fields accessed through the fields API don't return values on errors, aggregations will ignore documents that throw errors.

Note that this change affects scripted runtime fields only, while leaving default behaviour untouched. Also, ignored errors are not reported back to users for now.

Relates to #72143
This commit is contained in:
Christoph Büscher 2022-12-23 09:29:12 +01:00 committed by GitHub
parent 3bbf202843
commit 8067f01d48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
78 changed files with 2184 additions and 303 deletions

View file

@ -0,0 +1,5 @@
pr: 92380
summary: Add option to allow script errors on runtime fields
area: Search
type: enhancement
issues: []

View file

@ -227,6 +227,16 @@ with `params._source` (such as `params._source.day_of_week`). For simplicity,
defining a runtime field in the mapping definition without a script is the defining a runtime field in the mapping definition without a script is the
recommended option, whenever possible. recommended option, whenever possible.
[[runtime-errorhandling]]
==== Ignoring script errors on runtime fields
Scripts can throw errors at runtime, e.g. on accessing missing or invalid values
in documents or because of performing invalid operations. The `on_script_error`
parameter can be used to control error behaviour when this happens. Setting this
parameter to `continue` will have the effect of silently ignoring all errors on
this runtime field. The default `fail` value will cause a shard failure which
gets reported in the search response.
[[runtime-updating-scripts]] [[runtime-updating-scripts]]
==== Updating and removing runtime fields ==== Updating and removing runtime fields

View file

@ -49,6 +49,7 @@ import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexService; import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.mapper.DateFieldMapper; import org.elasticsearch.index.mapper.DateFieldMapper;
import org.elasticsearch.index.mapper.DocumentMapper; import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.index.mapper.ParsedDocument; import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.SourceToParse; import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.query.AbstractQueryBuilder; import org.elasticsearch.index.query.AbstractQueryBuilder;
@ -557,7 +558,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
BooleanFieldScript.LeafFactory leafFactory = factory.newFactory( BooleanFieldScript.LeafFactory leafFactory = factory.newFactory(
BooleanFieldScript.CONTEXT.name, BooleanFieldScript.CONTEXT.name,
request.getScript().getParams(), request.getScript().getParams(),
context.lookup() context.lookup(),
OnScriptError.FAIL
); );
BooleanFieldScript booleanFieldScript = leafFactory.newInstance(leafReaderContext); BooleanFieldScript booleanFieldScript = leafFactory.newInstance(leafReaderContext);
List<Boolean> booleans = new ArrayList<>(); List<Boolean> booleans = new ArrayList<>();
@ -571,7 +573,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
DateFieldScript.CONTEXT.name, DateFieldScript.CONTEXT.name,
request.getScript().getParams(), request.getScript().getParams(),
context.lookup(), context.lookup(),
DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER,
OnScriptError.FAIL
); );
DateFieldScript dateFieldScript = leafFactory.newInstance(leafReaderContext); DateFieldScript dateFieldScript = leafFactory.newInstance(leafReaderContext);
List<String> dates = new ArrayList<>(); List<String> dates = new ArrayList<>();
@ -584,7 +587,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
DoubleFieldScript.LeafFactory leafFactory = factory.newFactory( DoubleFieldScript.LeafFactory leafFactory = factory.newFactory(
DoubleFieldScript.CONTEXT.name, DoubleFieldScript.CONTEXT.name,
request.getScript().getParams(), request.getScript().getParams(),
context.lookup() context.lookup(),
OnScriptError.FAIL
); );
DoubleFieldScript doubleFieldScript = leafFactory.newInstance(leafReaderContext); DoubleFieldScript doubleFieldScript = leafFactory.newInstance(leafReaderContext);
List<Double> doubles = new ArrayList<>(); List<Double> doubles = new ArrayList<>();
@ -597,7 +601,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
GeoPointFieldScript.LeafFactory leafFactory = factory.newFactory( GeoPointFieldScript.LeafFactory leafFactory = factory.newFactory(
GeoPointFieldScript.CONTEXT.name, GeoPointFieldScript.CONTEXT.name,
request.getScript().getParams(), request.getScript().getParams(),
context.lookup() context.lookup(),
OnScriptError.FAIL
); );
GeoPointFieldScript geoPointFieldScript = leafFactory.newInstance(leafReaderContext); GeoPointFieldScript geoPointFieldScript = leafFactory.newInstance(leafReaderContext);
List<GeoPoint> points = new ArrayList<>(); List<GeoPoint> points = new ArrayList<>();
@ -615,7 +620,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
IpFieldScript.LeafFactory leafFactory = factory.newFactory( IpFieldScript.LeafFactory leafFactory = factory.newFactory(
IpFieldScript.CONTEXT.name, IpFieldScript.CONTEXT.name,
request.getScript().getParams(), request.getScript().getParams(),
context.lookup() context.lookup(),
OnScriptError.FAIL
); );
IpFieldScript ipFieldScript = leafFactory.newInstance(leafReaderContext); IpFieldScript ipFieldScript = leafFactory.newInstance(leafReaderContext);
List<String> ips = new ArrayList<>(); List<String> ips = new ArrayList<>();
@ -634,7 +640,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
LongFieldScript.LeafFactory leafFactory = factory.newFactory( LongFieldScript.LeafFactory leafFactory = factory.newFactory(
LongFieldScript.CONTEXT.name, LongFieldScript.CONTEXT.name,
request.getScript().getParams(), request.getScript().getParams(),
context.lookup() context.lookup(),
OnScriptError.FAIL
); );
LongFieldScript longFieldScript = leafFactory.newInstance(leafReaderContext); LongFieldScript longFieldScript = leafFactory.newInstance(leafReaderContext);
List<Long> longs = new ArrayList<>(); List<Long> longs = new ArrayList<>();
@ -647,7 +654,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
StringFieldScript.LeafFactory leafFactory = factory.newFactory( StringFieldScript.LeafFactory leafFactory = factory.newFactory(
StringFieldScript.CONTEXT.name, StringFieldScript.CONTEXT.name,
request.getScript().getParams(), request.getScript().getParams(),
context.lookup() context.lookup(),
OnScriptError.FAIL
); );
StringFieldScript stringFieldScript = leafFactory.newInstance(leafReaderContext); StringFieldScript stringFieldScript = leafFactory.newInstance(leafReaderContext);
List<String> keywords = new ArrayList<>(); List<String> keywords = new ArrayList<>();
@ -660,7 +668,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
CompositeFieldScript.LeafFactory leafFactory = factory.newFactory( CompositeFieldScript.LeafFactory leafFactory = factory.newFactory(
CompositeFieldScript.CONTEXT.name, CompositeFieldScript.CONTEXT.name,
request.getScript().getParams(), request.getScript().getParams(),
context.lookup() context.lookup(),
OnScriptError.FAIL
); );
CompositeFieldScript compositeFieldScript = leafFactory.newInstance(leafReaderContext); CompositeFieldScript compositeFieldScript = leafFactory.newInstance(leafReaderContext);
compositeFieldScript.runForDoc(0); compositeFieldScript.runForDoc(0);

View file

@ -0,0 +1,124 @@
---
setup:
- do:
indices.create:
index: test
body:
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
runtime:
rtf:
type: composite
on_script_error: continue
script:
source: |
if (doc["message"].value.equals("fail")) throw new Exception("error");
emit('msg', doc['message'].value);
fields:
msg:
type: keyword
rtf_strict:
type: composite
on_script_error: fail
script:
source: |
if (doc["message"].value.equals("fail")) throw new Exception("error");
emit('msg', doc['message'].value);
fields:
msg:
type: keyword
properties:
timestamp:
type: date
message:
type: keyword
- do:
bulk:
index: test
refresh: true
body: |
{"index":{}}
{"timestamp": "1998-04-30T14:30:17-05:00", "message" : "this is okay"}
{"index":{}}
{"timestamp": "1998-04-30T14:30:53-05:00", "message" : "fail"}
---
"query with continue on error":
- do:
search:
index: test
body:
query:
term:
rtf.msg: "this is okay"
- match: { hits.total.value: 1 }
- match: { hits.hits.0._source.message: "this is okay"}
---
"query with fail on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: test
body:
query:
term:
rtf_strict.msg: "this is okay"
---
"query with search time field":
- do:
search:
index: test
body:
query:
term:
rtf_search.msg: "this is okay"
runtime_mappings:
rtf_search:
type: composite
on_script_error: continue
script:
source: |
if (doc["message"].value.equals("fail")) throw new Exception("error");
emit('msg', doc['message'].value);
fields:
msg:
type: keyword
- match: { hits.total.value: 1 }
- match: { hits.hits.0._source.message: "this is okay"}
---
fetch:
- do:
search:
index: test
body:
sort: timestamp
fields:
- message
- rtf.msg
- match: {hits.total.value: 2}
- match: {hits.hits.0.fields.message: ["this is okay"] }
- match: {hits.hits.0.fields.rtf\.msg: ["this is okay"] }
- match: {hits.hits.1.fields.message: ["fail"] }
- is_false: hits.hits.1.fields.rtf.msg
---
"terms agg":
- do:
search:
index: test
body:
aggs:
messages:
terms:
field: rtf.msg
- match: { hits.total.value: 2}
- length: { aggregations.messages.buckets: 1 }
- match: { aggregations.messages.buckets.0.key: "this is okay" }
- match: { aggregations.messages.buckets.0.doc_count: 1 }

View file

@ -0,0 +1,216 @@
---
setup:
- do:
indices.create:
index: testindex
body:
settings:
number_of_shards: 1
mappings:
runtime:
first_char:
type: keyword
script: |
emit(doc['name'].value.substring(0,1));
on_script_error: continue
first_char_strict_error:
type: keyword
script: |
emit(doc['name'].value.substring(0,1));
on_script_error: fail
properties:
name:
type: keyword
- do:
bulk:
index: testindex
refresh: true
body: |
{"index":{}}
{"name": "foo"}
{"index":{}}
{"name": ""}
---
"Query rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
match:
first_char: "f"
fields: [ name, first_char ]
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.first_char: [ f ] }
---
"Query rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
first_char_strict_error: "f"
fields: [ name, first_char_strict_error ]
---
"Aggregate on rtf with on_script_error continue":
- do:
search:
index: testindex
body:
aggs:
firstchar:
terms:
field: first_char
- length: { aggregations.firstchar.buckets: 1 }
- match: { aggregations.firstchar.buckets.0.key: "f" }
---
"Aggregate on rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
aggs:
firstchar:
terms:
field: first_char_strict_error
---
"Fields retrieval with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name, first_char ]
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.first_char: [ f ] }
- match: { hits.hits.1.fields.name: [ "" ] }
- is_false: hits.hits.1.fields.first_char
---
"Fields retrieval with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name, first_char_strict_error ]
---
"Sorting with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name ]
sort: first_char
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.1.fields.name: [ "" ] }
---
"Sorting with with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name ]
sort: first_char_strict_error
---
"Query search time rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
match:
first_char_search: "f"
fields: [ name, first_char_search ]
runtime_mappings:
first_char_search:
type: keyword
script: |
emit(doc['name'].value.substring(0,1));
on_script_error: continue
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.first_char_search: [ f ] }
---
"Query search time rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
first_char_search: "f"
fields: [ name, first_char_search ]
runtime_mappings:
first_char_search:
type: keyword
script: |
emit(doc['name'].value.substring(0,1));
on_script_error: fail
---
"Change error behaviour for lenient runtime field":
- do:
indices.put_mapping:
index: testindex
body:
runtime:
first_char_variant:
type: keyword
script: |
emit(doc['name'].value.substring(0,1));
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
first_char_variant: "f"
- do:
indices.put_mapping:
index: testindex
body:
runtime:
first_char_variant:
type: keyword
script: |
emit(doc['name'].value.substring(0,1));
on_script_error: continue
- do:
search:
index: testindex
body:
query:
match:
first_char_variant: "f"
fields: [ name, first_char_variant ]
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.first_char_variant: [ f ] }

View file

@ -0,0 +1,176 @@
---
setup:
- do:
indices.create:
index: testindex
body:
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
runtime:
rtf:
type: long
script: |
if(doc['name'].value.equals("")) throw new Exception("empty");
emit(doc['name'].value.length());
on_script_error: continue
rtf_strict_error:
type: long
script: |
if(doc['name'].value.equals("")) throw new Exception("empty");
emit(doc['name'].value.length());
on_script_error: fail
properties:
name:
type: keyword
- do:
bulk:
index: testindex
refresh: true
body: |
{"index":{}}
{"name": "foo"}
{"index":{}}
{"name": ""}
---
"Query rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
match:
rtf: 3
fields: [ name, rtf ]
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.rtf: [ 3 ] }
---
"Query rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
rtf_strict_error: 3
fields: [ name, rtf_strict_error ]
---
"Aggregate on rtf with on_script_error continue":
- do:
search:
index: testindex
body:
aggs:
firstchar:
terms:
field: rtf
- length: { aggregations.firstchar.buckets: 1 }
- match: { aggregations.firstchar.buckets.0.key: 3 }
---
"Aggregate on rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
aggs:
firstchar:
terms:
field: rtf_strict_error
---
"Fields retrieval with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name, rtf ]
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.rtf: [ 3 ] }
- match: { hits.hits.1.fields.name: [ "" ] }
- is_false: hits.hits.1.fields.rtf
---
"Fields retrieval with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name, rtf_strict_error ]
---
"Sorting with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name ]
sort: rtf
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.1.fields.name: [ "" ] }
---
"Sorting with with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name ]
sort: rtf_strict_error
---
"Query search time rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
match:
rtf_search: 3
fields: [ name, rtf_search ]
runtime_mappings:
rtf_search:
type: long
script: |
if(doc['name'].value.equals("")) throw new Exception("empty");
emit(doc['name'].value.length());
on_script_error: continue
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.rtf_search: [ 3 ] }
---
"Query search time rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
rtf_search: 3
fields: [ name, rtf_search ]
runtime_mappings:
rtf_search:
type: long
script: |
if(doc['name'].value.equals("")) throw new Exception("empty");
emit(doc['name'].value.length());
on_script_error: fail

View file

@ -0,0 +1,176 @@
---
setup:
- do:
indices.create:
index: testindex
body:
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
runtime:
rtf:
type: double
script: |
if(doc['name'].value.equals("")) throw new Exception("empty");
emit(doc['name'].value.length());
on_script_error: continue
rtf_strict_error:
type: double
script: |
if(doc['name'].value.equals("")) throw new Exception("empty");
emit(doc['name'].value.length());
on_script_error: fail
properties:
name:
type: keyword
- do:
bulk:
index: testindex
refresh: true
body: |
{"index":{}}
{"name": "foo"}
{"index":{}}
{"name": ""}
---
"Query rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
match:
rtf: 3
fields: [ name, rtf ]
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.rtf: [ 3.0 ] }
---
"Query rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
rtf_strict_error: 3
fields: [ name, rtf_strict_error ]
---
"Aggregate on rtf with on_script_error continue":
- do:
search:
index: testindex
body:
aggs:
firstchar:
terms:
field: rtf
- length: { aggregations.firstchar.buckets: 1 }
- match: { aggregations.firstchar.buckets.0.key: 3.0 }
---
"Aggregate on rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
aggs:
firstchar:
terms:
field: rtf_strict_error
---
"Fields retrieval with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name, rtf ]
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.rtf: [ 3.0 ] }
- match: { hits.hits.1.fields.name: [ "" ] }
- is_false: hits.hits.1.fields.rtf
---
"Fields retrieval with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name, rtf_strict_error ]
---
"Sorting with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name ]
sort: rtf
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.1.fields.name: [ "" ] }
---
"Sorting with with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ name ]
sort: rtf_strict_error
---
"Query search time rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
match:
rtf_search: 3
fields: [ name, rtf_search ]
runtime_mappings:
rtf_search:
type: double
script: |
if(doc['name'].value.equals("")) throw new Exception("empty");
emit(doc['name'].value.length());
on_script_error: continue
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.name: [ foo ] }
- match: { hits.hits.0.fields.rtf_search: [ 3.0 ] }
---
"Query search time rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
rtf_search: 3
fields: [ name, rtf_search ]
runtime_mappings:
rtf_search:
type: double
script: |
if(doc['name'].value.equals("")) throw new Exception("empty");
emit(doc['name'].value.length());
on_script_error: fail

View file

@ -0,0 +1,184 @@
---
setup:
- do:
indices.create:
index: testindex
body:
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
runtime:
rtf:
type: date
format: yyyy-MM-dd
script: |
if(doc['millis_since_epoch'].value < 0) throw new Exception("date before 1970");
emit(doc['millis_since_epoch'].value);
on_script_error: continue
rtf_strict_error:
type: date
format: yyyy-MM-dd
script: |
if(doc['millis_since_epoch'].value < 0) throw new Exception("date before 1970");
emit(doc['millis_since_epoch'].value);
on_script_error: fail
properties:
millis_since_epoch:
type: long
- do:
bulk:
index: testindex
refresh: true
body: |
{"index":{}}
{"millis_since_epoch": 1671033474411}
{"index":{}}
{"millis_since_epoch": -1}
---
"Query rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
range:
rtf:
gte: "2022-12-14"
fields: [ millis_since_epoch, rtf ]
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.millis_since_epoch: [ 1671033474411 ] }
- match: { hits.hits.0.fields.rtf: [ "2022-12-14" ] }
---
"Query rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
range:
rtf_strict_error:
gte: "2022-12-14"
fields: [ millis_since_epoch, rtf_strict_error ]
---
"Aggregate on rtf with on_script_error continue":
- do:
search:
index: testindex
body:
aggs:
firstchar:
terms:
field: rtf
- length: { aggregations.firstchar.buckets: 1 }
- match: { aggregations.firstchar.buckets.0.key_as_string: "2022-12-14" }
---
"Aggregate on rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
aggs:
firstchar:
terms:
field: rtf_strict_error
---
"Fields retrieval with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ millis_since_epoch, rtf ]
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.millis_since_epoch: [ 1671033474411 ] }
- match: { hits.hits.0.fields.rtf: [ "2022-12-14" ] }
- match: { hits.hits.1.fields.millis_since_epoch: [ -1 ] }
- is_false: hits.hits.1.fields.rtf
---
"Fields retrieval with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ millis_since_epoch, rtf_strict_error ]
---
"Sorting with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ millis_since_epoch ]
sort: rtf
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.millis_since_epoch: [ 1671033474411 ] }
- match: { hits.hits.1.fields.millis_since_epoch: [ -1 ] }
---
"Sorting with with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ millis_since_epoch ]
sort: rtf_strict_error
---
"Query search time rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
range:
rtf_search:
gte: "2022-12-14"
fields: [ millis_since_epoch, rtf_search ]
runtime_mappings:
rtf_search:
type: date
format: yyyy-MM-dd
script: |
if(doc['millis_since_epoch'].value < 0) throw new Exception("date before 1970");
emit(doc['millis_since_epoch'].value);
on_script_error: continue
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.millis_since_epoch: [ 1671033474411 ] }
- match: { hits.hits.0.fields.rtf_search: [ "2022-12-14" ] }
---
"Query search time rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
range:
rtf_search:
gte: "2022-12-14"
fields: [ millis_since_epoch, rtf_search ]
runtime_mappings:
rtf_search:
type: date
format: yyyy-MM-dd
script: |
if(doc['millis_since_epoch'].value < 0) throw new Exception("date before 1970");
emit(doc['millis_since_epoch'].value);
on_script_error: fail

View file

@ -0,0 +1,177 @@
---
setup:
- do:
indices.create:
index: testindex
body:
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
runtime:
rtf:
type: ip
script: |
if(doc['ip_string'].value.length() <= 0) throw new Exception("empty");
emit(doc['ip_string'].value);
on_script_error: continue
rtf_strict_error:
type: ip
script: |
if(doc['ip_string'].value.length() <= 0) throw new Exception("empty");
emit(doc['ip_string'].value);
on_script_error: fail
properties:
ip_string:
type: keyword
- do:
bulk:
index: testindex
refresh: true
body: |
{"index":{}}
{"ip_string": "192.68.0.1"}
{"index":{}}
{"ip_string": ""}
---
"Query rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
term:
rtf:
192.68.0.1
fields: [ ip_string, rtf ]
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.ip_string: [ "192.68.0.1" ] }
- match: { hits.hits.0.fields.rtf: [ 192.68.0.1 ] }
---
"Query rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
term:
rtf_strict_error: 192.68.0.1
fields: [ ip_string, rtf_strict_error ]
---
"Aggregate on rtf with on_script_error continue":
- do:
search:
index: testindex
body:
aggs:
rtf:
terms:
field: rtf
- length: { aggregations.rtf.buckets: 1 }
- match: { aggregations.rtf.buckets.0.key: 192.68.0.1 }
---
"Aggregate on rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
aggs:
rtf:
terms:
field: rtf_strict_error
---
"Fields retrieval with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ ip_string, rtf ]
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.ip_string: [ "192.68.0.1" ] }
- match: { hits.hits.0.fields.rtf: [ "192.68.0.1" ] }
- match: { hits.hits.1.fields.ip_string: [ "" ] }
- is_false: hits.hits.1.fields.rtf
---
"Fields retrieval with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ ip_string, rtf_strict_error ]
---
"Sorting with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ ip_string ]
sort: rtf
- match: { hits.total.value: 2 }
- match: { hits.hits.0.fields.ip_string: [ "192.68.0.1" ] }
- match: { hits.hits.1.fields.ip_string: [ "" ] }
---
"Sorting with with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ ip_string ]
sort: rtf_strict_error
---
"Query search time rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
match:
rtf_search: "192.68.0.1"
fields: [ ip_string, rtf_search ]
runtime_mappings:
rtf_search:
type: ip
script: |
if(doc['ip_string'].value.length() <= 0) throw new Exception("empty");
emit(doc['ip_string'].value);
on_script_error: continue
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.ip_string: [ "192.68.0.1" ] }
- match: { hits.hits.0.fields.rtf_search: [ "192.68.0.1" ] }
---
"Query search time rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
rtf_search: "192.68.0.1"
fields: [ ip_string, rtf_search ]
runtime_mappings:
rtf_search:
type: ip
script: |
if(doc['ip_string'].value.length() <= 0) throw new Exception("empty");
emit(doc['ip_string'].value);
on_script_error: fail

View file

@ -0,0 +1,184 @@
---
setup:
- do:
indices.create:
index: testindex
body:
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
runtime:
rtf:
type: boolean
script: |
if(doc['age'].value < 0) throw new Exception("invalid age");
emit(doc['age'].value >= 18);
on_script_error: continue
rtf_strict_error:
type: boolean
script: |
if(doc['age'].value <= 0) throw new Exception("invalid age");
emit(doc['age'].value >=18);
on_script_error: fail
properties:
age:
type: integer
- do:
bulk:
index: testindex
refresh: true
body: |
{"index":{}}
{"age": 14}
{"index":{}}
{"age": 20}
{"index":{}}
{"age": -1}
---
"Query rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
match:
rtf:
true
fields: [ age, rtf ]
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.age: [ 20 ] }
- match: { hits.hits.0.fields.rtf: [ true ] }
---
"Query rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
rtf_strict_error: true
fields: [ age, rtf_strict_error ]
---
"Aggregate on rtf with on_script_error continue":
- do:
search:
index: testindex
body:
aggs:
rtf:
terms:
field: rtf
order: { "_key": "asc" }
- length: { aggregations.rtf.buckets: 2 }
- match: { aggregations.rtf.buckets.0.key_as_string: "false" }
- match: { aggregations.rtf.buckets.1.key_as_string: "true" }
---
"Aggregate on rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
aggs:
rtf:
terms:
field: rtf_strict_error
---
"Fields retrieval with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ age, rtf ]
sort: { "age": "desc" }
- match: { hits.total.value: 3 }
- match: { hits.hits.0.fields.age: [ 20 ] }
- match: { hits.hits.0.fields.rtf: [ true ] }
- match: { hits.hits.1.fields.age: [ 14 ] }
- match: { hits.hits.1.fields.rtf: [ false ] }
- match: { hits.hits.2.fields.age: [ -1 ] }
- is_false: hits.hits.2.fields.rtf
---
"Fields retrieval with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ age, rtf_strict_error ]
---
"Sorting with ignoring error":
- do:
search:
index: testindex
body:
query: { match_all: { } }
fields: [ age ]
sort: rtf
- match: { hits.total.value: 3 }
- match: { hits.hits.0.fields.age: [ 14 ] }
- match: { hits.hits.1.fields.age: [ 20 ] }
- match: { hits.hits.2.fields.age: [ -1 ] }
---
"Sorting with with failing on error":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query: { match_all: { } }
fields: [ age ]
sort: rtf_strict_error
---
"Query search time rtf with on_script_error continue":
- do:
search:
index: testindex
body:
query:
match:
rtf_search: true
fields: [ age, rtf_search ]
runtime_mappings:
rtf_search:
type: boolean
script: |
if(doc['age'].value < 0) throw new Exception("invalid age");
emit(doc['age'].value >= 18);
on_script_error: continue
- match: { hits.total.value: 1 }
- match: { hits.hits.0.fields.age: [ 20 ] }
- match: { hits.hits.0.fields.rtf_search: [ true ] }
---
"Query search time rtf with on_script_error fail":
- do:
catch: /type=script_exception, reason=runtime error/
search:
index: testindex
body:
query:
match:
rtf_search: true
fields: [ age, rtf_search ]
runtime_mappings:
rtf_search:
type: boolean
script: |
if(doc['age'].value < 0) throw new Exception("invalid age");
emit(doc['age'].value >= 18);
on_script_error: fail

View file

@ -215,7 +215,7 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
abstract static class Builder<Factory> extends RuntimeField.Builder { abstract static class Builder<Factory> extends RuntimeField.Builder {
private final ScriptContext<Factory> scriptContext; private final ScriptContext<Factory> scriptContext;
final FieldMapper.Parameter<Script> script = new FieldMapper.Parameter<>( private final FieldMapper.Parameter<Script> script = new FieldMapper.Parameter<>(
"script", "script",
true, true,
() -> null, () -> null,
@ -225,6 +225,8 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
Objects::toString Objects::toString
).setSerializerCheck((id, ic, v) -> ic); ).setSerializerCheck((id, ic, v) -> ic);
private final FieldMapper.Parameter<String> onScriptError = FieldMapper.Parameter.onScriptErrorParam(m -> m.onScriptError, script);
Builder(String name, ScriptContext<Factory> scriptContext) { Builder(String name, ScriptContext<Factory> scriptContext) {
super(name); super(name);
this.scriptContext = scriptContext; this.scriptContext = scriptContext;
@ -247,7 +249,8 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
protected final RuntimeField createChildRuntimeField( protected final RuntimeField createChildRuntimeField(
MappingParserContext parserContext, MappingParserContext parserContext,
String parent, String parent,
Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory,
OnScriptError onScriptError
) { ) {
if (script.isConfigured()) { if (script.isConfigured()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
@ -257,7 +260,7 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
String fullName = parent + "." + name; String fullName = parent + "." + name;
return new LeafRuntimeField( return new LeafRuntimeField(
name, name,
createFieldType(fullName, getCompositeLeafFactory(parentScriptFactory), getScript(), meta()), createFieldType(fullName, getCompositeLeafFactory(parentScriptFactory), getScript(), meta(), onScriptError),
getParameters() getParameters()
); );
} }
@ -267,26 +270,41 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
} }
final RuntimeField createRuntimeField(Factory scriptFactory, Version indexVersion) { final RuntimeField createRuntimeField(Factory scriptFactory, Version indexVersion) {
var fieldType = createFieldType(name, scriptFactory, getScript(), meta(), indexVersion); var fieldType = createFieldType(
name,
scriptFactory,
getScript(),
meta(),
indexVersion,
OnScriptError.fromString(onScriptError.get())
);
return new LeafRuntimeField(name, fieldType, getParameters()); return new LeafRuntimeField(name, fieldType, getParameters());
} }
abstract AbstractScriptFieldType<?> createFieldType(String name, Factory factory, Script script, Map<String, String> meta); abstract AbstractScriptFieldType<?> createFieldType(
String name,
Factory factory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
);
AbstractScriptFieldType<?> createFieldType( AbstractScriptFieldType<?> createFieldType(
String name, String name,
Factory factory, Factory factory,
Script script, Script script,
Map<String, String> meta, Map<String, String> meta,
Version supportedVersion Version supportedVersion,
OnScriptError onScriptError
) { ) {
return createFieldType(name, factory, script, meta); return createFieldType(name, factory, script, meta, onScriptError);
} }
@Override @Override
protected List<FieldMapper.Parameter<?>> getParameters() { protected List<FieldMapper.Parameter<?>> getParameters() {
List<FieldMapper.Parameter<?>> parameters = new ArrayList<>(super.getParameters()); List<FieldMapper.Parameter<?>> parameters = new ArrayList<>(super.getParameters());
parameters.add(script); parameters.add(script);
parameters.add(onScriptError);
return Collections.unmodifiableList(parameters); return Collections.unmodifiableList(parameters);
} }
@ -296,5 +314,6 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
} }
return script.get(); return script.get();
} }
} }
} }

View file

@ -139,7 +139,7 @@ public class BooleanFieldMapper extends FieldMapper {
BooleanFieldScript.Factory scriptFactory = scriptCompiler.compile(script.get(), BooleanFieldScript.CONTEXT); BooleanFieldScript.Factory scriptFactory = scriptCompiler.compile(script.get(), BooleanFieldScript.CONTEXT);
return scriptFactory == null return scriptFactory == null
? null ? null
: (lookup, ctx, doc, consumer) -> scriptFactory.newFactory(name, script.get().getParams(), lookup) : (lookup, ctx, doc, consumer) -> scriptFactory.newFactory(name, script.get().getParams(), lookup, OnScriptError.FAIL)
.newInstance(ctx) .newInstance(ctx)
.runForDoc(doc, consumer); .runForDoc(doc, consumer);
} }

View file

@ -46,9 +46,10 @@ public final class BooleanScriptFieldType extends AbstractScriptFieldType<Boolea
String name, String name,
BooleanFieldScript.Factory factory, BooleanFieldScript.Factory factory,
Script script, Script script,
Map<String, String> meta Map<String, String> meta,
OnScriptError onScriptError
) { ) {
return new BooleanScriptFieldType(name, factory, script, meta); return new BooleanScriptFieldType(name, factory, script, meta, onScriptError);
} }
@Override @Override
@ -67,10 +68,16 @@ public final class BooleanScriptFieldType extends AbstractScriptFieldType<Boolea
return new Builder(name).createRuntimeField(BooleanFieldScript.PARSE_FROM_SOURCE); return new Builder(name).createRuntimeField(BooleanFieldScript.PARSE_FROM_SOURCE);
} }
BooleanScriptFieldType(String name, BooleanFieldScript.Factory scriptFactory, Script script, Map<String, String> meta) { BooleanScriptFieldType(
String name,
BooleanFieldScript.Factory scriptFactory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
) {
super( super(
name, name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup), searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script, script,
scriptFactory.isResultDeterministic(), scriptFactory.isResultDeterministic(),
meta meta

View file

@ -47,6 +47,8 @@ public class CompositeRuntimeField implements RuntimeField {
} }
}); });
private final FieldMapper.Parameter<String> onScriptError = FieldMapper.Parameter.onScriptErrorParam(m -> m.onScriptError, script);
private final FieldMapper.Parameter<Map<String, Object>> fields = new FieldMapper.Parameter<Map<String, Object>>( private final FieldMapper.Parameter<Map<String, Object>> fields = new FieldMapper.Parameter<Map<String, Object>>(
"fields", "fields",
false, false,
@ -66,6 +68,7 @@ public class CompositeRuntimeField implements RuntimeField {
List<FieldMapper.Parameter<?>> parameters = new ArrayList<>(super.getParameters()); List<FieldMapper.Parameter<?>> parameters = new ArrayList<>(super.getParameters());
parameters.add(script); parameters.add(script);
parameters.add(fields); parameters.add(fields);
parameters.add(onScriptError);
return Collections.unmodifiableList(parameters); return Collections.unmodifiableList(parameters);
} }
@ -73,7 +76,8 @@ public class CompositeRuntimeField implements RuntimeField {
protected RuntimeField createChildRuntimeField( protected RuntimeField createChildRuntimeField(
MappingParserContext parserContext, MappingParserContext parserContext,
String parent, String parent,
Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory,
OnScriptError onScriptError
) { ) {
throw new IllegalArgumentException("Composite field [" + name + "] cannot be a child of composite field [" + parent + "]"); throw new IllegalArgumentException("Composite field [" + name + "] cannot be a child of composite field [" + parent + "]");
} }
@ -81,11 +85,15 @@ public class CompositeRuntimeField implements RuntimeField {
@Override @Override
protected RuntimeField createRuntimeField(MappingParserContext parserContext) { protected RuntimeField createRuntimeField(MappingParserContext parserContext) {
CompositeFieldScript.Factory factory = parserContext.scriptCompiler().compile(script.get(), CompositeFieldScript.CONTEXT); CompositeFieldScript.Factory factory = parserContext.scriptCompiler().compile(script.get(), CompositeFieldScript.CONTEXT);
Function<RuntimeField.Builder, RuntimeField> builder = b -> b.createChildRuntimeField( Function<RuntimeField.Builder, RuntimeField> builder = b -> {
OnScriptError onScriptError = OnScriptError.fromString(this.onScriptError.get());
return b.createChildRuntimeField(
parserContext, parserContext,
name, name,
lookup -> factory.newFactory(name, script.get().getParams(), lookup) lookup -> factory.newFactory(name, script.get().getParams(), lookup, onScriptError),
onScriptError
); );
};
Map<String, RuntimeField> runtimeFields = RuntimeField.parseRuntimeFields( Map<String, RuntimeField> runtimeFields = RuntimeField.parseRuntimeFields(
new HashMap<>(fields.getValue()), new HashMap<>(fields.getValue()),
parserContext, parserContext,

View file

@ -303,9 +303,13 @@ public final class DateFieldMapper extends FieldMapper {
DateFieldScript.Factory factory = scriptCompiler.compile(script.get(), DateFieldScript.CONTEXT); DateFieldScript.Factory factory = scriptCompiler.compile(script.get(), DateFieldScript.CONTEXT);
return factory == null return factory == null
? null ? null
: (lookup, ctx, doc, consumer) -> factory.newFactory(name, script.get().getParams(), lookup, buildFormatter()) : (lookup, ctx, doc, consumer) -> factory.newFactory(
.newInstance(ctx) name,
.runForDoc(doc, consumer::accept); script.get().getParams(),
lookup,
buildFormatter(),
OnScriptError.FAIL
).newInstance(ctx).runForDoc(doc, consumer::accept);
} }
@Override @Override

View file

@ -87,23 +87,29 @@ public class DateScriptFieldType extends AbstractScriptFieldType<DateFieldScript
return Collections.unmodifiableList(parameters); return Collections.unmodifiableList(parameters);
} }
AbstractScriptFieldType<?> createFieldType(
String name,
DateFieldScript.Factory factory,
Script script,
Map<String, String> meta,
Version supportedVersion,
OnScriptError onScriptError
) {
String pattern = format.getValue() == null ? DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.pattern() : format.getValue();
Locale locale = this.locale.getValue() == null ? Locale.ROOT : this.locale.getValue();
DateFormatter dateTimeFormatter = DateFormatter.forPattern(pattern, supportedVersion).withLocale(locale);
return new DateScriptFieldType(name, factory, dateTimeFormatter, script, meta, onScriptError);
}
@Override @Override
AbstractScriptFieldType<?> createFieldType( AbstractScriptFieldType<?> createFieldType(
String name, String name,
DateFieldScript.Factory factory, DateFieldScript.Factory factory,
Script script, Script script,
Map<String, String> meta, Map<String, String> meta,
Version supportedVersion OnScriptError onScriptError
) { ) {
String pattern = format.getValue() == null ? DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.pattern() : format.getValue(); return createFieldType(name, factory, script, meta, Version.CURRENT, onScriptError);
Locale locale = this.locale.getValue() == null ? Locale.ROOT : this.locale.getValue();
DateFormatter dateTimeFormatter = DateFormatter.forPattern(pattern, supportedVersion).withLocale(locale);
return new DateScriptFieldType(name, factory, dateTimeFormatter, script, meta);
}
@Override
AbstractScriptFieldType<?> createFieldType(String name, DateFieldScript.Factory factory, Script script, Map<String, String> meta) {
return createFieldType(name, factory, script, meta, Version.CURRENT);
} }
@Override @Override
@ -131,11 +137,12 @@ public class DateScriptFieldType extends AbstractScriptFieldType<DateFieldScript
DateFieldScript.Factory scriptFactory, DateFieldScript.Factory scriptFactory,
DateFormatter dateTimeFormatter, DateFormatter dateTimeFormatter,
Script script, Script script,
Map<String, String> meta Map<String, String> meta,
OnScriptError onScriptError
) { ) {
super( super(
name, name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, dateTimeFormatter), searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, dateTimeFormatter, onScriptError),
script, script,
scriptFactory.isResultDeterministic(), scriptFactory.isResultDeterministic(),
meta meta

View file

@ -47,9 +47,10 @@ public final class DoubleScriptFieldType extends AbstractScriptFieldType<DoubleF
String name, String name,
DoubleFieldScript.Factory factory, DoubleFieldScript.Factory factory,
Script script, Script script,
Map<String, String> meta Map<String, String> meta,
OnScriptError onScriptError
) { ) {
return new DoubleScriptFieldType(name, factory, script, meta); return new DoubleScriptFieldType(name, factory, script, meta, onScriptError);
} }
@Override @Override
@ -67,10 +68,16 @@ public final class DoubleScriptFieldType extends AbstractScriptFieldType<DoubleF
return new Builder(name).createRuntimeField(DoubleFieldScript.PARSE_FROM_SOURCE); return new Builder(name).createRuntimeField(DoubleFieldScript.PARSE_FROM_SOURCE);
} }
DoubleScriptFieldType(String name, DoubleFieldScript.Factory scriptFactory, Script script, Map<String, String> meta) { DoubleScriptFieldType(
String name,
DoubleFieldScript.Factory scriptFactory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
) {
super( super(
name, name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup), searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script, script,
scriptFactory.isResultDeterministic(), scriptFactory.isResultDeterministic(),
meta meta

View file

@ -143,7 +143,7 @@ public class GeoPointFieldMapper extends AbstractPointGeometryFieldMapper<GeoPoi
GeoPointFieldScript.Factory factory = scriptCompiler.compile(this.script.get(), GeoPointFieldScript.CONTEXT); GeoPointFieldScript.Factory factory = scriptCompiler.compile(this.script.get(), GeoPointFieldScript.CONTEXT);
return factory == null return factory == null
? null ? null
: (lookup, ctx, doc, consumer) -> factory.newFactory(name, script.get().getParams(), lookup) : (lookup, ctx, doc, consumer) -> factory.newFactory(name, script.get().getParams(), lookup, OnScriptError.FAIL)
.newInstance(ctx) .newInstance(ctx)
.runForDoc(doc, consumer); .runForDoc(doc, consumer);
} }

View file

@ -50,9 +50,10 @@ public final class GeoPointScriptFieldType extends AbstractScriptFieldType<GeoPo
String name, String name,
GeoPointFieldScript.Factory factory, GeoPointFieldScript.Factory factory,
Script script, Script script,
Map<String, String> meta Map<String, String> meta,
OnScriptError onScriptError
) { ) {
return new GeoPointScriptFieldType(name, factory, getScript(), meta()); return new GeoPointScriptFieldType(name, factory, getScript(), meta(), onScriptError);
} }
@Override @Override
@ -66,10 +67,16 @@ public final class GeoPointScriptFieldType extends AbstractScriptFieldType<GeoPo
} }
}); });
GeoPointScriptFieldType(String name, GeoPointFieldScript.Factory scriptFactory, Script script, Map<String, String> meta) { GeoPointScriptFieldType(
String name,
GeoPointFieldScript.Factory scriptFactory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
) {
super( super(
name, name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup), searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script, script,
scriptFactory.isResultDeterministic(), scriptFactory.isResultDeterministic(),
meta meta
@ -154,7 +161,7 @@ public final class GeoPointScriptFieldType extends AbstractScriptFieldType<GeoPo
) { ) {
return ctx -> { return ctx -> {
GeoPointFieldScript script = delegateLeafFactory.apply(ctx); GeoPointFieldScript script = delegateLeafFactory.apply(ctx);
return new AbstractLongFieldScript(name, Map.of(), lookup, ctx) { return new AbstractLongFieldScript(name, Map.of(), lookup, OnScriptError.FAIL, ctx) {
private int docId; private int docId;
@Override @Override

View file

@ -145,7 +145,7 @@ public class IpFieldMapper extends FieldMapper {
IpFieldScript.Factory factory = scriptCompiler.compile(this.script.get(), IpFieldScript.CONTEXT); IpFieldScript.Factory factory = scriptCompiler.compile(this.script.get(), IpFieldScript.CONTEXT);
return factory == null return factory == null
? null ? null
: (lookup, ctx, doc, consumer) -> factory.newFactory(name, script.get().getParams(), lookup) : (lookup, ctx, doc, consumer) -> factory.newFactory(name, script.get().getParams(), lookup, OnScriptError.FAIL)
.newInstance(ctx) .newInstance(ctx)
.runForDoc(doc, consumer); .runForDoc(doc, consumer);
} }

View file

@ -45,8 +45,14 @@ public final class IpScriptFieldType extends AbstractScriptFieldType<IpFieldScri
public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(name -> new Builder<>(name, IpFieldScript.CONTEXT) { public static final RuntimeField.Parser PARSER = new RuntimeField.Parser(name -> new Builder<>(name, IpFieldScript.CONTEXT) {
@Override @Override
AbstractScriptFieldType<?> createFieldType(String name, IpFieldScript.Factory factory, Script script, Map<String, String> meta) { AbstractScriptFieldType<?> createFieldType(
return new IpScriptFieldType(name, factory, getScript(), meta()); String name,
IpFieldScript.Factory factory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
) {
return new IpScriptFieldType(name, factory, getScript(), meta(), onScriptError);
} }
@Override @Override
@ -60,10 +66,16 @@ public final class IpScriptFieldType extends AbstractScriptFieldType<IpFieldScri
} }
}); });
IpScriptFieldType(String name, IpFieldScript.Factory scriptFactory, Script script, Map<String, String> meta) { IpScriptFieldType(
String name,
IpFieldScript.Factory scriptFactory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
) {
super( super(
name, name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup), searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script, script,
scriptFactory.isResultDeterministic(), scriptFactory.isResultDeterministic(),
meta meta

View file

@ -245,7 +245,7 @@ public final class KeywordFieldMapper extends FieldMapper {
StringFieldScript.Factory scriptFactory = scriptCompiler.compile(script.get(), StringFieldScript.CONTEXT); StringFieldScript.Factory scriptFactory = scriptCompiler.compile(script.get(), StringFieldScript.CONTEXT);
return scriptFactory == null return scriptFactory == null
? null ? null
: (lookup, ctx, doc, consumer) -> scriptFactory.newFactory(name, script.get().getParams(), lookup) : (lookup, ctx, doc, consumer) -> scriptFactory.newFactory(name, script.get().getParams(), lookup, OnScriptError.FAIL)
.newInstance(ctx) .newInstance(ctx)
.runForDoc(doc, consumer); .runForDoc(doc, consumer);
} }

View file

@ -54,9 +54,10 @@ public final class KeywordScriptFieldType extends AbstractScriptFieldType<String
String name, String name,
StringFieldScript.Factory factory, StringFieldScript.Factory factory,
Script script, Script script,
Map<String, String> meta Map<String, String> meta,
OnScriptError onScriptError
) { ) {
return new KeywordScriptFieldType(name, factory, script, meta); return new KeywordScriptFieldType(name, factory, script, meta, onScriptError);
} }
@Override @Override
@ -74,10 +75,16 @@ public final class KeywordScriptFieldType extends AbstractScriptFieldType<String
return new Builder(name).createRuntimeField(StringFieldScript.PARSE_FROM_SOURCE); return new Builder(name).createRuntimeField(StringFieldScript.PARSE_FROM_SOURCE);
} }
public KeywordScriptFieldType(String name, StringFieldScript.Factory scriptFactory, Script script, Map<String, String> meta) { public KeywordScriptFieldType(
String name,
StringFieldScript.Factory scriptFactory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
) {
super( super(
name, name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup), searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script, script,
scriptFactory.isResultDeterministic(), scriptFactory.isResultDeterministic(),
meta meta

View file

@ -43,8 +43,14 @@ public final class LongScriptFieldType extends AbstractScriptFieldType<LongField
} }
@Override @Override
AbstractScriptFieldType<?> createFieldType(String name, LongFieldScript.Factory factory, Script script, Map<String, String> meta) { AbstractScriptFieldType<?> createFieldType(
return new LongScriptFieldType(name, factory, script, meta); String name,
LongFieldScript.Factory factory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
) {
return new LongScriptFieldType(name, factory, script, meta, onScriptError);
} }
@Override @Override
@ -62,10 +68,16 @@ public final class LongScriptFieldType extends AbstractScriptFieldType<LongField
return new Builder(name).createRuntimeField(LongFieldScript.PARSE_FROM_SOURCE); return new Builder(name).createRuntimeField(LongFieldScript.PARSE_FROM_SOURCE);
} }
public LongScriptFieldType(String name, LongFieldScript.Factory scriptFactory, Script script, Map<String, String> meta) { public LongScriptFieldType(
String name,
LongFieldScript.Factory scriptFactory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
) {
super( super(
name, name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup), searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script, script,
scriptFactory.isResultDeterministic(), scriptFactory.isResultDeterministic(),
meta meta

View file

@ -159,7 +159,8 @@ public final class LookupRuntimeFieldType extends MappedFieldType {
protected RuntimeField createChildRuntimeField( protected RuntimeField createChildRuntimeField(
MappingParserContext parserContext, MappingParserContext parserContext,
String parentName, String parentName,
Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory,
OnScriptError onScriptError
) { ) {
return createRuntimeField(parserContext); return createRuntimeField(parserContext);
} }

View file

@ -592,7 +592,7 @@ public class NumberFieldMapper extends FieldMapper {
@Override @Override
public FieldValues<Number> compile(String fieldName, Script script, ScriptCompiler compiler) { public FieldValues<Number> compile(String fieldName, Script script, ScriptCompiler compiler) {
DoubleFieldScript.Factory scriptFactory = compiler.compile(script, DoubleFieldScript.CONTEXT); DoubleFieldScript.Factory scriptFactory = compiler.compile(script, DoubleFieldScript.CONTEXT);
return (lookup, ctx, doc, consumer) -> scriptFactory.newFactory(fieldName, script.getParams(), lookup) return (lookup, ctx, doc, consumer) -> scriptFactory.newFactory(fieldName, script.getParams(), lookup, OnScriptError.FAIL)
.newInstance(ctx) .newInstance(ctx)
.runForDoc(doc, consumer::accept); .runForDoc(doc, consumer::accept);
} }
@ -1055,7 +1055,7 @@ public class NumberFieldMapper extends FieldMapper {
@Override @Override
public FieldValues<Number> compile(String fieldName, Script script, ScriptCompiler compiler) { public FieldValues<Number> compile(String fieldName, Script script, ScriptCompiler compiler) {
final LongFieldScript.Factory scriptFactory = compiler.compile(script, LongFieldScript.CONTEXT); final LongFieldScript.Factory scriptFactory = compiler.compile(script, LongFieldScript.CONTEXT);
return (lookup, ctx, doc, consumer) -> scriptFactory.newFactory(fieldName, script.getParams(), lookup) return (lookup, ctx, doc, consumer) -> scriptFactory.newFactory(fieldName, script.getParams(), lookup, OnScriptError.FAIL)
.newInstance(ctx) .newInstance(ctx)
.runForDoc(doc, consumer::accept); .runForDoc(doc, consumer::accept);
} }

View file

@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.index.mapper;
import java.util.Locale;
import java.util.Objects;
/**
* Represents the behaviour when a runtime field or an index-time script fails: either fail and raise the error,
* or continue and ignore the error.
*/
public enum OnScriptError {
FAIL,
CONTINUE;
/**
* Parses the on_script_error parameter from a string into its corresponding enum instance
*/
public static OnScriptError fromString(final String str) {
Objects.requireNonNull(str, "input string is null");
return switch (str.toLowerCase(Locale.ROOT)) {
case "fail" -> FAIL;
case "continue" -> CONTINUE;
default -> throw new IllegalArgumentException("Unknown onScriptError [" + str + "]");
};
}
}

View file

@ -63,7 +63,8 @@ public interface RuntimeField extends ToXContentFragment {
protected abstract RuntimeField createChildRuntimeField( protected abstract RuntimeField createChildRuntimeField(
MappingParserContext parserContext, MappingParserContext parserContext,
String parentName, String parentName,
Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory,
OnScriptError onScriptError
); );
public final void parse(String name, MappingParserContext parserContext, Map<String, Object> fieldNode) { public final void parse(String name, MappingParserContext parserContext, Map<String, Object> fieldNode) {

View file

@ -10,6 +10,7 @@ package org.elasticsearch.script;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.search.lookup.SourceLookup; import org.elasticsearch.search.lookup.SourceLookup;
@ -69,10 +70,16 @@ public abstract class AbstractFieldScript extends DocBasedScript {
protected final String fieldName; protected final String fieldName;
protected final SourceLookup sourceLookup; protected final SourceLookup sourceLookup;
private final Map<String, Object> params; private final Map<String, Object> params;
private final OnScriptError onScriptError;
public AbstractFieldScript(String fieldName, Map<String, Object> params, SearchLookup searchLookup, LeafReaderContext ctx) { public AbstractFieldScript(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
LeafReaderContext ctx,
OnScriptError onScriptError
) {
super(new DocValuesDocReader(searchLookup, ctx)); super(new DocValuesDocReader(searchLookup, ctx));
this.fieldName = fieldName; this.fieldName = fieldName;
Map<String, Object> docAsMap = docAsMap(); Map<String, Object> docAsMap = docAsMap();
this.sourceLookup = (SourceLookup) docAsMap.get("_source"); this.sourceLookup = (SourceLookup) docAsMap.get("_source");
@ -80,6 +87,7 @@ public abstract class AbstractFieldScript extends DocBasedScript {
params.put("_source", sourceLookup); params.put("_source", sourceLookup);
params.put("_fields", docAsMap.get("_fields")); params.put("_fields", docAsMap.get("_fields"));
this.params = new DynamicMap(params, PARAMS_FUNCTIONS); this.params = new DynamicMap(params, PARAMS_FUNCTIONS);
this.onScriptError = onScriptError;
} }
/** /**
@ -141,7 +149,15 @@ public abstract class AbstractFieldScript extends DocBasedScript {
public final void runForDoc(int docId) { public final void runForDoc(int docId) {
prepareExecute(); prepareExecute();
setDocument(docId); setDocument(docId);
try {
execute(); execute();
} catch (Exception e) {
if (onScriptError == OnScriptError.CONTINUE) {
// ignore
} else {
throw e;
}
}
} }
public abstract void execute(); public abstract void execute();

View file

@ -10,6 +10,7 @@ package org.elasticsearch.script;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.ArrayUtil;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.util.Map; import java.util.Map;
@ -22,8 +23,14 @@ public abstract class AbstractLongFieldScript extends AbstractFieldScript {
private long[] values = new long[1]; private long[] values = new long[1];
private int count; private int count;
public AbstractLongFieldScript(String fieldName, Map<String, Object> params, SearchLookup searchLookup, LeafReaderContext ctx) { public AbstractLongFieldScript(
super(fieldName, params, searchLookup, ctx); String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError,
LeafReaderContext ctx
) {
super(fieldName, params, searchLookup, ctx, onScriptError);
} }
@Override @Override

View file

@ -10,6 +10,7 @@ package org.elasticsearch.script;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.core.Booleans; import org.elasticsearch.core.Booleans;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.util.Map; import java.util.Map;
@ -22,8 +23,8 @@ public abstract class BooleanFieldScript extends AbstractFieldScript {
public static final Factory PARSE_FROM_SOURCE = new Factory() { public static final Factory PARSE_FROM_SOURCE = new Factory() {
@Override @Override
public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup) { public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup, OnScriptError onScriptError) {
return ctx -> new BooleanFieldScript(field, params, lookup, ctx) { return ctx -> new BooleanFieldScript(field, params, lookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emitFromSource(); emitFromSource();
@ -38,11 +39,11 @@ public abstract class BooleanFieldScript extends AbstractFieldScript {
}; };
public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) { public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) {
return (leafFieldName, params, searchLookup) -> { return (leafFieldName, params, searchLookup, onScriptError) -> {
CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup); CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup);
return (LeafFactory) ctx -> { return (LeafFactory) ctx -> {
CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx); CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx);
return new BooleanFieldScript(leafFieldName, params, searchLookup, ctx) { return new BooleanFieldScript(leafFieldName, params, searchLookup, onScriptError, ctx) {
@Override @Override
public void setDocument(int docId) { public void setDocument(int docId) {
compositeFieldScript.setDocument(docId); compositeFieldScript.setDocument(docId);
@ -61,7 +62,7 @@ public abstract class BooleanFieldScript extends AbstractFieldScript {
public static final String[] PARAMETERS = {}; public static final String[] PARAMETERS = {};
public interface Factory extends ScriptFactory { public interface Factory extends ScriptFactory {
LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup); LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup, OnScriptError onScriptError);
} }
public interface LeafFactory { public interface LeafFactory {
@ -71,8 +72,14 @@ public abstract class BooleanFieldScript extends AbstractFieldScript {
private int trues; private int trues;
private int falses; private int falses;
public BooleanFieldScript(String fieldName, Map<String, Object> params, SearchLookup searchLookup, LeafReaderContext ctx) { public BooleanFieldScript(
super(fieldName, params, searchLookup, ctx); String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError,
LeafReaderContext ctx
) {
super(fieldName, params, searchLookup, ctx, onScriptError);
} }
@Override @Override

View file

@ -9,6 +9,7 @@
package org.elasticsearch.script; package org.elasticsearch.script;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.util.ArrayList; import java.util.ArrayList;
@ -27,7 +28,12 @@ public abstract class CompositeFieldScript extends AbstractFieldScript {
public static final String[] PARAMETERS = {}; public static final String[] PARAMETERS = {};
public interface Factory extends ScriptFactory { public interface Factory extends ScriptFactory {
CompositeFieldScript.LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup); CompositeFieldScript.LeafFactory newFactory(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError
);
} }
public interface LeafFactory { public interface LeafFactory {
@ -36,8 +42,14 @@ public abstract class CompositeFieldScript extends AbstractFieldScript {
private final Map<String, List<Object>> fieldValues = new HashMap<>(); private final Map<String, List<Object>> fieldValues = new HashMap<>();
public CompositeFieldScript(String fieldName, Map<String, Object> params, SearchLookup searchLookup, LeafReaderContext ctx) { public CompositeFieldScript(
super(fieldName, params, searchLookup, ctx); String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError,
LeafReaderContext ctx
) {
super(fieldName, params, searchLookup, ctx, onScriptError);
} }
/** /**

View file

@ -10,6 +10,7 @@ package org.elasticsearch.script;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.common.time.DateFormatter;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.util.Map; import java.util.Map;
@ -21,8 +22,14 @@ public abstract class DateFieldScript extends AbstractLongFieldScript {
public static final Factory PARSE_FROM_SOURCE = new Factory() { public static final Factory PARSE_FROM_SOURCE = new Factory() {
@Override @Override
public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup, DateFormatter formatter) { public LeafFactory newFactory(
return ctx -> new DateFieldScript(field, params, lookup, formatter, ctx) { String field,
Map<String, Object> params,
SearchLookup lookup,
DateFormatter formatter,
OnScriptError onScriptError
) {
return ctx -> new DateFieldScript(field, params, lookup, formatter, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emitFromSource(); emitFromSource();
@ -37,11 +44,11 @@ public abstract class DateFieldScript extends AbstractLongFieldScript {
}; };
public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) { public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) {
return (leafFieldName, params, searchLookup, formatter) -> { return (leafFieldName, params, searchLookup, formatter, onScriptError) -> {
CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup); CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup);
return (LeafFactory) ctx -> { return (LeafFactory) ctx -> {
CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx); CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx);
return new DateFieldScript(leafFieldName, params, searchLookup, formatter, ctx) { return new DateFieldScript(leafFieldName, params, searchLookup, formatter, onScriptError, ctx) {
@Override @Override
public void setDocument(int docId) { public void setDocument(int docId) {
compositeFieldScript.setDocument(docId); compositeFieldScript.setDocument(docId);
@ -60,7 +67,13 @@ public abstract class DateFieldScript extends AbstractLongFieldScript {
public static final String[] PARAMETERS = {}; public static final String[] PARAMETERS = {};
public interface Factory extends ScriptFactory { public interface Factory extends ScriptFactory {
LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup, DateFormatter formatter); LeafFactory newFactory(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
DateFormatter formatter,
OnScriptError onScriptError
);
} }
public interface LeafFactory { public interface LeafFactory {
@ -74,9 +87,10 @@ public abstract class DateFieldScript extends AbstractLongFieldScript {
Map<String, Object> params, Map<String, Object> params,
SearchLookup searchLookup, SearchLookup searchLookup,
DateFormatter formatter, DateFormatter formatter,
OnScriptError onScriptError,
LeafReaderContext ctx LeafReaderContext ctx
) { ) {
super(fieldName, params, searchLookup, ctx); super(fieldName, params, searchLookup, onScriptError, ctx);
this.formatter = formatter; this.formatter = formatter;
} }

View file

@ -10,6 +10,7 @@ package org.elasticsearch.script;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.ArrayUtil;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.util.Map; import java.util.Map;
@ -21,8 +22,8 @@ public abstract class DoubleFieldScript extends AbstractFieldScript {
public static final Factory PARSE_FROM_SOURCE = new Factory() { public static final Factory PARSE_FROM_SOURCE = new Factory() {
@Override @Override
public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup) { public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup, OnScriptError onScriptError) {
return ctx -> new DoubleFieldScript(field, params, lookup, ctx) { return ctx -> new DoubleFieldScript(field, params, lookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emitFromSource(); emitFromSource();
@ -37,11 +38,11 @@ public abstract class DoubleFieldScript extends AbstractFieldScript {
}; };
public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) { public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) {
return (leafFieldName, params, searchLookup) -> { return (leafFieldName, params, searchLookup, onScriptError) -> {
CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup); CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup);
return (LeafFactory) ctx -> { return (LeafFactory) ctx -> {
CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx); CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx);
return new DoubleFieldScript(leafFieldName, params, searchLookup, ctx) { return new DoubleFieldScript(leafFieldName, params, searchLookup, onScriptError, ctx) {
@Override @Override
public void setDocument(int docId) { public void setDocument(int docId) {
compositeFieldScript.setDocument(docId); compositeFieldScript.setDocument(docId);
@ -60,7 +61,7 @@ public abstract class DoubleFieldScript extends AbstractFieldScript {
public static final String[] PARAMETERS = {}; public static final String[] PARAMETERS = {};
public interface Factory extends ScriptFactory { public interface Factory extends ScriptFactory {
LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup); LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup, OnScriptError onScriptError);
} }
public interface LeafFactory { public interface LeafFactory {
@ -70,8 +71,14 @@ public abstract class DoubleFieldScript extends AbstractFieldScript {
private double[] values = new double[1]; private double[] values = new double[1];
private int count; private int count;
public DoubleFieldScript(String fieldName, Map<String, Object> params, SearchLookup searchLookup, LeafReaderContext ctx) { public DoubleFieldScript(
super(fieldName, params, searchLookup, ctx); String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError,
LeafReaderContext ctx
) {
super(fieldName, params, searchLookup, ctx, onScriptError);
} }
@Override @Override

View file

@ -14,6 +14,7 @@ import org.apache.lucene.util.ArrayUtil;
import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoUtils; import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.util.Collections; import java.util.Collections;
@ -31,8 +32,8 @@ public abstract class GeoPointFieldScript extends AbstractFieldScript {
public static final Factory PARSE_FROM_SOURCE = new Factory() { public static final Factory PARSE_FROM_SOURCE = new Factory() {
@Override @Override
public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup) { public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup, OnScriptError onScriptError) {
return ctx -> new GeoPointFieldScript(field, params, lookup, ctx) { return ctx -> new GeoPointFieldScript(field, params, lookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emitFromSource(); emitFromSource();
@ -47,11 +48,11 @@ public abstract class GeoPointFieldScript extends AbstractFieldScript {
}; };
public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) { public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) {
return (leafFieldName, params, searchLookup) -> { return (leafFieldName, params, searchLookup, onScriptError) -> {
CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup); CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup);
return (LeafFactory) ctx -> { return (LeafFactory) ctx -> {
CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx); CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx);
return new GeoPointFieldScript(leafFieldName, params, searchLookup, ctx) { return new GeoPointFieldScript(leafFieldName, params, searchLookup, onScriptError, ctx) {
@Override @Override
public void setDocument(int docId) { public void setDocument(int docId) {
compositeFieldScript.setDocument(docId); compositeFieldScript.setDocument(docId);
@ -70,7 +71,7 @@ public abstract class GeoPointFieldScript extends AbstractFieldScript {
public static final String[] PARAMETERS = {}; public static final String[] PARAMETERS = {};
public interface Factory extends ScriptFactory { public interface Factory extends ScriptFactory {
LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup); LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup, OnScriptError onScriptError);
} }
public interface LeafFactory { public interface LeafFactory {
@ -81,8 +82,14 @@ public abstract class GeoPointFieldScript extends AbstractFieldScript {
private double[] lons = new double[1]; private double[] lons = new double[1];
private int count; private int count;
public GeoPointFieldScript(String fieldName, Map<String, Object> params, SearchLookup searchLookup, LeafReaderContext ctx) { public GeoPointFieldScript(
super(fieldName, params, searchLookup, ctx); String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError,
LeafReaderContext ctx
) {
super(fieldName, params, searchLookup, ctx, onScriptError);
} }
@Override @Override

View file

@ -14,6 +14,7 @@ import org.apache.lucene.util.ArrayUtil;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.index.mapper.IpFieldMapper; import org.elasticsearch.index.mapper.IpFieldMapper;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.net.Inet4Address; import java.net.Inet4Address;
@ -42,8 +43,8 @@ public abstract class IpFieldScript extends AbstractFieldScript {
public static final Factory PARSE_FROM_SOURCE = new Factory() { public static final Factory PARSE_FROM_SOURCE = new Factory() {
@Override @Override
public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup) { public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup, OnScriptError onScriptError) {
return ctx -> new IpFieldScript(field, params, lookup, ctx) { return ctx -> new IpFieldScript(field, params, lookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emitFromSource(); emitFromSource();
@ -58,11 +59,11 @@ public abstract class IpFieldScript extends AbstractFieldScript {
}; };
public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) { public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) {
return (leafFieldName, params, searchLookup) -> { return (leafFieldName, params, searchLookup, onScriptError) -> {
CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup); CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup);
return (LeafFactory) ctx -> { return (LeafFactory) ctx -> {
CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx); CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx);
return new IpFieldScript(leafFieldName, params, searchLookup, ctx) { return new IpFieldScript(leafFieldName, params, searchLookup, onScriptError, ctx) {
@Override @Override
public void setDocument(int docId) { public void setDocument(int docId) {
compositeFieldScript.setDocument(docId); compositeFieldScript.setDocument(docId);
@ -81,7 +82,7 @@ public abstract class IpFieldScript extends AbstractFieldScript {
public static final String[] PARAMETERS = {}; public static final String[] PARAMETERS = {};
public interface Factory extends ScriptFactory { public interface Factory extends ScriptFactory {
LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup); LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup, OnScriptError onScriptError);
} }
public interface LeafFactory { public interface LeafFactory {
@ -91,8 +92,14 @@ public abstract class IpFieldScript extends AbstractFieldScript {
private BytesRef[] values = new BytesRef[1]; private BytesRef[] values = new BytesRef[1];
private int count; private int count;
public IpFieldScript(String fieldName, Map<String, Object> params, SearchLookup searchLookup, LeafReaderContext ctx) { public IpFieldScript(
super(fieldName, params, searchLookup, ctx); String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError,
LeafReaderContext ctx
) {
super(fieldName, params, searchLookup, ctx, onScriptError);
} }
@Override @Override

View file

@ -10,6 +10,7 @@ package org.elasticsearch.script;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.util.Map; import java.util.Map;
@ -20,8 +21,8 @@ public abstract class LongFieldScript extends AbstractLongFieldScript {
public static final Factory PARSE_FROM_SOURCE = new Factory() { public static final Factory PARSE_FROM_SOURCE = new Factory() {
@Override @Override
public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup) { public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup, OnScriptError onScriptError) {
return ctx -> new LongFieldScript(field, params, lookup, ctx) { return ctx -> new LongFieldScript(field, params, lookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emitFromSource(); emitFromSource();
@ -36,11 +37,11 @@ public abstract class LongFieldScript extends AbstractLongFieldScript {
}; };
public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) { public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) {
return (leafFieldName, params, searchLookup) -> { return (leafFieldName, params, searchLookup, onScriptError) -> {
CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup); CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup);
return (LeafFactory) ctx -> { return (LeafFactory) ctx -> {
CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx); CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx);
return new LongFieldScript(leafFieldName, params, searchLookup, ctx) { return new LongFieldScript(leafFieldName, params, searchLookup, onScriptError, ctx) {
@Override @Override
public void setDocument(int docId) { public void setDocument(int docId) {
compositeFieldScript.setDocument(docId); compositeFieldScript.setDocument(docId);
@ -59,15 +60,21 @@ public abstract class LongFieldScript extends AbstractLongFieldScript {
public static final String[] PARAMETERS = {}; public static final String[] PARAMETERS = {};
public interface Factory extends ScriptFactory { public interface Factory extends ScriptFactory {
LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup); LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup, OnScriptError onScriptError);
} }
public interface LeafFactory { public interface LeafFactory {
LongFieldScript newInstance(LeafReaderContext ctx); LongFieldScript newInstance(LeafReaderContext ctx);
} }
public LongFieldScript(String fieldName, Map<String, Object> params, SearchLookup searchLookup, LeafReaderContext ctx) { public LongFieldScript(
super(fieldName, params, searchLookup, ctx); String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError,
LeafReaderContext ctx
) {
super(fieldName, params, searchLookup, onScriptError, ctx);
} }
@Override @Override

View file

@ -10,6 +10,7 @@ package org.elasticsearch.script;
import org.apache.lucene.index.DocValues; import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.script.field.LongDocValuesField; import org.elasticsearch.script.field.LongDocValuesField;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
@ -21,7 +22,7 @@ public class SortedNumericDocValuesLongFieldScript extends AbstractLongFieldScri
final LongDocValuesField longDocValuesField; final LongDocValuesField longDocValuesField;
public SortedNumericDocValuesLongFieldScript(String fieldName, SearchLookup lookup, LeafReaderContext ctx) { public SortedNumericDocValuesLongFieldScript(String fieldName, SearchLookup lookup, LeafReaderContext ctx) {
super(fieldName, Map.of(), lookup, ctx); super(fieldName, Map.of(), lookup, OnScriptError.FAIL, ctx);
try { try {
longDocValuesField = new LongDocValuesField(DocValues.getSortedNumeric(ctx.reader(), fieldName), fieldName); longDocValuesField = new LongDocValuesField(DocValues.getSortedNumeric(ctx.reader(), fieldName), fieldName);
} catch (IOException e) { } catch (IOException e) {

View file

@ -12,6 +12,7 @@ import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.io.IOException; import java.io.IOException;
@ -23,7 +24,7 @@ public class SortedSetDocValuesStringFieldScript extends StringFieldScript {
boolean hasValue = false; boolean hasValue = false;
public SortedSetDocValuesStringFieldScript(String fieldName, SearchLookup searchLookup, LeafReaderContext ctx) { public SortedSetDocValuesStringFieldScript(String fieldName, SearchLookup searchLookup, LeafReaderContext ctx) {
super(fieldName, Map.of(), searchLookup, ctx); super(fieldName, Map.of(), searchLookup, OnScriptError.FAIL, ctx);
try { try {
sortedSetDocValues = DocValues.getSortedSet(ctx.reader(), fieldName); sortedSetDocValues = DocValues.getSortedSet(ctx.reader(), fieldName);
} catch (IOException e) { } catch (IOException e) {

View file

@ -9,6 +9,7 @@
package org.elasticsearch.script; package org.elasticsearch.script;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import java.util.ArrayList; import java.util.ArrayList;
@ -28,8 +29,8 @@ public abstract class StringFieldScript extends AbstractFieldScript {
public static final StringFieldScript.Factory PARSE_FROM_SOURCE = new Factory() { public static final StringFieldScript.Factory PARSE_FROM_SOURCE = new Factory() {
@Override @Override
public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup) { public LeafFactory newFactory(String field, Map<String, Object> params, SearchLookup lookup, OnScriptError onScriptError) {
return ctx -> new StringFieldScript(field, params, lookup, ctx) { return ctx -> new StringFieldScript(field, params, lookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emitFromSource(); emitFromSource();
@ -44,11 +45,11 @@ public abstract class StringFieldScript extends AbstractFieldScript {
}; };
public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) { public static Factory leafAdapter(Function<SearchLookup, CompositeFieldScript.LeafFactory> parentFactory) {
return (leafFieldName, params, searchLookup) -> { return (leafFieldName, params, searchLookup, onScriptError) -> {
CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup); CompositeFieldScript.LeafFactory parentLeafFactory = parentFactory.apply(searchLookup);
return (LeafFactory) ctx -> { return (LeafFactory) ctx -> {
CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx); CompositeFieldScript compositeFieldScript = parentLeafFactory.newInstance(ctx);
return new StringFieldScript(leafFieldName, params, searchLookup, ctx) { return new StringFieldScript(leafFieldName, params, searchLookup, onScriptError, ctx) {
@Override @Override
public void setDocument(int docId) { public void setDocument(int docId) {
compositeFieldScript.setDocument(docId); compositeFieldScript.setDocument(docId);
@ -67,7 +68,7 @@ public abstract class StringFieldScript extends AbstractFieldScript {
public static final String[] PARAMETERS = {}; public static final String[] PARAMETERS = {};
public interface Factory extends ScriptFactory { public interface Factory extends ScriptFactory {
LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup); LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup, OnScriptError onScriptError);
} }
public interface LeafFactory { public interface LeafFactory {
@ -77,8 +78,14 @@ public abstract class StringFieldScript extends AbstractFieldScript {
private final List<String> results = new ArrayList<>(); private final List<String> results = new ArrayList<>();
private long chars; private long chars;
public StringFieldScript(String fieldName, Map<String, Object> params, SearchLookup searchLookup, LeafReaderContext ctx) { public StringFieldScript(
super(fieldName, params, searchLookup, ctx); String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError,
LeafReaderContext ctx
) {
super(fieldName, params, searchLookup, ctx, onScriptError);
} }
@Override @Override

View file

@ -12,6 +12,7 @@ import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateUtils; import org.elasticsearch.common.time.DateUtils;
import org.elasticsearch.index.mapper.MapperServiceTestCase; import org.elasticsearch.index.mapper.MapperServiceTestCase;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.script.Script; import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.StringFieldScript; import org.elasticsearch.script.StringFieldScript;
@ -264,7 +265,12 @@ public class TimeSeriesModeTests extends MapperServiceTestCase {
if (context.equals(StringFieldScript.CONTEXT) && script.getLang().equals("mock")) { if (context.equals(StringFieldScript.CONTEXT) && script.getLang().equals("mock")) {
return (T) new StringFieldScript.Factory() { return (T) new StringFieldScript.Factory() {
@Override @Override
public LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup) { public LeafFactory newFactory(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError
) {
throw new UnsupportedOperationException("error should be thrown before getting here"); throw new UnsupportedOperationException("error should be thrown before getting here");
} }
}; };

View file

@ -8,9 +8,14 @@
package org.elasticsearch.index.mapper; package org.elasticsearch.index.mapper;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;
import org.apache.lucene.tests.index.RandomIndexWriter;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
@ -18,6 +23,7 @@ import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.index.fielddata.FieldDataContext; import org.elasticsearch.index.fielddata.FieldDataContext;
import org.elasticsearch.index.fielddata.IndexFieldDataCache; import org.elasticsearch.index.fielddata.IndexFieldDataCache;
import org.elasticsearch.index.query.ExistsQueryBuilder;
import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
import org.elasticsearch.script.BooleanFieldScript; import org.elasticsearch.script.BooleanFieldScript;
@ -38,7 +44,9 @@ import org.elasticsearch.xcontent.json.JsonXContent;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
@ -157,6 +165,45 @@ public abstract class AbstractScriptFieldTypeTestCase extends MapperServiceTestC
assertEquals(concreteIndexType.isAggregatable(), scriptFieldType.isAggregatable()); assertEquals(concreteIndexType.isAggregatable(), scriptFieldType.isAggregatable());
} }
/**
* Check that running query on a runtime field script that fails has the expected behaviour according to its configuration
*/
public final void testOnScriptError() throws IOException {
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [1]}"))));
try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader);
{
AbstractScriptFieldType<?> fieldType = build("error", Collections.emptyMap(), OnScriptError.CONTINUE);
SearchExecutionContext searchExecutionContext = mockContext(true, fieldType);
Query query = new ExistsQueryBuilder("test").rewrite(searchExecutionContext).toQuery(searchExecutionContext);
assertEquals(0, searcher.count(query));
}
{
AbstractScriptFieldType<?> fieldType = build("error", Collections.emptyMap(), OnScriptError.FAIL);
SearchExecutionContext searchExecutionContext = mockContext(true, fieldType);
Query query = new ExistsQueryBuilder("test").rewrite(searchExecutionContext).toQuery(searchExecutionContext);
expectThrows(RuntimeException.class, () -> searcher.count(query));
}
}
}
}
public final void testOnScriptErrorFail() throws IOException {
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [1]}"))));
try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader);
AbstractScriptFieldType<?> fieldType = build("error", Collections.emptyMap(), OnScriptError.FAIL);
SearchExecutionContext searchExecutionContext = mockContext(true, fieldType);
Query query = new ExistsQueryBuilder("test").rewrite(searchExecutionContext).toQuery(searchExecutionContext);
expectThrows(RuntimeException.class, () -> searcher.count(query));
}
}
}
protected abstract AbstractScriptFieldType<?> build(String error, Map<String, Object> emptyMap, OnScriptError onScriptError);
@SuppressWarnings("unused") @SuppressWarnings("unused")
public abstract void testDocValues() throws IOException; public abstract void testDocValues() throws IOException;
@ -237,6 +284,7 @@ public abstract class AbstractScriptFieldTypeTestCase extends MapperServiceTestC
return ft.fielddataBuilder(new FieldDataContext("test", context::lookup, context::sourcePath, fdo)) return ft.fielddataBuilder(new FieldDataContext("test", context::lookup, context::sourcePath, fdo))
.build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService()); .build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService());
}); });
when(context.getMatchingFieldNames(any())).thenReturn(Set.of("dummy_field"));
return context; return context;
} }

View file

@ -258,7 +258,13 @@ public class BooleanFieldMapperTests extends MapperTestCase {
return new IngestScriptSupport() { return new IngestScriptSupport() {
@Override @Override
protected BooleanFieldScript.Factory emptyFieldScript() { protected BooleanFieldScript.Factory emptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new BooleanFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new BooleanFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() {} public void execute() {}
}; };
@ -266,7 +272,13 @@ public class BooleanFieldMapperTests extends MapperTestCase {
@Override @Override
protected BooleanFieldScript.Factory nonEmptyFieldScript() { protected BooleanFieldScript.Factory nonEmptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new BooleanFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new BooleanFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit(true); emit(true);

View file

@ -24,10 +24,11 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class BooleanFieldScriptTests extends FieldScriptTestCase<BooleanFieldScript.Factory> { public class BooleanFieldScriptTests extends FieldScriptTestCase<BooleanFieldScript.Factory> {
public static final BooleanFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new BooleanFieldScript( public static final BooleanFieldScript.Factory DUMMY = (fieldName, params, lookup, onScriptError) -> ctx -> new BooleanFieldScript(
fieldName, fieldName,
params, params,
lookup, lookup,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -59,6 +60,7 @@ public class BooleanFieldScriptTests extends FieldScriptTestCase<BooleanFieldScr
"test", "test",
Map.of(), Map.of(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override

View file

@ -253,7 +253,10 @@ public class BooleanScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeT
assertThat(searcher.count(simpleMappedFieldType().termQuery(true, mockContext())), equalTo(1)); assertThat(searcher.count(simpleMappedFieldType().termQuery(true, mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery("true", mockContext())), equalTo(1)); assertThat(searcher.count(simpleMappedFieldType().termQuery("true", mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(false, mockContext())), equalTo(0)); assertThat(searcher.count(simpleMappedFieldType().termQuery(false, mockContext())), equalTo(0));
assertThat(searcher.count(build("xor_param", Map.of("param", false)).termQuery(true, mockContext())), equalTo(1)); assertThat(
searcher.count(build("xor_param", Map.of("param", false), OnScriptError.FAIL).termQuery(true, mockContext())),
equalTo(1)
);
} }
} }
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) { try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
@ -264,7 +267,10 @@ public class BooleanScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeT
assertThat(searcher.count(simpleMappedFieldType().termQuery("false", mockContext())), equalTo(1)); assertThat(searcher.count(simpleMappedFieldType().termQuery("false", mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(null, mockContext())), equalTo(1)); assertThat(searcher.count(simpleMappedFieldType().termQuery(null, mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(true, mockContext())), equalTo(0)); assertThat(searcher.count(simpleMappedFieldType().termQuery(true, mockContext())), equalTo(0));
assertThat(searcher.count(build("xor_param", Map.of("param", false)).termQuery(false, mockContext())), equalTo(1)); assertThat(
searcher.count(build("xor_param", Map.of("param", false), OnScriptError.FAIL).termQuery(false, mockContext())),
equalTo(1)
);
} }
} }
} }
@ -400,12 +406,12 @@ public class BooleanScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeT
@Override @Override
protected BooleanScriptFieldType simpleMappedFieldType() { protected BooleanScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of()); return build("read_foo", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
protected MappedFieldType loopFieldType() { protected MappedFieldType loopFieldType() {
return build("loop", Map.of()); return build("loop", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
@ -413,13 +419,20 @@ public class BooleanScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeT
return "boolean"; return "boolean";
} }
private static BooleanScriptFieldType build(String code, Map<String, Object> params) { protected BooleanScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
return build(new Script(ScriptType.INLINE, "test", code, params)); Script script = new Script(ScriptType.INLINE, "test", code, params);
return new BooleanScriptFieldType("test", factory(script), script, emptyMap(), onScriptError);
} }
private static BooleanFieldScript.Factory factory(Script script) { private static BooleanFieldScript.Factory factory(Script script) {
return switch (script.getIdOrCode()) { return switch (script.getIdOrCode()) {
case "read_foo" -> (fieldName, params, lookup) -> (ctx) -> new BooleanFieldScript(fieldName, params, lookup, ctx) { case "read_foo" -> (fieldName, params, lookup, onScriptError) -> (ctx) -> new BooleanFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -427,7 +440,13 @@ public class BooleanScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeT
} }
} }
}; };
case "xor_param" -> (fieldName, params, lookup) -> (ctx) -> new BooleanFieldScript(fieldName, params, lookup, ctx) { case "xor_param" -> (fieldName, params, lookup, onScriptError) -> (ctx) -> new BooleanFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -435,16 +454,24 @@ public class BooleanScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeT
} }
} }
}; };
case "loop" -> (fieldName, params, lookup) -> { case "loop" -> (fieldName, params, lookup, onScriptError) -> {
// Indicate that this script wants the field call "test", which *is* the name of this field // Indicate that this script wants the field call "test", which *is* the name of this field
lookup.forkAndTrackFieldReferences("test"); lookup.forkAndTrackFieldReferences("test");
throw new IllegalStateException("should have thrown on the line above"); throw new IllegalStateException("should have thrown on the line above");
}; };
case "error" -> (fieldName, params, lookup, onScriptError) -> ctx -> new BooleanFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override
public void execute() {
throw new RuntimeException("test error");
}
};
default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]"); default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]");
}; };
} }
private static BooleanScriptFieldType build(Script script) {
return new BooleanScriptFieldType("test", factory(script), script, emptyMap());
}
} }

View file

@ -21,11 +21,16 @@ public class BooleanScriptMapperTests extends MapperScriptTestCase<BooleanFieldS
private static BooleanFieldScript.Factory factory(Consumer<BooleanFieldScript> executor) { private static BooleanFieldScript.Factory factory(Consumer<BooleanFieldScript> executor) {
return new BooleanFieldScript.Factory() { return new BooleanFieldScript.Factory() {
@Override @Override
public BooleanFieldScript.LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup) { public BooleanFieldScript.LeafFactory newFactory(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError
) {
return new BooleanFieldScript.LeafFactory() { return new BooleanFieldScript.LeafFactory() {
@Override @Override
public BooleanFieldScript newInstance(LeafReaderContext ctx) { public BooleanFieldScript newInstance(LeafReaderContext ctx) {
return new BooleanFieldScript(fieldName, params, searchLookup, ctx) { return new BooleanFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
executor.accept(this); executor.accept(this);

View file

@ -33,10 +33,11 @@ public class CompositeRuntimeFieldTests extends MapperServiceTestCase {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T> T compileScript(Script script, ScriptContext<T> context) { protected <T> T compileScript(Script script, ScriptContext<T> context) {
if (context == CompositeFieldScript.CONTEXT) { if (context == CompositeFieldScript.CONTEXT) {
return (T) (CompositeFieldScript.Factory) (fieldName, params, searchLookup) -> ctx -> new CompositeFieldScript( return (T) (CompositeFieldScript.Factory) (fieldName, params, searchLookup, onScriptError) -> ctx -> new CompositeFieldScript(
fieldName, fieldName,
params, params,
searchLookup, searchLookup,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -52,7 +53,13 @@ public class CompositeRuntimeFieldTests extends MapperServiceTestCase {
}; };
} }
if (context == LongFieldScript.CONTEXT) { if (context == LongFieldScript.CONTEXT) {
return (T) (LongFieldScript.Factory) (field, params, lookup) -> ctx -> new LongFieldScript(field, params, lookup, ctx) { return (T) (LongFieldScript.Factory) (field, params, lookup, onScriptError) -> ctx -> new LongFieldScript(
field,
params,
lookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {

View file

@ -669,11 +669,12 @@ public class DateFieldMapperTests extends MapperTestCase {
return new IngestScriptSupport() { return new IngestScriptSupport() {
@Override @Override
protected DateFieldScript.Factory emptyFieldScript() { protected DateFieldScript.Factory emptyFieldScript() {
return (fieldName, params, searchLookup, formatter) -> ctx -> new DateFieldScript( return (fieldName, params, searchLookup, formatter, onScriptError) -> ctx -> new DateFieldScript(
fieldName, fieldName,
params, params,
searchLookup, searchLookup,
formatter, formatter,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -683,11 +684,12 @@ public class DateFieldMapperTests extends MapperTestCase {
@Override @Override
protected DateFieldScript.Factory nonEmptyFieldScript() { protected DateFieldScript.Factory nonEmptyFieldScript() {
return (fieldName, params, searchLookup, formatter) -> ctx -> new DateFieldScript( return (fieldName, params, searchLookup, formatter, onScriptError) -> ctx -> new DateFieldScript(
fieldName, fieldName,
params, params,
searchLookup, searchLookup,
formatter, formatter,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override

View file

@ -32,11 +32,12 @@ import java.util.Map;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class DateFieldScriptTests extends FieldScriptTestCase<DateFieldScript.Factory> { public class DateFieldScriptTests extends FieldScriptTestCase<DateFieldScript.Factory> {
public static final DateFieldScript.Factory DUMMY = (fieldName, params, lookup, formatter) -> ctx -> new DateFieldScript( public static final DateFieldScript.Factory DUMMY = (fieldName, params, lookup, formatter, onScriptError) -> ctx -> new DateFieldScript(
fieldName, fieldName,
params, params,
lookup, lookup,
formatter, formatter,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -69,6 +70,7 @@ public class DateFieldScriptTests extends FieldScriptTestCase<DateFieldScript.Fa
Map.of(), Map.of(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
DateFormatter.forPattern(randomDateFormatterPattern()).withLocale(randomLocale(random())), DateFormatter.forPattern(randomDateFormatterPattern()).withLocale(randomLocale(random())),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override
@ -104,7 +106,8 @@ public class DateFieldScriptTests extends FieldScriptTestCase<DateFieldScript.Fa
"field", "field",
Collections.emptyMap(), Collections.emptyMap(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
DateFormatter.forPattern("epoch_millis") DateFormatter.forPattern("epoch_millis"),
OnScriptError.FAIL
); );
DateFieldScript dateFieldScript = leafFactory.newInstance(reader.leaves().get(0)); DateFieldScript dateFieldScript = leafFactory.newInstance(reader.leaves().get(0));
List<Long> results = new ArrayList<>(); List<Long> results = new ArrayList<>();

View file

@ -128,7 +128,11 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
public void testFormatDuel() throws IOException { public void testFormatDuel() throws IOException {
DateFormatter formatter = DateFormatter.forPattern(randomDateFormatterPattern()).withLocale(randomLocale(random())); DateFormatter formatter = DateFormatter.forPattern(randomDateFormatterPattern()).withLocale(randomLocale(random()));
DateScriptFieldType scripted = build(new Script(ScriptType.INLINE, "test", "read_timestamp", Map.of()), formatter); DateScriptFieldType scripted = build(
new Script(ScriptType.INLINE, "test", "read_timestamp", Map.of()),
formatter,
OnScriptError.FAIL
);
DateFieldMapper.DateFieldType indexed = new DateFieldMapper.DateFieldType("test", formatter); DateFieldMapper.DateFieldType indexed = new DateFieldMapper.DateFieldType("test", formatter);
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
long date = randomDate(); long date = randomDate();
@ -149,7 +153,7 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
List<Long> results = new ArrayList<>(); List<Long> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
DateScriptFieldType ft = build("add_days", Map.of("days", 1)); DateScriptFieldType ft = build("add_days", Map.of("days", 1), OnScriptError.FAIL);
DateScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null); DateScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null);
searcher.search(new MatchAllDocsQuery(), new Collector() { searcher.search(new MatchAllDocsQuery(), new Collector() {
@Override @Override
@ -381,7 +385,9 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
assertThat(searcher.count(simpleMappedFieldType().termQuery(1595432181354L, mockContext())), equalTo(1)); assertThat(searcher.count(simpleMappedFieldType().termQuery(1595432181354L, mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(2595432181354L, mockContext())), equalTo(0)); assertThat(searcher.count(simpleMappedFieldType().termQuery(2595432181354L, mockContext())), equalTo(0));
assertThat( assertThat(
searcher.count(build("add_days", Map.of("days", 1)).termQuery("2020-07-23T15:36:21.354Z", mockContext())), searcher.count(
build("add_days", Map.of("days", 1), OnScriptError.FAIL).termQuery("2020-07-23T15:36:21.354Z", mockContext())
),
equalTo(1) equalTo(1)
); );
checkBadDate(() -> searcher.count(simpleMappedFieldType().termQuery("2020-07-22(-■_■)15:36:21.354Z", mockContext()))); checkBadDate(() -> searcher.count(simpleMappedFieldType().termQuery("2020-07-22(-■_■)15:36:21.354Z", mockContext())));
@ -462,7 +468,11 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
} }
private DateScriptFieldType coolFormattedFieldType() { private DateScriptFieldType coolFormattedFieldType() {
return build(simpleMappedFieldType().script, DateFormatter.forPattern("yyyy-MM-dd(-■_■)HH:mm:ss.SSSz||epoch_millis")); return build(
simpleMappedFieldType().script,
DateFormatter.forPattern("yyyy-MM-dd(-■_■)HH:mm:ss.SSSz||epoch_millis"),
OnScriptError.FAIL
);
} }
@Override @Override
@ -470,21 +480,22 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
return "date"; return "date";
} }
private static DateScriptFieldType build(String code) { private DateScriptFieldType build(String code) {
return build(code, Map.of()); return build(code, Map.of(), OnScriptError.FAIL);
} }
private static DateScriptFieldType build(String code, Map<String, Object> params) { protected DateScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
return build(new Script(ScriptType.INLINE, "test", code, params), DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER); return build(new Script(ScriptType.INLINE, "test", code, params), DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER, onScriptError);
} }
private static DateFieldScript.Factory factory(Script script) { private static DateFieldScript.Factory factory(Script script) {
return switch (script.getIdOrCode()) { return switch (script.getIdOrCode()) {
case "read_timestamp" -> (fieldName, params, lookup, formatter) -> ctx -> new DateFieldScript( case "read_timestamp" -> (fieldName, params, lookup, formatter, onScriptError) -> ctx -> new DateFieldScript(
fieldName, fieldName,
params, params,
lookup, lookup,
formatter, formatter,
onScriptError,
ctx ctx
) { ) {
@Override @Override
@ -495,11 +506,12 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
} }
} }
}; };
case "add_days" -> (fieldName, params, lookup, formatter) -> ctx -> new DateFieldScript( case "add_days" -> (fieldName, params, lookup, formatter, onScriptError) -> ctx -> new DateFieldScript(
fieldName, fieldName,
params, params,
lookup, lookup,
formatter, formatter,
onScriptError,
ctx ctx
) { ) {
@Override @Override
@ -512,17 +524,30 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
} }
} }
}; };
case "loop" -> (fieldName, params, lookup, formatter) -> { case "loop" -> (fieldName, params, lookup, formatter, onScriptError) -> {
// Indicate that this script wants the field call "test", which *is* the name of this field // Indicate that this script wants the field call "test", which *is* the name of this field
lookup.forkAndTrackFieldReferences("test"); lookup.forkAndTrackFieldReferences("test");
throw new IllegalStateException("shoud have thrown on the line above"); throw new IllegalStateException("should have thrown on the line above");
};
case "error" -> (fieldName, params, lookup, formatter, onScriptError) -> ctx -> new DateFieldScript(
fieldName,
params,
lookup,
formatter,
onScriptError,
ctx
) {
@Override
public void execute() {
throw new RuntimeException("test error");
}
}; };
default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]"); default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]");
}; };
} }
private static DateScriptFieldType build(Script script, DateFormatter dateTimeFormatter) { private static DateScriptFieldType build(Script script, DateFormatter dateTimeFormatter, OnScriptError onScriptError) {
return new DateScriptFieldType("test", factory(script), dateTimeFormatter, script, emptyMap()); return new DateScriptFieldType("test", factory(script), dateTimeFormatter, script, emptyMap(), onScriptError);
} }
private static long randomDate() { private static long randomDate() {

View file

@ -26,12 +26,13 @@ public class DateScriptMapperTests extends MapperScriptTestCase<DateFieldScript.
String fieldName, String fieldName,
Map<String, Object> params, Map<String, Object> params,
SearchLookup searchLookup, SearchLookup searchLookup,
DateFormatter formatter DateFormatter formatter,
OnScriptError onScriptError
) { ) {
return new DateFieldScript.LeafFactory() { return new DateFieldScript.LeafFactory() {
@Override @Override
public DateFieldScript newInstance(LeafReaderContext ctx) { public DateFieldScript newInstance(LeafReaderContext ctx) {
return new DateFieldScript(fieldName, params, searchLookup, formatter, ctx) { return new DateFieldScript(fieldName, params, searchLookup, formatter, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
executor.accept(this); executor.accept(this);

View file

@ -2604,7 +2604,8 @@ public class DocumentParserTests extends MapperServiceTestCase {
protected RuntimeField createChildRuntimeField( protected RuntimeField createChildRuntimeField(
MappingParserContext parserContext, MappingParserContext parserContext,
String parentName, String parentName,
Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory,
OnScriptError onScriptError
) { ) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View file

@ -105,7 +105,13 @@ public class DoubleFieldMapperTests extends NumberFieldMapperTests {
@Override @Override
protected DoubleFieldScript.Factory emptyFieldScript() { protected DoubleFieldScript.Factory emptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new DoubleFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new DoubleFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() {} public void execute() {}
}; };
@ -113,7 +119,13 @@ public class DoubleFieldMapperTests extends NumberFieldMapperTests {
@Override @Override
protected DoubleFieldScript.Factory nonEmptyFieldScript() { protected DoubleFieldScript.Factory nonEmptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new DoubleFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new DoubleFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit(1.0); emit(1.0);

View file

@ -31,10 +31,11 @@ import java.util.Map;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class DoubleFieldScriptTests extends FieldScriptTestCase<DoubleFieldScript.Factory> { public class DoubleFieldScriptTests extends FieldScriptTestCase<DoubleFieldScript.Factory> {
public static final DoubleFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new DoubleFieldScript( public static final DoubleFieldScript.Factory DUMMY = (fieldName, params, lookup, onScriptError) -> ctx -> new DoubleFieldScript(
fieldName, fieldName,
params, params,
lookup, lookup,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -66,6 +67,7 @@ public class DoubleFieldScriptTests extends FieldScriptTestCase<DoubleFieldScrip
"test", "test",
Map.of(), Map.of(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override
@ -100,7 +102,8 @@ public class DoubleFieldScriptTests extends FieldScriptTestCase<DoubleFieldScrip
DoubleFieldScript.LeafFactory leafFactory = fromSource().newFactory( DoubleFieldScript.LeafFactory leafFactory = fromSource().newFactory(
"field", "field",
Collections.emptyMap(), Collections.emptyMap(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()) new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL
); );
DoubleFieldScript doubleFieldScript = leafFactory.newInstance(reader.leaves().get(0)); DoubleFieldScript doubleFieldScript = leafFactory.newInstance(reader.leaves().get(0));
List<Double> results = new ArrayList<>(); List<Double> results = new ArrayList<>();

View file

@ -64,7 +64,7 @@ public class DoubleScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTe
List<Double> results = new ArrayList<>(); List<Double> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
DoubleScriptFieldType ft = build("add_param", Map.of("param", 1)); DoubleScriptFieldType ft = build("add_param", Map.of("param", 1), OnScriptError.FAIL);
DoubleScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null); DoubleScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null);
searcher.search(new MatchAllDocsQuery(), new Collector() { searcher.search(new MatchAllDocsQuery(), new Collector() {
@Override @Override
@ -190,7 +190,10 @@ public class DoubleScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTe
assertThat(searcher.count(simpleMappedFieldType().termQuery("1", mockContext())), equalTo(1)); assertThat(searcher.count(simpleMappedFieldType().termQuery("1", mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(1, mockContext())), equalTo(1)); assertThat(searcher.count(simpleMappedFieldType().termQuery(1, mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(1.1, mockContext())), equalTo(0)); assertThat(searcher.count(simpleMappedFieldType().termQuery(1.1, mockContext())), equalTo(0));
assertThat(searcher.count(build("add_param", Map.of("param", 1)).termQuery(2, mockContext())), equalTo(1)); assertThat(
searcher.count(build("add_param", Map.of("param", 1), OnScriptError.FAIL).termQuery(2, mockContext())),
equalTo(1)
);
} }
} }
} }
@ -223,12 +226,12 @@ public class DoubleScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTe
@Override @Override
protected DoubleScriptFieldType simpleMappedFieldType() { protected DoubleScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of()); return build("read_foo", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
protected MappedFieldType loopFieldType() { protected MappedFieldType loopFieldType() {
return build("loop", Map.of()); return build("loop", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
@ -236,13 +239,20 @@ public class DoubleScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTe
return "double"; return "double";
} }
private static DoubleScriptFieldType build(String code, Map<String, Object> params) { protected DoubleScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
return build(new Script(ScriptType.INLINE, "test", code, params)); Script script = new Script(ScriptType.INLINE, "test", code, params);
return new DoubleScriptFieldType("test", factory(script), script, emptyMap(), onScriptError);
} }
private static DoubleFieldScript.Factory factory(Script script) { private static DoubleFieldScript.Factory factory(Script script) {
return switch (script.getIdOrCode()) { return switch (script.getIdOrCode()) {
case "read_foo" -> (fieldName, params, lookup) -> (ctx) -> new DoubleFieldScript(fieldName, params, lookup, ctx) { case "read_foo" -> (fieldName, params, lookup, onScriptError) -> (ctx) -> new DoubleFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -250,7 +260,13 @@ public class DoubleScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTe
} }
} }
}; };
case "add_param" -> (fieldName, params, lookup) -> (ctx) -> new DoubleFieldScript(fieldName, params, lookup, ctx) { case "add_param" -> (fieldName, params, lookup, onScriptError) -> (ctx) -> new DoubleFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -258,16 +274,24 @@ public class DoubleScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTe
} }
} }
}; };
case "loop" -> (fieldName, params, lookup) -> { case "loop" -> (fieldName, params, lookup, onScriptError) -> {
// Indicate that this script wants the field call "test", which *is* the name of this field // Indicate that this script wants the field call "test", which *is* the name of this field
lookup.forkAndTrackFieldReferences("test"); lookup.forkAndTrackFieldReferences("test");
throw new IllegalStateException("shoud have thrown on the line above"); throw new IllegalStateException("should have thrown on the line above");
};
case "error" -> (fieldName, params, lookup, onScriptError) -> ctx -> new DoubleFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override
public void execute() {
throw new RuntimeException("test error");
}
}; };
default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]"); default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]");
}; };
} }
private static DoubleScriptFieldType build(Script script) {
return new DoubleScriptFieldType("test", factory(script), script, emptyMap());
}
} }

View file

@ -21,11 +21,16 @@ public class DoubleScriptMapperTests extends MapperScriptTestCase<DoubleFieldScr
private static DoubleFieldScript.Factory factory(Consumer<DoubleFieldScript> executor) { private static DoubleFieldScript.Factory factory(Consumer<DoubleFieldScript> executor) {
return new DoubleFieldScript.Factory() { return new DoubleFieldScript.Factory() {
@Override @Override
public DoubleFieldScript.LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup) { public DoubleFieldScript.LeafFactory newFactory(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError
) {
return new DoubleFieldScript.LeafFactory() { return new DoubleFieldScript.LeafFactory() {
@Override @Override
public DoubleFieldScript newInstance(LeafReaderContext ctx) { public DoubleFieldScript newInstance(LeafReaderContext ctx) {
return new DoubleFieldScript(fieldName, params, searchLookup, ctx) { return new DoubleFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
executor.accept(this); executor.accept(this);

View file

@ -26,10 +26,11 @@ import java.util.Map;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class GeoPointFieldScriptTests extends FieldScriptTestCase<GeoPointFieldScript.Factory> { public class GeoPointFieldScriptTests extends FieldScriptTestCase<GeoPointFieldScript.Factory> {
public static final GeoPointFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new GeoPointFieldScript( public static final GeoPointFieldScript.Factory DUMMY = (fieldName, params, lookup, onScriptError) -> ctx -> new GeoPointFieldScript(
fieldName, fieldName,
params, params,
lookup, lookup,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -61,6 +62,7 @@ public class GeoPointFieldScriptTests extends FieldScriptTestCase<GeoPointFieldS
"test", "test",
Map.of(), Map.of(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override

View file

@ -64,7 +64,7 @@ public class GeoPointScriptFieldTypeTests extends AbstractNonTextScriptFieldType
List<Object> results = new ArrayList<>(); List<Object> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
GeoPointScriptFieldType ft = build("fromLatLon", Map.of()); GeoPointScriptFieldType ft = build("fromLatLon", Map.of(), OnScriptError.FAIL);
GeoPointScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null); GeoPointScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null);
searcher.search(new MatchAllDocsQuery(), new Collector() { searcher.search(new MatchAllDocsQuery(), new Collector() {
@Override @Override
@ -213,12 +213,12 @@ public class GeoPointScriptFieldTypeTests extends AbstractNonTextScriptFieldType
@Override @Override
protected GeoPointScriptFieldType simpleMappedFieldType() { protected GeoPointScriptFieldType simpleMappedFieldType() {
return build("fromLatLon", Map.of()); return build("fromLatLon", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
protected MappedFieldType loopFieldType() { protected MappedFieldType loopFieldType() {
return build("loop", Map.of()); return build("loop", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
@ -226,29 +226,44 @@ public class GeoPointScriptFieldTypeTests extends AbstractNonTextScriptFieldType
return "geo_point"; return "geo_point";
} }
private static GeoPointScriptFieldType build(String code, Map<String, Object> params) { protected GeoPointScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
return build(new Script(ScriptType.INLINE, "test", code, params)); Script script = new Script(ScriptType.INLINE, "test", code, params);
return new GeoPointScriptFieldType("test", factory(script), script, emptyMap(), onScriptError);
} }
private static GeoPointFieldScript.Factory factory(Script script) { private static GeoPointFieldScript.Factory factory(Script script) {
return switch (script.getIdOrCode()) { return switch (script.getIdOrCode()) {
case "fromLatLon" -> (fieldName, params, lookup) -> (ctx) -> new GeoPointFieldScript(fieldName, params, lookup, ctx) { case "fromLatLon" -> (fieldName, params, lookup, onScriptError) -> (ctx) -> new GeoPointFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override @Override
public void execute() { public void execute() {
Map<?, ?> foo = (Map<?, ?>) lookup.source().source().get("foo"); Map<?, ?> foo = (Map<?, ?>) lookup.source().source().get("foo");
emit(((Number) foo.get("lat")).doubleValue(), ((Number) foo.get("lon")).doubleValue()); emit(((Number) foo.get("lat")).doubleValue(), ((Number) foo.get("lon")).doubleValue());
} }
}; };
case "loop" -> (fieldName, params, lookup) -> { case "loop" -> (fieldName, params, lookup, onScriptError) -> {
// Indicate that this script wants the field call "test", which *is* the name of this field // Indicate that this script wants the field call "test", which *is* the name of this field
lookup.forkAndTrackFieldReferences("test"); lookup.forkAndTrackFieldReferences("test");
throw new IllegalStateException("shoud have thrown on the line above"); throw new IllegalStateException("should have thrown on the line above");
};
case "error" -> (fieldName, params, lookup, onScriptError) -> ctx -> new GeoPointFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override
public void execute() {
throw new RuntimeException("test error");
}
}; };
default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]"); default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]");
}; };
} }
private static GeoPointScriptFieldType build(Script script) {
return new GeoPointScriptFieldType("test", factory(script), script, emptyMap());
}
} }

View file

@ -21,11 +21,16 @@ public class GeoPointScriptMapperTests extends MapperScriptTestCase<GeoPointFiel
private static GeoPointFieldScript.Factory factory(Consumer<GeoPointFieldScript.Emit> executor) { private static GeoPointFieldScript.Factory factory(Consumer<GeoPointFieldScript.Emit> executor) {
return new GeoPointFieldScript.Factory() { return new GeoPointFieldScript.Factory() {
@Override @Override
public GeoPointFieldScript.LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup) { public GeoPointFieldScript.LeafFactory newFactory(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError
) {
return new GeoPointFieldScript.LeafFactory() { return new GeoPointFieldScript.LeafFactory() {
@Override @Override
public GeoPointFieldScript newInstance(LeafReaderContext ctx) { public GeoPointFieldScript newInstance(LeafReaderContext ctx) {
return new GeoPointFieldScript(fieldName, params, searchLookup, ctx) { return new GeoPointFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
executor.accept(new Emit(this)); executor.accept(new Emit(this));

View file

@ -128,7 +128,7 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T> T compileScript(Script script, ScriptContext<T> context) { protected <T> T compileScript(Script script, ScriptContext<T> context) {
if (context.factoryClazz == LongFieldScript.Factory.class) { if (context.factoryClazz == LongFieldScript.Factory.class) {
return (T) (LongFieldScript.Factory) (n, p, l) -> ctx -> new TestLongFieldScript( return (T) (LongFieldScript.Factory) (n, p, l, onScriptError) -> ctx -> new TestLongFieldScript(
n, n,
p, p,
l, l,
@ -137,7 +137,7 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
); );
} }
if (context.factoryClazz == DoubleFieldScript.Factory.class) { if (context.factoryClazz == DoubleFieldScript.Factory.class) {
return (T) (DoubleFieldScript.Factory) (n, p, l) -> ctx -> new TestDoubleFieldScript( return (T) (DoubleFieldScript.Factory) (n, p, l, onScriptError) -> ctx -> new TestDoubleFieldScript(
n, n,
p, p,
l, l,
@ -195,7 +195,7 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
LeafReaderContext ctx, LeafReaderContext ctx,
Consumer<TestLongFieldScript> executor Consumer<TestLongFieldScript> executor
) { ) {
super(fieldName, params, searchLookup, ctx); super(fieldName, params, searchLookup, OnScriptError.FAIL, ctx);
this.executor = executor; this.executor = executor;
} }
@ -224,7 +224,7 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
LeafReaderContext ctx, LeafReaderContext ctx,
Consumer<TestDoubleFieldScript> executor Consumer<TestDoubleFieldScript> executor
) { ) {
super(fieldName, params, searchLookup, ctx); super(fieldName, params, searchLookup, OnScriptError.FAIL, ctx);
this.executor = executor; this.executor = executor;
} }

View file

@ -388,7 +388,13 @@ public class IpFieldMapperTests extends MapperTestCase {
return new IngestScriptSupport() { return new IngestScriptSupport() {
@Override @Override
protected IpFieldScript.Factory emptyFieldScript() { protected IpFieldScript.Factory emptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new IpFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new IpFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() {} public void execute() {}
}; };
@ -396,7 +402,13 @@ public class IpFieldMapperTests extends MapperTestCase {
@Override @Override
protected IpFieldScript.Factory nonEmptyFieldScript() { protected IpFieldScript.Factory nonEmptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new IpFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new IpFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit("192.168.0.1"); emit("192.168.0.1");

View file

@ -32,10 +32,11 @@ import java.util.Map;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class IpFieldScriptTests extends FieldScriptTestCase<IpFieldScript.Factory> { public class IpFieldScriptTests extends FieldScriptTestCase<IpFieldScript.Factory> {
public static final IpFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new IpFieldScript( public static final IpFieldScript.Factory DUMMY = (fieldName, params, lookup, onScriptError) -> ctx -> new IpFieldScript(
fieldName, fieldName,
params, params,
lookup, lookup,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -67,6 +68,7 @@ public class IpFieldScriptTests extends FieldScriptTestCase<IpFieldScript.Factor
"test", "test",
Map.of(), Map.of(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override
@ -101,7 +103,8 @@ public class IpFieldScriptTests extends FieldScriptTestCase<IpFieldScript.Factor
IpFieldScript.LeafFactory leafFactory = fromSource().newFactory( IpFieldScript.LeafFactory leafFactory = fromSource().newFactory(
"field", "field",
Collections.emptyMap(), Collections.emptyMap(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()) new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL
); );
IpFieldScript ipFieldScript = leafFactory.newInstance(reader.leaves().get(0)); IpFieldScript ipFieldScript = leafFactory.newInstance(reader.leaves().get(0));
List<InetAddress> results = new ArrayList<>(); List<InetAddress> results = new ArrayList<>();

View file

@ -66,7 +66,7 @@ public class IpScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase {
List<Object> results = new ArrayList<>(); List<Object> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
IpScriptFieldType ft = build("append_param", Map.of("param", ".1")); IpScriptFieldType ft = build("append_param", Map.of("param", ".1"), OnScriptError.FAIL);
BinaryScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null); BinaryScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null);
DocValueFormat format = ft.docValueFormat(null, null); DocValueFormat format = ft.docValueFormat(null, null);
searcher.search(new MatchAllDocsQuery(), new Collector() { searcher.search(new MatchAllDocsQuery(), new Collector() {
@ -198,7 +198,7 @@ public class IpScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase {
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [\"200.0.0\"]}")))); iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [\"200.0.0\"]}"))));
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
IpScriptFieldType fieldType = build("append_param", Map.of("param", ".1")); IpScriptFieldType fieldType = build("append_param", Map.of("param", ".1"), OnScriptError.FAIL);
assertThat(searcher.count(fieldType.termQuery("192.168.0.1", mockContext())), equalTo(1)); assertThat(searcher.count(fieldType.termQuery("192.168.0.1", mockContext())), equalTo(1));
assertThat(searcher.count(fieldType.termQuery("192.168.0.7", mockContext())), equalTo(0)); assertThat(searcher.count(fieldType.termQuery("192.168.0.7", mockContext())), equalTo(0));
assertThat(searcher.count(fieldType.termQuery("192.168.0.0/16", mockContext())), equalTo(2)); assertThat(searcher.count(fieldType.termQuery("192.168.0.0/16", mockContext())), equalTo(2));
@ -240,12 +240,12 @@ public class IpScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase {
@Override @Override
protected IpScriptFieldType simpleMappedFieldType() { protected IpScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of()); return build("read_foo", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
protected MappedFieldType loopFieldType() { protected MappedFieldType loopFieldType() {
return build("loop", Map.of()); return build("loop", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
@ -253,13 +253,20 @@ public class IpScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase {
return "ip"; return "ip";
} }
private static IpScriptFieldType build(String code, Map<String, Object> params) { protected IpScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
return build(new Script(ScriptType.INLINE, "test", code, params)); Script script = new Script(ScriptType.INLINE, "test", code, params);
return new IpScriptFieldType("test", factory(script), script, emptyMap(), onScriptError);
} }
private static IpFieldScript.Factory factory(Script script) { private static IpFieldScript.Factory factory(Script script) {
return switch (script.getIdOrCode()) { return switch (script.getIdOrCode()) {
case "read_foo" -> (fieldName, params, lookup) -> (ctx) -> new IpFieldScript(fieldName, params, lookup, ctx) { case "read_foo" -> (fieldName, params, lookup, onScriptError) -> (ctx) -> new IpFieldScript(
fieldName,
params,
lookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -267,7 +274,13 @@ public class IpScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase {
} }
} }
}; };
case "append_param" -> (fieldName, params, lookup) -> (ctx) -> new IpFieldScript(fieldName, params, lookup, ctx) { case "append_param" -> (fieldName, params, lookup, onScriptError) -> (ctx) -> new IpFieldScript(
fieldName,
params,
lookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -275,16 +288,24 @@ public class IpScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase {
} }
} }
}; };
case "loop" -> (fieldName, params, lookup) -> { case "loop" -> (fieldName, params, lookup, onScriptError) -> {
// Indicate that this script wants the field call "test", which *is* the name of this field // Indicate that this script wants the field call "test", which *is* the name of this field
lookup.forkAndTrackFieldReferences("test"); lookup.forkAndTrackFieldReferences("test");
throw new IllegalStateException("shoud have thrown on the line above"); throw new IllegalStateException("should have thrown on the line above");
};
case "error" -> (fieldName, params, lookup, onScriptError) -> ctx -> new IpFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override
public void execute() {
throw new RuntimeException("test error");
}
}; };
default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]"); default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]");
}; };
} }
private static IpScriptFieldType build(Script script) {
return new IpScriptFieldType("test", factory(script), script, emptyMap());
}
} }

View file

@ -21,11 +21,16 @@ public class IpScriptMapperTests extends MapperScriptTestCase<IpFieldScript.Fact
private static IpFieldScript.Factory factory(Consumer<IpFieldScript> executor) { private static IpFieldScript.Factory factory(Consumer<IpFieldScript> executor) {
return new IpFieldScript.Factory() { return new IpFieldScript.Factory() {
@Override @Override
public IpFieldScript.LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup) { public IpFieldScript.LeafFactory newFactory(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError
) {
return new IpFieldScript.LeafFactory() { return new IpFieldScript.LeafFactory() {
@Override @Override
public IpFieldScript newInstance(LeafReaderContext ctx) { public IpFieldScript newInstance(LeafReaderContext ctx) {
return new IpFieldScript(fieldName, params, searchLookup, ctx) { return new IpFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
executor.accept(this); executor.accept(this);

View file

@ -729,7 +729,13 @@ public class KeywordFieldMapperTests extends MapperTestCase {
return new IngestScriptSupport() { return new IngestScriptSupport() {
@Override @Override
protected StringFieldScript.Factory emptyFieldScript() { protected StringFieldScript.Factory emptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new StringFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new StringFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() {} public void execute() {}
}; };
@ -737,7 +743,13 @@ public class KeywordFieldMapperTests extends MapperTestCase {
@Override @Override
protected StringFieldScript.Factory nonEmptyFieldScript() { protected StringFieldScript.Factory nonEmptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new StringFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new StringFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit("foo"); emit("foo");

View file

@ -60,7 +60,7 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
List<String> results = new ArrayList<>(); List<String> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
KeywordScriptFieldType ft = build("append_param", Map.of("param", "-suffix")); KeywordScriptFieldType ft = build("append_param", Map.of("param", "-suffix"), OnScriptError.FAIL);
StringScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null); StringScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null);
searcher.search(new MatchAllDocsQuery(), new Collector() { searcher.search(new MatchAllDocsQuery(), new Collector() {
@Override @Override
@ -287,7 +287,7 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [2]}")))); iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [2]}"))));
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
KeywordScriptFieldType fieldType = build("append_param", Map.of("param", "-suffix")); KeywordScriptFieldType fieldType = build("append_param", Map.of("param", "-suffix"), OnScriptError.FAIL);
assertThat(searcher.count(fieldType.termQuery("1-suffix", mockContext())), equalTo(1)); assertThat(searcher.count(fieldType.termQuery("1-suffix", mockContext())), equalTo(1));
} }
} }
@ -299,7 +299,7 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [2]}")))); iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [2]}"))));
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
KeywordScriptFieldType fieldType = build("append_param", Map.of("param", "-suffix")); KeywordScriptFieldType fieldType = build("append_param", Map.of("param", "-suffix"), OnScriptError.FAIL);
expectThrows( expectThrows(
IllegalArgumentException.class, IllegalArgumentException.class,
() -> { () -> {
@ -375,7 +375,7 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [2]}")))); iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [2]}"))));
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
KeywordScriptFieldType fieldType = build("append_param", Map.of("param", "-Suffix")); KeywordScriptFieldType fieldType = build("append_param", Map.of("param", "-Suffix"), OnScriptError.FAIL);
SearchExecutionContext searchExecutionContext = mockContext(true, fieldType); SearchExecutionContext searchExecutionContext = mockContext(true, fieldType);
Query query = new MatchQueryBuilder("test", "1-Suffix").toQuery(searchExecutionContext); Query query = new MatchQueryBuilder("test", "1-Suffix").toQuery(searchExecutionContext);
assertThat(searcher.count(query), equalTo(1)); assertThat(searcher.count(query), equalTo(1));
@ -385,12 +385,12 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
@Override @Override
protected KeywordScriptFieldType simpleMappedFieldType() { protected KeywordScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of()); return build("read_foo", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
protected KeywordScriptFieldType loopFieldType() { protected KeywordScriptFieldType loopFieldType() {
return build("loop", Map.of()); return build("loop", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
@ -398,13 +398,20 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
return "keyword"; return "keyword";
} }
private static KeywordScriptFieldType build(String code, Map<String, Object> params) { protected KeywordScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
return build(new Script(ScriptType.INLINE, "test", code, params)); Script script = new Script(ScriptType.INLINE, "test", code, params);
return new KeywordScriptFieldType("test", factory(script), script, emptyMap(), onScriptError);
} }
private static StringFieldScript.Factory factory(Script script) { private static StringFieldScript.Factory factory(Script script) {
return switch (script.getIdOrCode()) { return switch (script.getIdOrCode()) {
case "read_foo" -> (fieldName, params, lookup) -> ctx -> new StringFieldScript(fieldName, params, lookup, ctx) { case "read_foo" -> (fieldName, params, lookup, onScriptError) -> ctx -> new StringFieldScript(
fieldName,
params,
lookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -412,7 +419,13 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
} }
} }
}; };
case "append_param" -> (fieldName, params, lookup) -> ctx -> new StringFieldScript(fieldName, params, lookup, ctx) { case "append_param" -> (fieldName, params, lookup, onScriptError) -> ctx -> new StringFieldScript(
fieldName,
params,
lookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -420,16 +433,24 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
} }
} }
}; };
case "loop" -> (fieldName, params, lookup) -> { case "loop" -> (fieldName, params, lookup, onScriptError) -> {
// Indicate that this script wants the field call "test", which *is* the name of this field // Indicate that this script wants the field call "test", which *is* the name of this field
lookup.forkAndTrackFieldReferences("test"); lookup.forkAndTrackFieldReferences("test");
throw new IllegalStateException("shoud have thrown on the line above"); throw new IllegalStateException("should have thrown on the line above");
};
case "error" -> (fieldName, params, lookup, onScriptError) -> ctx -> new StringFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override
public void execute() {
throw new RuntimeException("test error");
}
}; };
default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]"); default -> throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]");
}; };
} }
private static KeywordScriptFieldType build(Script script) {
return new KeywordScriptFieldType("test", factory(script), script, emptyMap());
}
} }

View file

@ -22,11 +22,16 @@ public class KeywordScriptMapperTests extends MapperScriptTestCase<StringFieldSc
private static StringFieldScript.Factory factory(Consumer<StringFieldScript> executor) { private static StringFieldScript.Factory factory(Consumer<StringFieldScript> executor) {
return new StringFieldScript.Factory() { return new StringFieldScript.Factory() {
@Override @Override
public StringFieldScript.LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup) { public StringFieldScript.LeafFactory newFactory(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError
) {
return new StringFieldScript.LeafFactory() { return new StringFieldScript.LeafFactory() {
@Override @Override
public StringFieldScript newInstance(LeafReaderContext ctx) { public StringFieldScript newInstance(LeafReaderContext ctx) {
return new StringFieldScript(fieldName, params, searchLookup, ctx) { return new StringFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
executor.accept(this); executor.accept(this);

View file

@ -132,7 +132,13 @@ public class LongFieldMapperTests extends WholeNumberFieldMapperTests {
@Override @Override
protected LongFieldScript.Factory emptyFieldScript() { protected LongFieldScript.Factory emptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new LongFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new LongFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() {} public void execute() {}
}; };
@ -140,7 +146,13 @@ public class LongFieldMapperTests extends WholeNumberFieldMapperTests {
@Override @Override
protected LongFieldScript.Factory nonEmptyFieldScript() { protected LongFieldScript.Factory nonEmptyFieldScript() {
return (fieldName, params, searchLookup) -> ctx -> new LongFieldScript(fieldName, params, searchLookup, ctx) { return (fieldName, params, searchLookup, onScriptError) -> ctx -> new LongFieldScript(
fieldName,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit(1); emit(1);

View file

@ -31,10 +31,11 @@ import java.util.Map;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class LongFieldScriptTests extends FieldScriptTestCase<LongFieldScript.Factory> { public class LongFieldScriptTests extends FieldScriptTestCase<LongFieldScript.Factory> {
public static final LongFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new LongFieldScript( public static final LongFieldScript.Factory DUMMY = (fieldName, params, lookup, onScriptError) -> ctx -> new LongFieldScript(
fieldName, fieldName,
params, params,
lookup, lookup,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -66,6 +67,7 @@ public class LongFieldScriptTests extends FieldScriptTestCase<LongFieldScript.Fa
"test", "test",
Map.of(), Map.of(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override
@ -100,7 +102,8 @@ public class LongFieldScriptTests extends FieldScriptTestCase<LongFieldScript.Fa
LongFieldScript.LeafFactory leafFactory = fromSource().newFactory( LongFieldScript.LeafFactory leafFactory = fromSource().newFactory(
"field", "field",
Collections.emptyMap(), Collections.emptyMap(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()) new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL
); );
LongFieldScript longFieldScript = leafFactory.newInstance(reader.leaves().get(0)); LongFieldScript longFieldScript = leafFactory.newInstance(reader.leaves().get(0));
List<Long> results = new ArrayList<>(); List<Long> results = new ArrayList<>();

View file

@ -76,7 +76,7 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
List<Long> results = new ArrayList<>(); List<Long> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
LongScriptFieldType ft = build("add_param", Map.of("param", 1)); LongScriptFieldType ft = build("add_param", Map.of("param", 1), OnScriptError.FAIL);
LongScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null); LongScriptFieldData ifd = ft.fielddataBuilder(mockFielddataContext()).build(null, null);
searcher.search(new MatchAllDocsQuery(), new Collector() { searcher.search(new MatchAllDocsQuery(), new Collector() {
@Override @Override
@ -132,7 +132,8 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"timestamp\": [1595432181356]}")))); iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"timestamp\": [1595432181356]}"))));
try (DirectoryReader reader = iw.getReader()) { try (DirectoryReader reader = iw.getReader()) {
IndexSearcher searcher = newUnthreadedSearcher(reader); IndexSearcher searcher = newUnthreadedSearcher(reader);
LongScriptFieldData ifd = build("millis_ago", Map.of()).fielddataBuilder(mockFielddataContext()).build(null, null); LongScriptFieldData ifd = build("millis_ago", Map.of(), OnScriptError.FAIL).fielddataBuilder(mockFielddataContext())
.build(null, null);
SortField sf = ifd.sortField(null, MultiValueMode.MIN, null, false); SortField sf = ifd.sortField(null, MultiValueMode.MIN, null, false);
TopFieldDocs docs = searcher.search(new MatchAllDocsQuery(), 3, new Sort(sf)); TopFieldDocs docs = searcher.search(new MatchAllDocsQuery(), 3, new Sort(sf));
assertThat(readSource(reader, docs.scoreDocs[0].doc), equalTo("{\"timestamp\": [1595432181356]}")); assertThat(readSource(reader, docs.scoreDocs[0].doc), equalTo("{\"timestamp\": [1595432181356]}"));
@ -222,7 +223,10 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
assertThat(searcher.count(simpleMappedFieldType().termQuery("1", mockContext())), equalTo(1)); assertThat(searcher.count(simpleMappedFieldType().termQuery("1", mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(1, mockContext())), equalTo(1)); assertThat(searcher.count(simpleMappedFieldType().termQuery(1, mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(1.1, mockContext())), equalTo(0)); assertThat(searcher.count(simpleMappedFieldType().termQuery(1.1, mockContext())), equalTo(0));
assertThat(searcher.count(build("add_param", Map.of("param", 1)).termQuery(2, mockContext())), equalTo(1)); assertThat(
searcher.count(build("add_param", Map.of("param", 1), OnScriptError.FAIL).termQuery(2, mockContext())),
equalTo(1)
);
} }
} }
} }
@ -255,12 +259,12 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
@Override @Override
protected LongScriptFieldType simpleMappedFieldType() { protected LongScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of()); return build("read_foo", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
protected LongScriptFieldType loopFieldType() { protected LongScriptFieldType loopFieldType() {
return build("loop", Map.of()); return build("loop", Map.of(), OnScriptError.FAIL);
} }
@Override @Override
@ -268,14 +272,21 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
return "long"; return "long";
} }
private static LongScriptFieldType build(String code, Map<String, Object> params) { protected LongScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
return build(new Script(ScriptType.INLINE, "test", code, params)); Script script = new Script(ScriptType.INLINE, "test", code, params);
return new LongScriptFieldType("test", factory(script), script, emptyMap(), onScriptError);
} }
private static LongFieldScript.Factory factory(Script script) { private static LongFieldScript.Factory factory(Script script) {
switch (script.getIdOrCode()) { switch (script.getIdOrCode()) {
case "read_foo": case "read_foo":
return (fieldName, params, lookup) -> (ctx) -> new LongFieldScript(fieldName, params, lookup, ctx) { return (fieldName, params, lookup, onScriptError) -> (ctx) -> new LongFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -284,7 +295,13 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
} }
}; };
case "add_param": case "add_param":
return (fieldName, params, lookup) -> (ctx) -> new LongFieldScript(fieldName, params, lookup, ctx) { return (fieldName, params, lookup, onScriptError) -> (ctx) -> new LongFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) { for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -295,7 +312,13 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
case "millis_ago": case "millis_ago":
// Painless actually call System.currentTimeMillis. We could mock the time but this works fine too. // Painless actually call System.currentTimeMillis. We could mock the time but this works fine too.
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
return (fieldName, params, lookup) -> (ctx) -> new LongFieldScript(fieldName, params, lookup, ctx) { return (fieldName, params, lookup, onScriptError) -> (ctx) -> new LongFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override @Override
public void execute() { public void execute() {
for (Object timestamp : (List<?>) lookup.source().source().get("timestamp")) { for (Object timestamp : (List<?>) lookup.source().source().get("timestamp")) {
@ -304,17 +327,26 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
} }
}; };
case "loop": case "loop":
return (fieldName, params, lookup) -> { return (fieldName, params, lookup, onScriptError) -> {
// Indicate that this script wants the field call "test", which *is* the name of this field // Indicate that this script wants the field call "test", which *is* the name of this field
lookup.forkAndTrackFieldReferences("test"); lookup.forkAndTrackFieldReferences("test");
throw new IllegalStateException("shoud have thrown on the line above"); throw new IllegalStateException("should have thrown on the line above");
};
case "error":
return (fieldName, params, lookup, onScriptError) -> ctx -> new LongFieldScript(
fieldName,
params,
lookup,
onScriptError,
ctx
) {
@Override
public void execute() {
throw new RuntimeException("test error");
}
}; };
default: default:
throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]"); throw new IllegalArgumentException("unsupported script [" + script.getIdOrCode() + "]");
} }
} }
private static LongScriptFieldType build(Script script) {
return new LongScriptFieldType("test", factory(script), script, emptyMap());
}
} }

View file

@ -21,11 +21,16 @@ public class LongScriptMapperTests extends MapperScriptTestCase<LongFieldScript.
private static LongFieldScript.Factory factory(Consumer<LongFieldScript> executor) { private static LongFieldScript.Factory factory(Consumer<LongFieldScript> executor) {
return new LongFieldScript.Factory() { return new LongFieldScript.Factory() {
@Override @Override
public LongFieldScript.LeafFactory newFactory(String fieldName, Map<String, Object> params, SearchLookup searchLookup) { public LongFieldScript.LeafFactory newFactory(
String fieldName,
Map<String, Object> params,
SearchLookup searchLookup,
OnScriptError onScriptError
) {
return new LongFieldScript.LeafFactory() { return new LongFieldScript.LeafFactory() {
@Override @Override
public LongFieldScript newInstance(LeafReaderContext ctx) { public LongFieldScript newInstance(LeafReaderContext ctx) {
return new LongFieldScript(fieldName, params, searchLookup, ctx) { return new LongFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
executor.accept(this); executor.accept(this);

View file

@ -30,10 +30,11 @@ import java.util.Map;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class StringFieldScriptTests extends FieldScriptTestCase<StringFieldScript.Factory> { public class StringFieldScriptTests extends FieldScriptTestCase<StringFieldScript.Factory> {
public static final StringFieldScript.Factory DUMMY = (fieldName, params, lookup) -> ctx -> new StringFieldScript( public static final StringFieldScript.Factory DUMMY = (fieldName, params, lookup, onScriptError) -> ctx -> new StringFieldScript(
fieldName, fieldName,
params, params,
lookup, lookup,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -65,6 +66,7 @@ public class StringFieldScriptTests extends FieldScriptTestCase<StringFieldScrip
"test", "test",
Map.of(), Map.of(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override
@ -91,6 +93,7 @@ public class StringFieldScriptTests extends FieldScriptTestCase<StringFieldScrip
"test", "test",
Map.of(), Map.of(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override
@ -130,7 +133,8 @@ public class StringFieldScriptTests extends FieldScriptTestCase<StringFieldScrip
StringFieldScript.LeafFactory leafFactory = fromSource().newFactory( StringFieldScript.LeafFactory leafFactory = fromSource().newFactory(
"field", "field",
Collections.emptyMap(), Collections.emptyMap(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()) new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL
); );
StringFieldScript stringFieldScript = leafFactory.newInstance(reader.leaves().get(0)); StringFieldScript stringFieldScript = leafFactory.newInstance(reader.leaves().get(0));
stringFieldScript.runForDoc(0); stringFieldScript.runForDoc(0);
@ -159,7 +163,8 @@ public class StringFieldScriptTests extends FieldScriptTestCase<StringFieldScrip
StringFieldScript.LeafFactory leafFactory = fromSource().newFactory( StringFieldScript.LeafFactory leafFactory = fromSource().newFactory(
"field", "field",
Collections.emptyMap(), Collections.emptyMap(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()) new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL
); );
StringFieldScript stringFieldScript = leafFactory.newInstance(reader.leaves().get(0)); StringFieldScript stringFieldScript = leafFactory.newInstance(reader.leaves().get(0));
stringFieldScript.runForDoc(0); stringFieldScript.runForDoc(0);

View file

@ -13,6 +13,7 @@ import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.tests.index.RandomIndexWriter; import org.apache.lucene.tests.index.RandomIndexWriter;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.search.lookup.SourceLookup; import org.elasticsearch.search.lookup.SourceLookup;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
@ -33,6 +34,7 @@ public class CompositeFieldScriptTests extends ESTestCase {
"composite", "composite",
Collections.emptyMap(), Collections.emptyMap(),
new SearchLookup(field -> null, (ft, lookup, ftd) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, ftd) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override
@ -64,6 +66,7 @@ public class CompositeFieldScriptTests extends ESTestCase {
"composite", "composite",
Collections.emptyMap(), Collections.emptyMap(),
new SearchLookup(field -> null, (ft, lookup, ftd) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, ftd) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override
@ -77,6 +80,7 @@ public class CompositeFieldScriptTests extends ESTestCase {
"composite.leaf", "composite.leaf",
Collections.emptyMap(), Collections.emptyMap(),
new SearchLookup(field -> null, (ft, lookup, ftd) -> null, new SourceLookup.ReaderSourceProvider()), new SearchLookup(field -> null, (ft, lookup, ftd) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0) reader.leaves().get(0)
) { ) {
@Override @Override

View file

@ -27,6 +27,7 @@ import org.elasticsearch.index.mapper.LuceneDocument;
import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType; import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.script.LongFieldScript; import org.elasticsearch.script.LongFieldScript;
import org.elasticsearch.script.Script; import org.elasticsearch.script.Script;
import org.elasticsearch.script.StringFieldScript; import org.elasticsearch.script.StringFieldScript;
@ -599,7 +600,7 @@ public class RangeAggregatorTests extends AggregatorTestCase {
public void testRuntimeFieldTopLevelQueryNotOptimized() throws IOException { public void testRuntimeFieldTopLevelQueryNotOptimized() throws IOException {
long totalDocs = (long) RangeAggregator.DOCS_PER_RANGE_TO_USE_FILTERS * 4; long totalDocs = (long) RangeAggregator.DOCS_PER_RANGE_TO_USE_FILTERS * 4;
SearchLookup lookup = new SearchLookup(s -> null, (ft, l, ftd) -> null, new SourceLookup.ReaderSourceProvider()); SearchLookup lookup = new SearchLookup(s -> null, (ft, l, ftd) -> null, new SourceLookup.ReaderSourceProvider());
StringFieldScript.LeafFactory scriptFactory = ctx -> new StringFieldScript("dummy", Map.of(), lookup, ctx) { StringFieldScript.LeafFactory scriptFactory = ctx -> new StringFieldScript("dummy", Map.of(), lookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emit("cat"); emit("cat");
@ -641,13 +642,19 @@ public class RangeAggregatorTests extends AggregatorTestCase {
*/ */
public void testRuntimeFieldRangesNotOptimized() throws IOException { public void testRuntimeFieldRangesNotOptimized() throws IOException {
long totalDocs = (long) RangeAggregator.DOCS_PER_RANGE_TO_USE_FILTERS * 4; long totalDocs = (long) RangeAggregator.DOCS_PER_RANGE_TO_USE_FILTERS * 4;
LongFieldScript.Factory scriptFactory = (fieldName, params, l) -> ctx -> new LongFieldScript(fieldName, Map.of(), l, ctx) { LongFieldScript.Factory scriptFactory = (fieldName, params, l, onScriptError) -> ctx -> new LongFieldScript(
fieldName,
Map.of(),
l,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit((long) getDoc().get(NUMBER_FIELD_NAME).get(0)); emit((long) getDoc().get(NUMBER_FIELD_NAME).get(0));
} }
}; };
MappedFieldType dummyFt = new LongScriptFieldType("dummy", scriptFactory, new Script("test"), Map.of()); MappedFieldType dummyFt = new LongScriptFieldType("dummy", scriptFactory, new Script("test"), Map.of(), OnScriptError.FAIL);
MappedFieldType numberFt = new NumberFieldMapper.NumberFieldType(NUMBER_FIELD_NAME, NumberFieldMapper.NumberType.INTEGER); MappedFieldType numberFt = new NumberFieldMapper.NumberFieldType(NUMBER_FIELD_NAME, NumberFieldMapper.NumberType.INTEGER);
debugTestCase( debugTestCase(
new RangeAggregationBuilder("r").field("dummy").addRange(0, 1).addRange(1, 2).addRange(2, 3), new RangeAggregationBuilder("r").field("dummy").addRange(0, 1).addRange(1, 2).addRange(2, 3),

View file

@ -60,6 +60,7 @@ import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType; import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType; import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.index.mapper.ObjectMapper;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.index.mapper.ProvidedIdFieldMapper; import org.elasticsearch.index.mapper.ProvidedIdFieldMapper;
import org.elasticsearch.index.mapper.RangeFieldMapper; import org.elasticsearch.index.mapper.RangeFieldMapper;
import org.elasticsearch.index.mapper.RangeType; import org.elasticsearch.index.mapper.RangeType;
@ -1994,7 +1995,7 @@ public class TermsAggregatorTests extends AggregatorTestCase {
public void testRuntimeFieldTopLevelNotOptimized() throws IOException { public void testRuntimeFieldTopLevelNotOptimized() throws IOException {
long totalDocs = 500; long totalDocs = 500;
SearchLookup lookup = new SearchLookup(s -> null, (ft, l, ftd) -> null, new SourceLookup.ReaderSourceProvider()); SearchLookup lookup = new SearchLookup(s -> null, (ft, l, ftd) -> null, new SourceLookup.ReaderSourceProvider());
StringFieldScript.LeafFactory scriptFactory = ctx -> new StringFieldScript("dummy", Map.of(), lookup, ctx) { StringFieldScript.LeafFactory scriptFactory = ctx -> new StringFieldScript("dummy", Map.of(), lookup, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emit("cat"); emit("cat");
@ -2043,10 +2044,11 @@ public class TermsAggregatorTests extends AggregatorTestCase {
*/ */
public void testRuntimeFieldTermsNotOptimized() throws IOException { public void testRuntimeFieldTermsNotOptimized() throws IOException {
long totalDocs = 500; long totalDocs = 500;
StringFieldScript.Factory scriptFactory = (fieldName, params, lookup) -> ctx -> new StringFieldScript( StringFieldScript.Factory scriptFactory = (fieldName, params, lookup, onScriptError) -> ctx -> new StringFieldScript(
fieldName, fieldName,
Map.of(), Map.of(),
lookup, lookup,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override
@ -2056,7 +2058,7 @@ public class TermsAggregatorTests extends AggregatorTestCase {
}; };
BytesRef[] values = new BytesRef[] { new BytesRef("stuff"), new BytesRef("more_stuff"), new BytesRef("other_stuff"), }; BytesRef[] values = new BytesRef[] { new BytesRef("stuff"), new BytesRef("more_stuff"), new BytesRef("other_stuff"), };
MappedFieldType keywordFt = new KeywordFieldType("k", true, true, Collections.emptyMap()); MappedFieldType keywordFt = new KeywordFieldType("k", true, true, Collections.emptyMap());
MappedFieldType dummyFt = new KeywordScriptFieldType("dummy", scriptFactory, new Script("test"), Map.of()); MappedFieldType dummyFt = new KeywordScriptFieldType("dummy", scriptFactory, new Script("test"), Map.of(), OnScriptError.FAIL);
debugTestCase(new TermsAggregationBuilder("t").field("dummy"), new MatchAllDocsQuery(), iw -> { debugTestCase(new TermsAggregationBuilder("t").field("dummy"), new MatchAllDocsQuery(), iw -> {
for (int d = 0; d < totalDocs; d++) { for (int d = 0; d < totalDocs; d++) {
BytesRef value = values[d % values.length]; BytesRef value = values[d % values.length];

View file

@ -21,6 +21,7 @@ import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoUtils; import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.index.mapper.GeoPointScriptFieldType; import org.elasticsearch.index.mapper.GeoPointScriptFieldType;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.script.AbstractLongFieldScript; import org.elasticsearch.script.AbstractLongFieldScript;
import org.elasticsearch.script.GeoPointFieldScript; import org.elasticsearch.script.GeoPointFieldScript;
import org.elasticsearch.script.Script; import org.elasticsearch.script.Script;
@ -88,6 +89,7 @@ public class GeoPointScriptFieldDistanceFeatureQueryTests extends AbstractScript
"test", "test",
Map.of(), Map.of(),
searchLookup, searchLookup,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override

View file

@ -17,6 +17,7 @@ import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.tests.index.RandomIndexWriter; import org.apache.lucene.tests.index.RandomIndexWriter;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.script.AbstractLongFieldScript; import org.elasticsearch.script.AbstractLongFieldScript;
import org.elasticsearch.script.DateFieldScript; import org.elasticsearch.script.DateFieldScript;
import org.elasticsearch.script.Script; import org.elasticsearch.script.Script;
@ -75,6 +76,7 @@ public class LongScriptFieldDistanceFeatureQueryTests extends AbstractScriptFiel
Map.of(), Map.of(),
searchLookup, searchLookup,
null, null,
OnScriptError.FAIL,
ctx ctx
) { ) {
@Override @Override

View file

@ -15,6 +15,7 @@ import org.apache.lucene.search.Rescorer;
import org.apache.lucene.search.Scorable; import org.apache.lucene.search.Scorable;
import org.apache.lucene.search.SortField; import org.apache.lucene.search.SortField;
import org.elasticsearch.common.util.Maps; import org.elasticsearch.common.util.Maps;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.index.query.IntervalFilterScript; import org.elasticsearch.index.query.IntervalFilterScript;
import org.elasticsearch.index.similarity.ScriptedSimilarity.Doc; import org.elasticsearch.index.similarity.ScriptedSimilarity.Doc;
import org.elasticsearch.index.similarity.ScriptedSimilarity.Field; import org.elasticsearch.index.similarity.ScriptedSimilarity.Field;
@ -269,7 +270,13 @@ public class MockScriptEngine implements ScriptEngine {
IntervalFilterScript.Factory factory = mockCompiled::createIntervalFilterScript; IntervalFilterScript.Factory factory = mockCompiled::createIntervalFilterScript;
return context.factoryClazz.cast(factory); return context.factoryClazz.cast(factory);
} else if (context.instanceClazz.equals(BooleanFieldScript.class)) { } else if (context.instanceClazz.equals(BooleanFieldScript.class)) {
BooleanFieldScript.Factory booleanFieldScript = (f, p, s) -> ctx -> new BooleanFieldScript(f, p, s, ctx) { BooleanFieldScript.Factory booleanFieldScript = (f, p, s, onScriptError) -> ctx -> new BooleanFieldScript(
f,
p,
s,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit(true); emit(true);
@ -277,7 +284,13 @@ public class MockScriptEngine implements ScriptEngine {
}; };
return context.factoryClazz.cast(booleanFieldScript); return context.factoryClazz.cast(booleanFieldScript);
} else if (context.instanceClazz.equals(StringFieldScript.class)) { } else if (context.instanceClazz.equals(StringFieldScript.class)) {
StringFieldScript.Factory stringFieldScript = (f, p, s) -> ctx -> new StringFieldScript(f, p, s, ctx) { StringFieldScript.Factory stringFieldScript = (f, p, s, onScriptError) -> ctx -> new StringFieldScript(
f,
p,
s,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit("test"); emit("test");
@ -285,7 +298,13 @@ public class MockScriptEngine implements ScriptEngine {
}; };
return context.factoryClazz.cast(stringFieldScript); return context.factoryClazz.cast(stringFieldScript);
} else if (context.instanceClazz.equals(LongFieldScript.class)) { } else if (context.instanceClazz.equals(LongFieldScript.class)) {
LongFieldScript.Factory longFieldScript = (f, p, s) -> ctx -> new LongFieldScript(f, p, s, ctx) { LongFieldScript.Factory longFieldScript = (f, p, s, onScriptError) -> ctx -> new LongFieldScript(
f,
p,
s,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit(1L); emit(1L);
@ -293,7 +312,13 @@ public class MockScriptEngine implements ScriptEngine {
}; };
return context.factoryClazz.cast(longFieldScript); return context.factoryClazz.cast(longFieldScript);
} else if (context.instanceClazz.equals(DoubleFieldScript.class)) { } else if (context.instanceClazz.equals(DoubleFieldScript.class)) {
DoubleFieldScript.Factory doubleFieldScript = (f, p, s) -> ctx -> new DoubleFieldScript(f, p, s, ctx) { DoubleFieldScript.Factory doubleFieldScript = (f, p, s, onScriptError) -> ctx -> new DoubleFieldScript(
f,
p,
s,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit(1.2D); emit(1.2D);
@ -301,7 +326,14 @@ public class MockScriptEngine implements ScriptEngine {
}; };
return context.factoryClazz.cast(doubleFieldScript); return context.factoryClazz.cast(doubleFieldScript);
} else if (context.instanceClazz.equals(DateFieldScript.class)) { } else if (context.instanceClazz.equals(DateFieldScript.class)) {
DateFieldScript.Factory dateFieldScript = (f, p, s, formatter) -> ctx -> new DateFieldScript(f, p, s, formatter, ctx) { DateFieldScript.Factory dateFieldScript = (f, p, s, formatter, onScriptError) -> ctx -> new DateFieldScript(
f,
p,
s,
formatter,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit(123L); emit(123L);
@ -309,7 +341,7 @@ public class MockScriptEngine implements ScriptEngine {
}; };
return context.factoryClazz.cast(dateFieldScript); return context.factoryClazz.cast(dateFieldScript);
} else if (context.instanceClazz.equals(IpFieldScript.class)) { } else if (context.instanceClazz.equals(IpFieldScript.class)) {
IpFieldScript.Factory ipFieldScript = (f, p, s) -> ctx -> new IpFieldScript(f, p, s, ctx) { IpFieldScript.Factory ipFieldScript = (f, p, s, onScriptError) -> ctx -> new IpFieldScript(f, p, s, OnScriptError.FAIL, ctx) {
@Override @Override
public void execute() { public void execute() {
emit("127.0.0.1"); emit("127.0.0.1");
@ -317,7 +349,13 @@ public class MockScriptEngine implements ScriptEngine {
}; };
return context.factoryClazz.cast(ipFieldScript); return context.factoryClazz.cast(ipFieldScript);
} else if (context.instanceClazz.equals(GeoPointFieldScript.class)) { } else if (context.instanceClazz.equals(GeoPointFieldScript.class)) {
GeoPointFieldScript.Factory geoPointFieldScript = (f, p, s) -> ctx -> new GeoPointFieldScript(f, p, s, ctx) { GeoPointFieldScript.Factory geoPointFieldScript = (f, p, s, onScriptError) -> ctx -> new GeoPointFieldScript(
f,
p,
s,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit(1.2D, 1.2D); emit(1.2D, 1.2D);
@ -325,7 +363,13 @@ public class MockScriptEngine implements ScriptEngine {
}; };
return context.factoryClazz.cast(geoPointFieldScript); return context.factoryClazz.cast(geoPointFieldScript);
} else if (context.instanceClazz.equals(CompositeFieldScript.class)) { } else if (context.instanceClazz.equals(CompositeFieldScript.class)) {
CompositeFieldScript.Factory objectFieldScript = (f, p, s) -> ctx -> new CompositeFieldScript(f, p, s, ctx) { CompositeFieldScript.Factory objectFieldScript = (f, p, s, onScriptError) -> ctx -> new CompositeFieldScript(
f,
p,
s,
OnScriptError.FAIL,
ctx
) {
@Override @Override
public void execute() { public void execute() {
emit("field1", "value1"); emit("field1", "value1");