13
13
import org .apache .lucene .document .SortedNumericDocValuesField ;
14
14
import org .apache .lucene .document .StoredField ;
15
15
import org .apache .lucene .index .IndexOptions ;
16
+ import org .apache .lucene .index .LeafReaderContext ;
16
17
import org .apache .lucene .search .Query ;
17
18
import org .apache .lucene .search .TermRangeQuery ;
18
19
import org .apache .lucene .util .BytesRef ;
25
26
import org .elasticsearch .index .fielddata .IndexNumericFieldData .NumericType ;
26
27
import org .elasticsearch .index .fielddata .plain .SortedNumericIndexFieldData ;
27
28
import org .elasticsearch .index .query .SearchExecutionContext ;
29
+ import org .elasticsearch .script .BooleanFieldScript ;
30
+ import org .elasticsearch .script .Script ;
31
+ import org .elasticsearch .script .ScriptCompiler ;
28
32
import org .elasticsearch .search .DocValueFormat ;
33
+ import org .elasticsearch .search .lookup .FieldValues ;
29
34
import org .elasticsearch .search .lookup .SearchLookup ;
30
35
31
36
import java .io .IOException ;
32
37
import java .time .ZoneId ;
33
38
import java .util .Collections ;
34
39
import java .util .List ;
35
40
import java .util .Map ;
41
+ import java .util .Objects ;
36
42
import java .util .function .Supplier ;
37
43
38
44
/**
@@ -72,43 +78,69 @@ public static class Builder extends FieldMapper.Builder {
72
78
(n , c , o ) -> o == null ? null : XContentMapValues .nodeBooleanValue (o ), m -> toType (m ).nullValue )
73
79
.acceptsNull ();
74
80
81
+ private final Parameter <Script > script = Parameter .scriptParam (m -> toType (m ).script );
82
+ private final Parameter <String > onScriptError = Parameter .onScriptErrorParam (m -> toType (m ).onScriptError , script );
83
+
75
84
private final Parameter <Map <String , String >> meta = Parameter .metaParam ();
76
85
77
- public Builder (String name ) {
86
+ private final ScriptCompiler scriptCompiler ;
87
+
88
+ public Builder (String name , ScriptCompiler scriptCompiler ) {
78
89
super (name );
90
+ this .scriptCompiler = Objects .requireNonNull (scriptCompiler );
91
+ this .script .precludesParameters (nullValue );
92
+ this .script .setValidator (s -> {
93
+ if (s != null && indexed .get () == false && docValues .get () == false ) {
94
+ throw new MapperParsingException ("Cannot define script on field with index:false and doc_values:false" );
95
+ }
96
+ });
79
97
}
80
98
81
99
@ Override
82
100
protected List <Parameter <?>> getParameters () {
83
- return List .of (meta , docValues , indexed , nullValue , stored );
101
+ return List .of (meta , docValues , indexed , nullValue , stored , script , onScriptError );
84
102
}
85
103
86
104
@ Override
87
105
public BooleanFieldMapper build (ContentPath contentPath ) {
88
106
MappedFieldType ft = new BooleanFieldType (buildFullName (contentPath ), indexed .getValue (), stored .getValue (),
89
- docValues .getValue (), nullValue .getValue (), meta .getValue ());
107
+ docValues .getValue (), nullValue .getValue (), scriptValues (), meta .getValue ());
108
+
90
109
return new BooleanFieldMapper (name , ft , multiFieldsBuilder .build (this , contentPath ), copyTo .build (), this );
91
110
}
111
+
112
+ private FieldValues <Boolean > scriptValues () {
113
+ if (script .get () == null ) {
114
+ return null ;
115
+ }
116
+ BooleanFieldScript .Factory scriptFactory = scriptCompiler .compile (script .get (), BooleanFieldScript .CONTEXT );
117
+ return scriptFactory == null ? null : (lookup , ctx , doc , consumer ) -> scriptFactory
118
+ .newFactory (name , script .get ().getParams (), lookup )
119
+ .newInstance (ctx )
120
+ .runForDoc (doc , consumer );
121
+ }
92
122
}
93
123
94
- public static final TypeParser PARSER = new TypeParser ((n , c ) -> new Builder (n ));
124
+ public static final TypeParser PARSER = new TypeParser ((n , c ) -> new Builder (n , c . scriptCompiler () ));
95
125
96
126
public static final class BooleanFieldType extends TermBasedFieldType {
97
127
98
128
private final Boolean nullValue ;
129
+ private final FieldValues <Boolean > scriptValues ;
99
130
100
131
public BooleanFieldType (String name , boolean isSearchable , boolean isStored , boolean hasDocValues ,
101
- Boolean nullValue , Map <String , String > meta ) {
132
+ Boolean nullValue , FieldValues < Boolean > scriptValues , Map <String , String > meta ) {
102
133
super (name , isSearchable , isStored , hasDocValues , TextSearchInfo .SIMPLE_MATCH_ONLY , meta );
103
134
this .nullValue = nullValue ;
135
+ this .scriptValues = scriptValues ;
104
136
}
105
137
106
138
public BooleanFieldType (String name ) {
107
- this (name , true , false , true , false , Collections .emptyMap ());
139
+ this (name , true , false , true , false , null , Collections .emptyMap ());
108
140
}
109
141
110
142
public BooleanFieldType (String name , boolean searchable ) {
111
- this (name , searchable , false , true , false , Collections .emptyMap ());
143
+ this (name , searchable , false , true , false , null , Collections .emptyMap ());
112
144
}
113
145
114
146
@ Override
@@ -121,7 +153,9 @@ public ValueFetcher valueFetcher(SearchExecutionContext context, String format)
121
153
if (format != null ) {
122
154
throw new IllegalArgumentException ("Field [" + name () + "] of type [" + typeName () + "] doesn't support formats." );
123
155
}
124
-
156
+ if (this .scriptValues != null ) {
157
+ return FieldValues .valueFetcher (this .scriptValues , context );
158
+ }
125
159
return new SourceValueFetcher (name (), context , nullValue ) {
126
160
@ Override
127
161
protected Boolean parseSourceValue (Object value ) {
@@ -208,14 +242,21 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower
208
242
private final boolean indexed ;
209
243
private final boolean hasDocValues ;
210
244
private final boolean stored ;
245
+ private final Script script ;
246
+ private final FieldValues <Boolean > scriptValues ;
247
+ private final ScriptCompiler scriptCompiler ;
211
248
212
249
protected BooleanFieldMapper (String simpleName , MappedFieldType mappedFieldType ,
213
250
MultiFields multiFields , CopyTo copyTo , Builder builder ) {
214
- super (simpleName , mappedFieldType , Lucene .KEYWORD_ANALYZER , multiFields , copyTo );
251
+ super (simpleName , mappedFieldType , Lucene .KEYWORD_ANALYZER , multiFields , copyTo ,
252
+ builder .script .get () != null , builder .onScriptError .getValue ());
215
253
this .nullValue = builder .nullValue .getValue ();
216
254
this .stored = builder .stored .getValue ();
217
255
this .indexed = builder .indexed .getValue ();
218
256
this .hasDocValues = builder .docValues .getValue ();
257
+ this .script = builder .script .get ();
258
+ this .scriptValues = builder .scriptValues ();
259
+ this .scriptCompiler = builder .scriptCompiler ;
219
260
}
220
261
221
262
@ Override
@@ -240,7 +281,10 @@ protected void parseCreateField(ParseContext context) throws IOException {
240
281
value = context .parser ().booleanValue ();
241
282
}
242
283
}
284
+ indexValue (context , value );
285
+ }
243
286
287
+ private void indexValue (ParseContext context , Boolean value ) {
244
288
if (value == null ) {
245
289
return ;
246
290
}
@@ -257,14 +301,18 @@ protected void parseCreateField(ParseContext context) throws IOException {
257
301
}
258
302
}
259
303
304
+ @ Override
305
+ protected void indexScriptValues (SearchLookup searchLookup , LeafReaderContext readerContext , int doc , ParseContext parseContext ) {
306
+ this .scriptValues .valuesForDoc (searchLookup , readerContext , doc , value -> indexValue (parseContext , value ));
307
+ }
308
+
260
309
@ Override
261
310
public FieldMapper .Builder getMergeBuilder () {
262
- return new Builder (simpleName ()).init (this );
311
+ return new Builder (simpleName (), scriptCompiler ).init (this );
263
312
}
264
313
265
314
@ Override
266
315
protected String contentType () {
267
316
return CONTENT_TYPE ;
268
317
}
269
-
270
318
}
0 commit comments