2020import org .apache .lucene .util .NumericUtils ;
2121import org .elasticsearch .common .Explicit ;
2222import org .elasticsearch .common .io .stream .BytesStreamOutput ;
23+ import org .elasticsearch .common .settings .Setting ;
2324import org .elasticsearch .common .util .BigArrays ;
2425import org .elasticsearch .core .Nullable ;
2526import org .elasticsearch .core .Releasables ;
4142import org .elasticsearch .index .mapper .LuceneDocument ;
4243import org .elasticsearch .index .mapper .MappedFieldType ;
4344import org .elasticsearch .index .mapper .MapperBuilderContext ;
45+ import org .elasticsearch .index .mapper .NumberFieldMapper ;
4446import org .elasticsearch .index .mapper .SourceLoader ;
4547import org .elasticsearch .index .mapper .SourceValueFetcher ;
4648import org .elasticsearch .index .mapper .ValueFetcher ;
5961import org .elasticsearch .xcontent .XContentParser ;
6062import org .elasticsearch .xcontent .XContentSubParser ;
6163import org .elasticsearch .xpack .analytics .mapper .ExponentialHistogramParser ;
64+ import org .elasticsearch .xpack .analytics .mapper .HistogramParser ;
6265import org .elasticsearch .xpack .analytics .mapper .IndexWithCount ;
66+ import org .elasticsearch .xpack .analytics .mapper .ParsedHistogramConverter ;
6367import org .elasticsearch .xpack .exponentialhistogram .fielddata .ExponentialHistogramValuesReader ;
6468import org .elasticsearch .xpack .exponentialhistogram .fielddata .IndexExponentialHistogramFieldData ;
6569import org .elasticsearch .xpack .exponentialhistogram .fielddata .LeafExponentialHistogramFieldData ;
@@ -94,6 +98,9 @@ public class ExponentialHistogramFieldMapper extends FieldMapper {
9498
9599 public static final String CONTENT_TYPE = "exponential_histogram" ;
96100
101+ // use the same default as numbers
102+ private static final Setting <Boolean > COERCE_SETTING = NumberFieldMapper .COERCE_SETTING ;
103+
97104 private static ExponentialHistogramFieldMapper toType (FieldMapper in ) {
98105 return (ExponentialHistogramFieldMapper ) in ;
99106 }
@@ -108,7 +115,7 @@ private static ExponentialHistogramFieldMapper toType(FieldMapper in) {
108115 * @param fullPath the full path of the mapped field
109116 * @return the name for the lucene field
110117 */
111- private static String zeroThresholdSubFieldName (String fullPath ) {
118+ static String zeroThresholdSubFieldName (String fullPath ) {
112119 return fullPath + "._zero_threshold" ;
113120 }
114121
@@ -122,7 +129,7 @@ private static String zeroThresholdSubFieldName(String fullPath) {
122129 * @param fullPath the full path of the mapped field
123130 * @return the name for the lucene field
124131 */
125- private static String valuesCountSubFieldName (String fullPath ) {
132+ static String valuesCountSubFieldName (String fullPath ) {
126133 return fullPath + "._values_count" ;
127134 }
128135
@@ -142,20 +149,22 @@ static class Builder extends FieldMapper.Builder {
142149
143150 private final FieldMapper .Parameter <Map <String , String >> meta = FieldMapper .Parameter .metaParam ();
144151 private final FieldMapper .Parameter <Explicit <Boolean >> ignoreMalformed ;
152+ private final Parameter <Explicit <Boolean >> coerce ;
145153
146- Builder (String name , boolean ignoreMalformedByDefault ) {
154+ Builder (String name , boolean ignoreMalformedByDefault , boolean coerceByDefault ) {
147155 super (name );
148156 this .ignoreMalformed = FieldMapper .Parameter .explicitBoolParam (
149157 "ignore_malformed" ,
150158 true ,
151159 m -> toType (m ).ignoreMalformed ,
152160 ignoreMalformedByDefault
153161 );
162+ this .coerce = Parameter .explicitBoolParam ("coerce" , true , m -> toType (m ).coerce , coerceByDefault );
154163 }
155164
156165 @ Override
157166 protected FieldMapper .Parameter <?>[] getParameters () {
158- return new FieldMapper .Parameter <?>[] { ignoreMalformed , meta };
167+ return new FieldMapper .Parameter <?>[] { ignoreMalformed , coerce , meta };
159168 }
160169
161170 @ Override
@@ -170,13 +179,16 @@ public ExponentialHistogramFieldMapper build(MapperBuilderContext context) {
170179 }
171180
172181 public static final FieldMapper .TypeParser PARSER = new FieldMapper .TypeParser (
173- (n , c ) -> new Builder (n , IGNORE_MALFORMED_SETTING .get (c .getSettings ())),
182+ (n , c ) -> new Builder (n , IGNORE_MALFORMED_SETTING .get (c .getSettings ()), COERCE_SETTING . get ( c . getSettings ()) ),
174183 notInMultiFields (CONTENT_TYPE )
175184 );
176185
177186 private final Explicit <Boolean > ignoreMalformed ;
178187 private final boolean ignoreMalformedByDefault ;
179188
189+ private final Explicit <Boolean > coerce ;
190+ private final boolean coerceByDefault ;
191+
180192 ExponentialHistogramFieldMapper (
181193 String simpleName ,
182194 MappedFieldType mappedFieldType ,
@@ -186,21 +198,27 @@ public ExponentialHistogramFieldMapper build(MapperBuilderContext context) {
186198 super (simpleName , mappedFieldType , builderParams );
187199 this .ignoreMalformed = builder .ignoreMalformed .getValue ();
188200 this .ignoreMalformedByDefault = builder .ignoreMalformed .getDefaultValue ().value ();
201+ this .coerce = builder .coerce .getValue ();
202+ this .coerceByDefault = builder .coerce .getDefaultValue ().value ();
189203 }
190204
191205 @ Override
192206 public boolean ignoreMalformed () {
193207 return ignoreMalformed .value ();
194208 }
195209
210+ boolean coerce () {
211+ return coerce .value ();
212+ }
213+
196214 @ Override
197215 protected String contentType () {
198216 return CONTENT_TYPE ;
199217 }
200218
201219 @ Override
202220 public FieldMapper .Builder getMergeBuilder () {
203- return new Builder (leafName (), ignoreMalformedByDefault ).init (this );
221+ return new Builder (leafName (), ignoreMalformedByDefault , coerceByDefault ).init (this );
204222 }
205223
206224 @ Override
@@ -427,7 +445,15 @@ public void parse(DocumentParserContext context) throws IOException {
427445 subParser = new XContentSubParser (context .parser ());
428446 }
429447 subParser .nextToken ();
430- ExponentialHistogramParser .ParsedExponentialHistogram parsedHistogram = ExponentialHistogramParser .parse (fullPath (), subParser );
448+ ExponentialHistogramParser .ParsedExponentialHistogram parsedHistogram ;
449+ if (coerce ()
450+ && subParser .currentToken () == XContentParser .Token .FIELD_NAME
451+ && HistogramParser .isHistogramSubFieldName (subParser .currentName ())) {
452+ HistogramParser .ParsedHistogram parsedTDigest = HistogramParser .parse (fullPath (), subParser );
453+ parsedHistogram = ParsedHistogramConverter .tDigestToExponential (parsedTDigest );
454+ } else {
455+ parsedHistogram = ExponentialHistogramParser .parse (fullPath (), subParser );
456+ }
431457
432458 if (context .doc ().getByKey (fieldType ().name ()) != null ) {
433459 throw new IllegalArgumentException (
0 commit comments