Skip to content

Commit a972b7b

Browse files
committed
Warn on badly-formed null values for date and IP field mappers (#62487)
In #57666 we changed when null_value was parsed for ip and date fields. Previously, the null value was stored as a string, and parsed into a date or InetAddress whenever a document containing a null value was encountered. Now, the values are parsed when the mappings are built, which means that bad values are detected up front; if you try and add a mapping with a badly-parsed ip or date for a null_value, the mapping will be rejected. This causes problems for upgrades in the case when you have a badly-formed null_value in a pre-7.9 cluster. This commit fixes the upgrade case by changing the logic to only logging a warning on the badly formed value, replicating the earlier behaviour. Fixes #62363
1 parent f428961 commit a972b7b

File tree

4 files changed

+65
-3
lines changed

4 files changed

+65
-3
lines changed

server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22+
import org.apache.logging.log4j.LogManager;
2223
import org.apache.lucene.document.FieldType;
2324
import org.apache.lucene.document.LongPoint;
2425
import org.apache.lucene.document.SortedNumericDocValuesField;
@@ -38,6 +39,7 @@
3839
import org.elasticsearch.common.Nullable;
3940
import org.elasticsearch.common.geo.ShapeRelation;
4041
import org.elasticsearch.common.joda.Joda;
42+
import org.elasticsearch.common.logging.DeprecationLogger;
4143
import org.elasticsearch.common.time.DateFormatter;
4244
import org.elasticsearch.common.time.DateFormatters;
4345
import org.elasticsearch.common.time.DateMathParser;
@@ -72,6 +74,8 @@
7274
/** A {@link FieldMapper} for dates. */
7375
public final class DateFieldMapper extends FieldMapper {
7476

77+
private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(LogManager.getLogger(DateFieldMapper.class));
78+
7579
public static final String CONTENT_TYPE = "date";
7680
public static final String DATE_NANOS_CONTENT_TYPE = "date_nanos";
7781
public static final DateFormatter DEFAULT_DATE_TIME_FORMATTER = DateFormatter.forPattern("strict_date_optional_time||epoch_millis");
@@ -261,7 +265,9 @@ private Long parseNullValue(DateFieldType fieldType) {
261265
return fieldType.parse(nullValue);
262266
}
263267
catch (Exception e) {
264-
throw new MapperParsingException("Error parsing [null_value] on field [" + name() + "]: " + e.getMessage(), e);
268+
DEPRECATION_LOGGER.deprecatedAndMaybeLog("date_field_null_value",
269+
"Error parsing [{}] as date in [null_value] on field [{}]; [null_value] will be ignored", nullValue, name);
270+
return null;
265271
}
266272
}
267273

server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22+
import org.apache.logging.log4j.LogManager;
2223
import org.apache.lucene.document.FieldType;
2324
import org.apache.lucene.document.InetAddressPoint;
2425
import org.apache.lucene.document.SortedSetDocValuesField;
@@ -35,6 +36,7 @@
3536
import org.elasticsearch.common.Explicit;
3637
import org.elasticsearch.common.Nullable;
3738
import org.elasticsearch.common.collect.Tuple;
39+
import org.elasticsearch.common.logging.DeprecationLogger;
3840
import org.elasticsearch.common.network.InetAddresses;
3941
import org.elasticsearch.common.xcontent.XContentBuilder;
4042
import org.elasticsearch.common.xcontent.support.XContentMapValues;
@@ -57,6 +59,8 @@
5759
/** A {@link FieldMapper} for ip addresses. */
5860
public class IpFieldMapper extends FieldMapper {
5961

62+
private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(LogManager.getLogger(IpFieldMapper.class));
63+
6064
public static final String CONTENT_TYPE = "ip";
6165

6266
public static class Defaults {
@@ -125,7 +129,14 @@ public Mapper.Builder<?> parse(String name, Map<String, Object> node, ParserCont
125129
if (propNode == null) {
126130
throw new MapperParsingException("Property [null_value] cannot be null.");
127131
}
128-
builder.nullValue(InetAddresses.forString(propNode.toString()));
132+
try {
133+
builder.nullValue(InetAddresses.forString(propNode.toString()));
134+
}
135+
catch (Exception e) {
136+
DEPRECATION_LOGGER.deprecatedAndMaybeLog("ip_field_null_value",
137+
"Error parsing [{}] as IP in [null_value] on field [{}]; [null_value] will be ignored",
138+
propNode.toString(), name);
139+
}
129140
iterator.remove();
130141
} else if (propName.equals("ignore_malformed")) {
131142
builder.ignoreMalformed(XContentMapValues.nodeBooleanValue(propNode, name + ".ignore_malformed"));

server/src/test/java/org/elasticsearch/index/mapper/DateFieldMapperTests.java

+23-1
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ public void testNanosNullValue() throws IOException {
384384
assertFalse(dvField.fieldType().stored());
385385
}
386386

387-
public void testBadNullValue() throws IOException {
387+
public void testBadFormat() throws IOException {
388388

389389
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
390390
.startObject("type")
@@ -402,6 +402,28 @@ public void testBadNullValue() throws IOException {
402402
equalTo("Error parsing [format] on field [field]: No date pattern provided"));
403403
}
404404

405+
public void testBadNullValue() throws IOException {
406+
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
407+
.startObject("type")
408+
.startObject("properties")
409+
.startObject("field")
410+
.field("type", "date")
411+
.field("null_value", "foo")
412+
.endObject()
413+
.endObject()
414+
.endObject().endObject());
415+
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
416+
ParsedDocument doc = mapper.parse(new SourceToParse("test", "type", "1", BytesReference
417+
.bytes(XContentFactory.jsonBuilder()
418+
.startObject()
419+
.nullField("field")
420+
.endObject()),
421+
XContentType.JSON));
422+
IndexableField[] fields = doc.rootDoc().getFields("field");
423+
assertEquals(0, fields.length);
424+
assertWarnings("Error parsing [foo] as date in [null_value] on field [field]; [null_value] will be ignored");
425+
}
426+
405427
public void testTimeZoneParsing() throws Exception {
406428
final String timeZonePattern = "yyyy-MM-dd" + randomFrom("XXX", "[XXX]", "'['XXX']'");
407429

server/src/test/java/org/elasticsearch/index/mapper/IpFieldMapperTests.java

+23
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,29 @@ public void testNullValue() throws IOException {
268268
assertEquals(DocValuesType.SORTED_SET, dvField.fieldType().docValuesType());
269269
assertEquals(new BytesRef(InetAddressPoint.encode(InetAddresses.forString("::1"))), dvField.binaryValue());
270270
assertFalse(dvField.fieldType().stored());
271+
272+
mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
273+
.startObject("type")
274+
.startObject("properties")
275+
.startObject("field")
276+
.field("type", "ip")
277+
.field("null_value", ":1")
278+
.endObject()
279+
.endObject()
280+
.endObject().endObject());
281+
282+
mapper = parser.parse("type", new CompressedXContent(mapping));
283+
284+
doc = mapper.parse(new SourceToParse("test", "type", "1", BytesReference
285+
.bytes(XContentFactory.jsonBuilder()
286+
.startObject()
287+
.nullField("field")
288+
.endObject()),
289+
XContentType.JSON));
290+
fields = doc.rootDoc().getFields("field");
291+
assertEquals(0, fields.length);
292+
293+
assertWarnings("Error parsing [:1] as IP in [null_value] on field [field]; [null_value] will be ignored");
271294
}
272295

273296
public void testSerializeDefaults() throws Exception {

0 commit comments

Comments
 (0)