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
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]]
==== 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.mapper.DateFieldMapper;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.query.AbstractQueryBuilder;
@ -557,7 +558,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
BooleanFieldScript.LeafFactory leafFactory = factory.newFactory(
BooleanFieldScript.CONTEXT.name,
request.getScript().getParams(),
context.lookup()
context.lookup(),
OnScriptError.FAIL
);
BooleanFieldScript booleanFieldScript = leafFactory.newInstance(leafReaderContext);
List<Boolean> booleans = new ArrayList<>();
@ -571,7 +573,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
DateFieldScript.CONTEXT.name,
request.getScript().getParams(),
context.lookup(),
DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER
DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER,
OnScriptError.FAIL
);
DateFieldScript dateFieldScript = leafFactory.newInstance(leafReaderContext);
List<String> dates = new ArrayList<>();
@ -584,7 +587,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
DoubleFieldScript.LeafFactory leafFactory = factory.newFactory(
DoubleFieldScript.CONTEXT.name,
request.getScript().getParams(),
context.lookup()
context.lookup(),
OnScriptError.FAIL
);
DoubleFieldScript doubleFieldScript = leafFactory.newInstance(leafReaderContext);
List<Double> doubles = new ArrayList<>();
@ -597,7 +601,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
GeoPointFieldScript.LeafFactory leafFactory = factory.newFactory(
GeoPointFieldScript.CONTEXT.name,
request.getScript().getParams(),
context.lookup()
context.lookup(),
OnScriptError.FAIL
);
GeoPointFieldScript geoPointFieldScript = leafFactory.newInstance(leafReaderContext);
List<GeoPoint> points = new ArrayList<>();
@ -615,7 +620,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
IpFieldScript.LeafFactory leafFactory = factory.newFactory(
IpFieldScript.CONTEXT.name,
request.getScript().getParams(),
context.lookup()
context.lookup(),
OnScriptError.FAIL
);
IpFieldScript ipFieldScript = leafFactory.newInstance(leafReaderContext);
List<String> ips = new ArrayList<>();
@ -634,7 +640,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
LongFieldScript.LeafFactory leafFactory = factory.newFactory(
LongFieldScript.CONTEXT.name,
request.getScript().getParams(),
context.lookup()
context.lookup(),
OnScriptError.FAIL
);
LongFieldScript longFieldScript = leafFactory.newInstance(leafReaderContext);
List<Long> longs = new ArrayList<>();
@ -647,7 +654,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
StringFieldScript.LeafFactory leafFactory = factory.newFactory(
StringFieldScript.CONTEXT.name,
request.getScript().getParams(),
context.lookup()
context.lookup(),
OnScriptError.FAIL
);
StringFieldScript stringFieldScript = leafFactory.newInstance(leafReaderContext);
List<String> keywords = new ArrayList<>();
@ -660,7 +668,8 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
CompositeFieldScript.LeafFactory leafFactory = factory.newFactory(
CompositeFieldScript.CONTEXT.name,
request.getScript().getParams(),
context.lookup()
context.lookup(),
OnScriptError.FAIL
);
CompositeFieldScript compositeFieldScript = leafFactory.newInstance(leafReaderContext);
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 {
private final ScriptContext<Factory> scriptContext;
final FieldMapper.Parameter<Script> script = new FieldMapper.Parameter<>(
private final FieldMapper.Parameter<Script> script = new FieldMapper.Parameter<>(
"script",
true,
() -> null,
@ -225,6 +225,8 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
Objects::toString
).setSerializerCheck((id, ic, v) -> ic);
private final FieldMapper.Parameter<String> onScriptError = FieldMapper.Parameter.onScriptErrorParam(m -> m.onScriptError, script);
Builder(String name, ScriptContext<Factory> scriptContext) {
super(name);
this.scriptContext = scriptContext;
@ -247,7 +249,8 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
protected final RuntimeField createChildRuntimeField(
MappingParserContext parserContext,
String parent,
Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory
Function<SearchLookup, CompositeFieldScript.LeafFactory> parentScriptFactory,
OnScriptError onScriptError
) {
if (script.isConfigured()) {
throw new IllegalArgumentException(
@ -257,7 +260,7 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
String fullName = parent + "." + name;
return new LeafRuntimeField(
name,
createFieldType(fullName, getCompositeLeafFactory(parentScriptFactory), getScript(), meta()),
createFieldType(fullName, getCompositeLeafFactory(parentScriptFactory), getScript(), meta(), onScriptError),
getParameters()
);
}
@ -267,26 +270,41 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
}
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());
}
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(
String name,
Factory factory,
Script script,
Map<String, String> meta,
Version supportedVersion
Version supportedVersion,
OnScriptError onScriptError
) {
return createFieldType(name, factory, script, meta);
return createFieldType(name, factory, script, meta, onScriptError);
}
@Override
protected List<FieldMapper.Parameter<?>> getParameters() {
List<FieldMapper.Parameter<?>> parameters = new ArrayList<>(super.getParameters());
parameters.add(script);
parameters.add(onScriptError);
return Collections.unmodifiableList(parameters);
}
@ -296,5 +314,6 @@ abstract class AbstractScriptFieldType<LeafFactory> extends MappedFieldType {
}
return script.get();
}
}
}

View file

@ -139,7 +139,7 @@ public class BooleanFieldMapper extends FieldMapper {
BooleanFieldScript.Factory scriptFactory = scriptCompiler.compile(script.get(), BooleanFieldScript.CONTEXT);
return scriptFactory == 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)
.runForDoc(doc, consumer);
}

View file

@ -46,9 +46,10 @@ public final class BooleanScriptFieldType extends AbstractScriptFieldType<Boolea
String name,
BooleanFieldScript.Factory factory,
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
@ -67,10 +68,16 @@ public final class BooleanScriptFieldType extends AbstractScriptFieldType<Boolea
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(
name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup),
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script,
scriptFactory.isResultDeterministic(),
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>>(
"fields",
false,
@ -66,6 +68,7 @@ public class CompositeRuntimeField implements RuntimeField {
List<FieldMapper.Parameter<?>> parameters = new ArrayList<>(super.getParameters());
parameters.add(script);
parameters.add(fields);
parameters.add(onScriptError);
return Collections.unmodifiableList(parameters);
}
@ -73,7 +76,8 @@ public class CompositeRuntimeField implements RuntimeField {
protected RuntimeField createChildRuntimeField(
MappingParserContext parserContext,
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 + "]");
}
@ -81,11 +85,15 @@ public class CompositeRuntimeField implements RuntimeField {
@Override
protected RuntimeField createRuntimeField(MappingParserContext parserContext) {
CompositeFieldScript.Factory factory = parserContext.scriptCompiler().compile(script.get(), CompositeFieldScript.CONTEXT);
Function<RuntimeField.Builder, RuntimeField> builder = b -> b.createChildRuntimeField(
parserContext,
name,
lookup -> factory.newFactory(name, script.get().getParams(), lookup)
);
Function<RuntimeField.Builder, RuntimeField> builder = b -> {
OnScriptError onScriptError = OnScriptError.fromString(this.onScriptError.get());
return b.createChildRuntimeField(
parserContext,
name,
lookup -> factory.newFactory(name, script.get().getParams(), lookup, onScriptError),
onScriptError
);
};
Map<String, RuntimeField> runtimeFields = RuntimeField.parseRuntimeFields(
new HashMap<>(fields.getValue()),
parserContext,

View file

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

View file

@ -87,23 +87,29 @@ public class DateScriptFieldType extends AbstractScriptFieldType<DateFieldScript
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
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);
}
@Override
AbstractScriptFieldType<?> createFieldType(String name, DateFieldScript.Factory factory, Script script, Map<String, String> meta) {
return createFieldType(name, factory, script, meta, Version.CURRENT);
return createFieldType(name, factory, script, meta, Version.CURRENT, onScriptError);
}
@Override
@ -131,11 +137,12 @@ public class DateScriptFieldType extends AbstractScriptFieldType<DateFieldScript
DateFieldScript.Factory scriptFactory,
DateFormatter dateTimeFormatter,
Script script,
Map<String, String> meta
Map<String, String> meta,
OnScriptError onScriptError
) {
super(
name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, dateTimeFormatter),
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, dateTimeFormatter, onScriptError),
script,
scriptFactory.isResultDeterministic(),
meta

View file

@ -47,9 +47,10 @@ public final class DoubleScriptFieldType extends AbstractScriptFieldType<DoubleF
String name,
DoubleFieldScript.Factory factory,
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
@ -67,10 +68,16 @@ public final class DoubleScriptFieldType extends AbstractScriptFieldType<DoubleF
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(
name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup),
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script,
scriptFactory.isResultDeterministic(),
meta

View file

@ -143,7 +143,7 @@ public class GeoPointFieldMapper extends AbstractPointGeometryFieldMapper<GeoPoi
GeoPointFieldScript.Factory factory = scriptCompiler.compile(this.script.get(), GeoPointFieldScript.CONTEXT);
return factory == 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)
.runForDoc(doc, consumer);
}

View file

@ -50,9 +50,10 @@ public final class GeoPointScriptFieldType extends AbstractScriptFieldType<GeoPo
String name,
GeoPointFieldScript.Factory factory,
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
@ -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(
name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup),
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script,
scriptFactory.isResultDeterministic(),
meta
@ -154,7 +161,7 @@ public final class GeoPointScriptFieldType extends AbstractScriptFieldType<GeoPo
) {
return 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;
@Override

View file

@ -145,7 +145,7 @@ public class IpFieldMapper extends FieldMapper {
IpFieldScript.Factory factory = scriptCompiler.compile(this.script.get(), IpFieldScript.CONTEXT);
return factory == 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)
.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) {
@Override
AbstractScriptFieldType<?> createFieldType(String name, IpFieldScript.Factory factory, Script script, Map<String, String> meta) {
return new IpScriptFieldType(name, factory, getScript(), meta());
AbstractScriptFieldType<?> createFieldType(
String name,
IpFieldScript.Factory factory,
Script script,
Map<String, String> meta,
OnScriptError onScriptError
) {
return new IpScriptFieldType(name, factory, getScript(), meta(), onScriptError);
}
@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(
name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup),
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script,
scriptFactory.isResultDeterministic(),
meta

View file

@ -245,7 +245,7 @@ public final class KeywordFieldMapper extends FieldMapper {
StringFieldScript.Factory scriptFactory = scriptCompiler.compile(script.get(), StringFieldScript.CONTEXT);
return scriptFactory == 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)
.runForDoc(doc, consumer);
}

View file

@ -54,9 +54,10 @@ public final class KeywordScriptFieldType extends AbstractScriptFieldType<String
String name,
StringFieldScript.Factory factory,
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
@ -74,10 +75,16 @@ public final class KeywordScriptFieldType extends AbstractScriptFieldType<String
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(
name,
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup),
searchLookup -> scriptFactory.newFactory(name, script.getParams(), searchLookup, onScriptError),
script,
scriptFactory.isResultDeterministic(),
meta

View file

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

View file

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

View file

@ -592,7 +592,7 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public FieldValues<Number> compile(String fieldName, Script script, ScriptCompiler compiler) {
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)
.runForDoc(doc, consumer::accept);
}
@ -1055,7 +1055,7 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public FieldValues<Number> compile(String fieldName, Script script, ScriptCompiler compiler) {
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)
.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(
MappingParserContext parserContext,
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) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,6 +10,7 @@ package org.elasticsearch.script;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.script.field.LongDocValuesField;
import org.elasticsearch.search.lookup.SearchLookup;
@ -21,7 +22,7 @@ public class SortedNumericDocValuesLongFieldScript extends AbstractLongFieldScri
final LongDocValuesField longDocValuesField;
public SortedNumericDocValuesLongFieldScript(String fieldName, SearchLookup lookup, LeafReaderContext ctx) {
super(fieldName, Map.of(), lookup, ctx);
super(fieldName, Map.of(), lookup, OnScriptError.FAIL, ctx);
try {
longDocValuesField = new LongDocValuesField(DocValues.getSortedNumeric(ctx.reader(), fieldName), fieldName);
} 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.SortedSetDocValues;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.search.lookup.SearchLookup;
import java.io.IOException;
@ -23,7 +24,7 @@ public class SortedSetDocValuesStringFieldScript extends StringFieldScript {
boolean hasValue = false;
public SortedSetDocValuesStringFieldScript(String fieldName, SearchLookup searchLookup, LeafReaderContext ctx) {
super(fieldName, Map.of(), searchLookup, ctx);
super(fieldName, Map.of(), searchLookup, OnScriptError.FAIL, ctx);
try {
sortedSetDocValues = DocValues.getSortedSet(ctx.reader(), fieldName);
} catch (IOException e) {

View file

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

View file

@ -12,6 +12,7 @@ import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateUtils;
import org.elasticsearch.index.mapper.MapperServiceTestCase;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.StringFieldScript;
@ -264,7 +265,12 @@ public class TimeSeriesModeTests extends MapperServiceTestCase {
if (context.equals(StringFieldScript.CONTEXT) && script.getLang().equals("mock")) {
return (T) new StringFieldScript.Factory() {
@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");
}
};

View file

@ -8,9 +8,14 @@
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.search.IndexSearcher;
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.common.Strings;
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.index.fielddata.FieldDataContext;
import org.elasticsearch.index.fielddata.IndexFieldDataCache;
import org.elasticsearch.index.query.ExistsQueryBuilder;
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
import org.elasticsearch.script.BooleanFieldScript;
@ -38,7 +44,9 @@ import org.elasticsearch.xcontent.json.JsonXContent;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import static org.hamcrest.Matchers.containsString;
@ -157,6 +165,45 @@ public abstract class AbstractScriptFieldTypeTestCase extends MapperServiceTestC
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")
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))
.build(new IndexFieldDataCache.None(), new NoneCircuitBreakerService());
});
when(context.getMatchingFieldNames(any())).thenReturn(Set.of("dummy_field"));
return context;
}

View file

@ -258,7 +258,13 @@ public class BooleanFieldMapperTests extends MapperTestCase {
return new IngestScriptSupport() {
@Override
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
public void execute() {}
};
@ -266,7 +272,13 @@ public class BooleanFieldMapperTests extends MapperTestCase {
@Override
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
public void execute() {
emit(true);

View file

@ -24,10 +24,11 @@ import java.util.List;
import java.util.Map;
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,
params,
lookup,
OnScriptError.FAIL,
ctx
) {
@Override
@ -59,6 +60,7 @@ public class BooleanFieldScriptTests extends FieldScriptTestCase<BooleanFieldScr
"test",
Map.of(),
new SearchLookup(field -> null, (ft, lookup, fdt) -> null, new SourceLookup.ReaderSourceProvider()),
OnScriptError.FAIL,
reader.leaves().get(0)
) {
@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(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)) {
@ -264,7 +267,10 @@ public class BooleanScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeT
assertThat(searcher.count(simpleMappedFieldType().termQuery("false", mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(null, mockContext())), equalTo(1));
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
protected BooleanScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of());
return build("read_foo", Map.of(), OnScriptError.FAIL);
}
@Override
protected MappedFieldType loopFieldType() {
return build("loop", Map.of());
return build("loop", Map.of(), OnScriptError.FAIL);
}
@Override
@ -413,13 +419,20 @@ public class BooleanScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeT
return "boolean";
}
private static BooleanScriptFieldType build(String code, Map<String, Object> params) {
return build(new Script(ScriptType.INLINE, "test", code, params));
protected BooleanScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
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) {
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
public void execute() {
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
public void execute() {
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
lookup.forkAndTrackFieldReferences("test");
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() + "]");
};
}
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) {
return new BooleanFieldScript.Factory() {
@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() {
@Override
public BooleanFieldScript newInstance(LeafReaderContext ctx) {
return new BooleanFieldScript(fieldName, params, searchLookup, ctx) {
return new BooleanFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override
public void execute() {
executor.accept(this);

View file

@ -33,10 +33,11 @@ public class CompositeRuntimeFieldTests extends MapperServiceTestCase {
@SuppressWarnings("unchecked")
protected <T> T compileScript(Script script, ScriptContext<T> 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,
params,
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override
@ -52,7 +53,13 @@ public class CompositeRuntimeFieldTests extends MapperServiceTestCase {
};
}
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
public void execute() {

View file

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

View file

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

View file

@ -128,7 +128,11 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
public void testFormatDuel() throws IOException {
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);
for (int i = 0; i < 100; i++) {
long date = randomDate();
@ -149,7 +153,7 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
List<Long> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) {
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);
searcher.search(new MatchAllDocsQuery(), new Collector() {
@Override
@ -381,7 +385,9 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
assertThat(searcher.count(simpleMappedFieldType().termQuery(1595432181354L, mockContext())), equalTo(1));
assertThat(searcher.count(simpleMappedFieldType().termQuery(2595432181354L, mockContext())), equalTo(0));
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)
);
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() {
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
@ -470,21 +480,22 @@ public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
return "date";
}
private static DateScriptFieldType build(String code) {
return build(code, Map.of());
private DateScriptFieldType build(String code) {
return build(code, Map.of(), OnScriptError.FAIL);
}
private static DateScriptFieldType build(String code, Map<String, Object> params) {
return build(new Script(ScriptType.INLINE, "test", code, params), DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER);
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, onScriptError);
}
private static DateFieldScript.Factory factory(Script script) {
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,
params,
lookup,
formatter,
onScriptError,
ctx
) {
@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,
params,
lookup,
formatter,
onScriptError,
ctx
) {
@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
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() + "]");
};
}
private static DateScriptFieldType build(Script script, DateFormatter dateTimeFormatter) {
return new DateScriptFieldType("test", factory(script), dateTimeFormatter, script, emptyMap());
private static DateScriptFieldType build(Script script, DateFormatter dateTimeFormatter, OnScriptError onScriptError) {
return new DateScriptFieldType("test", factory(script), dateTimeFormatter, script, emptyMap(), onScriptError);
}
private static long randomDate() {

View file

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

View file

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

View file

@ -105,7 +105,13 @@ public class DoubleFieldMapperTests extends NumberFieldMapperTests {
@Override
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
public void execute() {}
};
@ -113,7 +119,13 @@ public class DoubleFieldMapperTests extends NumberFieldMapperTests {
@Override
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
public void execute() {
emit(1.0);

View file

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

View file

@ -64,7 +64,7 @@ public class DoubleScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTe
List<Double> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) {
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);
searcher.search(new MatchAllDocsQuery(), new Collector() {
@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.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
protected DoubleScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of());
return build("read_foo", Map.of(), OnScriptError.FAIL);
}
@Override
protected MappedFieldType loopFieldType() {
return build("loop", Map.of());
return build("loop", Map.of(), OnScriptError.FAIL);
}
@Override
@ -236,13 +239,20 @@ public class DoubleScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTe
return "double";
}
private static DoubleScriptFieldType build(String code, Map<String, Object> params) {
return build(new Script(ScriptType.INLINE, "test", code, params));
protected DoubleScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
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) {
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
public void execute() {
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
public void execute() {
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
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() + "]");
};
}
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) {
return new DoubleFieldScript.Factory() {
@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() {
@Override
public DoubleFieldScript newInstance(LeafReaderContext ctx) {
return new DoubleFieldScript(fieldName, params, searchLookup, ctx) {
return new DoubleFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override
public void execute() {
executor.accept(this);

View file

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

View file

@ -64,7 +64,7 @@ public class GeoPointScriptFieldTypeTests extends AbstractNonTextScriptFieldType
List<Object> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) {
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);
searcher.search(new MatchAllDocsQuery(), new Collector() {
@Override
@ -213,12 +213,12 @@ public class GeoPointScriptFieldTypeTests extends AbstractNonTextScriptFieldType
@Override
protected GeoPointScriptFieldType simpleMappedFieldType() {
return build("fromLatLon", Map.of());
return build("fromLatLon", Map.of(), OnScriptError.FAIL);
}
@Override
protected MappedFieldType loopFieldType() {
return build("loop", Map.of());
return build("loop", Map.of(), OnScriptError.FAIL);
}
@Override
@ -226,29 +226,44 @@ public class GeoPointScriptFieldTypeTests extends AbstractNonTextScriptFieldType
return "geo_point";
}
private static GeoPointScriptFieldType build(String code, Map<String, Object> params) {
return build(new Script(ScriptType.INLINE, "test", code, params));
protected GeoPointScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
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) {
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
public void execute() {
Map<?, ?> foo = (Map<?, ?>) lookup.source().source().get("foo");
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
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() + "]");
};
}
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) {
return new GeoPointFieldScript.Factory() {
@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() {
@Override
public GeoPointFieldScript newInstance(LeafReaderContext ctx) {
return new GeoPointFieldScript(fieldName, params, searchLookup, ctx) {
return new GeoPointFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override
public void execute() {
executor.accept(new Emit(this));

View file

@ -128,7 +128,7 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
@SuppressWarnings("unchecked")
protected <T> T compileScript(Script script, ScriptContext<T> context) {
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,
p,
l,
@ -137,7 +137,7 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
);
}
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,
p,
l,
@ -195,7 +195,7 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
LeafReaderContext ctx,
Consumer<TestLongFieldScript> executor
) {
super(fieldName, params, searchLookup, ctx);
super(fieldName, params, searchLookup, OnScriptError.FAIL, ctx);
this.executor = executor;
}
@ -224,7 +224,7 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
LeafReaderContext ctx,
Consumer<TestDoubleFieldScript> executor
) {
super(fieldName, params, searchLookup, ctx);
super(fieldName, params, searchLookup, OnScriptError.FAIL, ctx);
this.executor = executor;
}

View file

@ -388,7 +388,13 @@ public class IpFieldMapperTests extends MapperTestCase {
return new IngestScriptSupport() {
@Override
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
public void execute() {}
};
@ -396,7 +402,13 @@ public class IpFieldMapperTests extends MapperTestCase {
@Override
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
public void execute() {
emit("192.168.0.1");

View file

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

View file

@ -66,7 +66,7 @@ public class IpScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase {
List<Object> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) {
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);
DocValueFormat format = ft.docValueFormat(null, null);
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\"]}"))));
try (DirectoryReader reader = iw.getReader()) {
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.7", mockContext())), equalTo(0));
assertThat(searcher.count(fieldType.termQuery("192.168.0.0/16", mockContext())), equalTo(2));
@ -240,12 +240,12 @@ public class IpScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase {
@Override
protected IpScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of());
return build("read_foo", Map.of(), OnScriptError.FAIL);
}
@Override
protected MappedFieldType loopFieldType() {
return build("loop", Map.of());
return build("loop", Map.of(), OnScriptError.FAIL);
}
@Override
@ -253,13 +253,20 @@ public class IpScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase {
return "ip";
}
private static IpScriptFieldType build(String code, Map<String, Object> params) {
return build(new Script(ScriptType.INLINE, "test", code, params));
protected IpScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
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) {
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
public void execute() {
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
public void execute() {
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
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() + "]");
};
}
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) {
return new IpFieldScript.Factory() {
@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() {
@Override
public IpFieldScript newInstance(LeafReaderContext ctx) {
return new IpFieldScript(fieldName, params, searchLookup, ctx) {
return new IpFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override
public void execute() {
executor.accept(this);

View file

@ -729,7 +729,13 @@ public class KeywordFieldMapperTests extends MapperTestCase {
return new IngestScriptSupport() {
@Override
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
public void execute() {}
};
@ -737,7 +743,13 @@ public class KeywordFieldMapperTests extends MapperTestCase {
@Override
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
public void execute() {
emit("foo");

View file

@ -60,7 +60,7 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
List<String> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) {
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);
searcher.search(new MatchAllDocsQuery(), new Collector() {
@Override
@ -287,7 +287,7 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [2]}"))));
try (DirectoryReader reader = iw.getReader()) {
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));
}
}
@ -299,7 +299,7 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [2]}"))));
try (DirectoryReader reader = iw.getReader()) {
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(
IllegalArgumentException.class,
() -> {
@ -375,7 +375,7 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"foo\": [2]}"))));
try (DirectoryReader reader = iw.getReader()) {
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);
Query query = new MatchQueryBuilder("test", "1-Suffix").toQuery(searchExecutionContext);
assertThat(searcher.count(query), equalTo(1));
@ -385,12 +385,12 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
@Override
protected KeywordScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of());
return build("read_foo", Map.of(), OnScriptError.FAIL);
}
@Override
protected KeywordScriptFieldType loopFieldType() {
return build("loop", Map.of());
return build("loop", Map.of(), OnScriptError.FAIL);
}
@Override
@ -398,13 +398,20 @@ public class KeywordScriptFieldTypeTests extends AbstractScriptFieldTypeTestCase
return "keyword";
}
private static KeywordScriptFieldType build(String code, Map<String, Object> params) {
return build(new Script(ScriptType.INLINE, "test", code, params));
protected KeywordScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
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) {
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
public void execute() {
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
public void execute() {
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
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() + "]");
};
}
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) {
return new StringFieldScript.Factory() {
@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() {
@Override
public StringFieldScript newInstance(LeafReaderContext ctx) {
return new StringFieldScript(fieldName, params, searchLookup, ctx) {
return new StringFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override
public void execute() {
executor.accept(this);

View file

@ -132,7 +132,13 @@ public class LongFieldMapperTests extends WholeNumberFieldMapperTests {
@Override
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
public void execute() {}
};
@ -140,7 +146,13 @@ public class LongFieldMapperTests extends WholeNumberFieldMapperTests {
@Override
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
public void execute() {
emit(1);

View file

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

View file

@ -76,7 +76,7 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
List<Long> results = new ArrayList<>();
try (DirectoryReader reader = iw.getReader()) {
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);
searcher.search(new MatchAllDocsQuery(), new Collector() {
@Override
@ -132,7 +132,8 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
iw.addDocument(List.of(new StoredField("_source", new BytesRef("{\"timestamp\": [1595432181356]}"))));
try (DirectoryReader reader = iw.getReader()) {
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);
TopFieldDocs docs = searcher.search(new MatchAllDocsQuery(), 3, new Sort(sf));
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.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
protected LongScriptFieldType simpleMappedFieldType() {
return build("read_foo", Map.of());
return build("read_foo", Map.of(), OnScriptError.FAIL);
}
@Override
protected LongScriptFieldType loopFieldType() {
return build("loop", Map.of());
return build("loop", Map.of(), OnScriptError.FAIL);
}
@Override
@ -268,14 +272,21 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
return "long";
}
private static LongScriptFieldType build(String code, Map<String, Object> params) {
return build(new Script(ScriptType.INLINE, "test", code, params));
protected LongScriptFieldType build(String code, Map<String, Object> params, OnScriptError onScriptError) {
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) {
switch (script.getIdOrCode()) {
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
public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -284,7 +295,13 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
}
};
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
public void execute() {
for (Object foo : (List<?>) lookup.source().source().get("foo")) {
@ -295,7 +312,13 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
case "millis_ago":
// Painless actually call System.currentTimeMillis. We could mock the time but this works fine too.
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
public void execute() {
for (Object timestamp : (List<?>) lookup.source().source().get("timestamp")) {
@ -304,17 +327,26 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
}
};
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
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:
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) {
return new LongFieldScript.Factory() {
@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() {
@Override
public LongFieldScript newInstance(LeafReaderContext ctx) {
return new LongFieldScript(fieldName, params, searchLookup, ctx) {
return new LongFieldScript(fieldName, params, searchLookup, OnScriptError.FAIL, ctx) {
@Override
public void execute() {
executor.accept(this);

View file

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

View file

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

View file

@ -27,6 +27,7 @@ import org.elasticsearch.index.mapper.LuceneDocument;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.script.LongFieldScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.StringFieldScript;
@ -599,7 +600,7 @@ public class RangeAggregatorTests extends AggregatorTestCase {
public void testRuntimeFieldTopLevelQueryNotOptimized() throws IOException {
long totalDocs = (long) RangeAggregator.DOCS_PER_RANGE_TO_USE_FILTERS * 4;
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
public void execute() {
emit("cat");
@ -641,13 +642,19 @@ public class RangeAggregatorTests extends AggregatorTestCase {
*/
public void testRuntimeFieldRangesNotOptimized() throws IOException {
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
public void execute() {
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);
debugTestCase(
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.NumberType;
import org.elasticsearch.index.mapper.ObjectMapper;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.index.mapper.ProvidedIdFieldMapper;
import org.elasticsearch.index.mapper.RangeFieldMapper;
import org.elasticsearch.index.mapper.RangeType;
@ -1994,7 +1995,7 @@ public class TermsAggregatorTests extends AggregatorTestCase {
public void testRuntimeFieldTopLevelNotOptimized() throws IOException {
long totalDocs = 500;
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
public void execute() {
emit("cat");
@ -2043,10 +2044,11 @@ public class TermsAggregatorTests extends AggregatorTestCase {
*/
public void testRuntimeFieldTermsNotOptimized() throws IOException {
long totalDocs = 500;
StringFieldScript.Factory scriptFactory = (fieldName, params, lookup) -> ctx -> new StringFieldScript(
StringFieldScript.Factory scriptFactory = (fieldName, params, lookup, onScriptError) -> ctx -> new StringFieldScript(
fieldName,
Map.of(),
lookup,
OnScriptError.FAIL,
ctx
) {
@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"), };
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 -> {
for (int d = 0; d < totalDocs; d++) {
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.GeoUtils;
import org.elasticsearch.index.mapper.GeoPointScriptFieldType;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.script.AbstractLongFieldScript;
import org.elasticsearch.script.GeoPointFieldScript;
import org.elasticsearch.script.Script;
@ -88,6 +89,7 @@ public class GeoPointScriptFieldDistanceFeatureQueryTests extends AbstractScript
"test",
Map.of(),
searchLookup,
OnScriptError.FAIL,
ctx
) {
@Override

View file

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

View file

@ -15,6 +15,7 @@ import org.apache.lucene.search.Rescorer;
import org.apache.lucene.search.Scorable;
import org.apache.lucene.search.SortField;
import org.elasticsearch.common.util.Maps;
import org.elasticsearch.index.mapper.OnScriptError;
import org.elasticsearch.index.query.IntervalFilterScript;
import org.elasticsearch.index.similarity.ScriptedSimilarity.Doc;
import org.elasticsearch.index.similarity.ScriptedSimilarity.Field;
@ -269,7 +270,13 @@ public class MockScriptEngine implements ScriptEngine {
IntervalFilterScript.Factory factory = mockCompiled::createIntervalFilterScript;
return context.factoryClazz.cast(factory);
} 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
public void execute() {
emit(true);
@ -277,7 +284,13 @@ public class MockScriptEngine implements ScriptEngine {
};
return context.factoryClazz.cast(booleanFieldScript);
} 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
public void execute() {
emit("test");
@ -285,7 +298,13 @@ public class MockScriptEngine implements ScriptEngine {
};
return context.factoryClazz.cast(stringFieldScript);
} 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
public void execute() {
emit(1L);
@ -293,7 +312,13 @@ public class MockScriptEngine implements ScriptEngine {
};
return context.factoryClazz.cast(longFieldScript);
} 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
public void execute() {
emit(1.2D);
@ -301,7 +326,14 @@ public class MockScriptEngine implements ScriptEngine {
};
return context.factoryClazz.cast(doubleFieldScript);
} 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
public void execute() {
emit(123L);
@ -309,7 +341,7 @@ public class MockScriptEngine implements ScriptEngine {
};
return context.factoryClazz.cast(dateFieldScript);
} 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
public void execute() {
emit("127.0.0.1");
@ -317,7 +349,13 @@ public class MockScriptEngine implements ScriptEngine {
};
return context.factoryClazz.cast(ipFieldScript);
} 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
public void execute() {
emit(1.2D, 1.2D);
@ -325,7 +363,13 @@ public class MockScriptEngine implements ScriptEngine {
};
return context.factoryClazz.cast(geoPointFieldScript);
} 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
public void execute() {
emit("field1", "value1");