mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-06-29 01:44:36 -04:00
Format default values of IP ranges to match other range bound
This commit is contained in:
parent
a2fdc53053
commit
acb513945b
5 changed files with 129 additions and 59 deletions
|
@ -323,7 +323,7 @@ setup:
|
|||
index:
|
||||
index: synthetic_source_test
|
||||
id: "4"
|
||||
body: { "ip_range" : { "gt": "192.168.0.4", "lt": "192.168.0.8" } }
|
||||
body: { "ip_range" : { "gt": "2001:db8::", "lt": "200a:100::" } }
|
||||
|
||||
- do:
|
||||
index:
|
||||
|
@ -347,7 +347,7 @@ setup:
|
|||
index:
|
||||
index: synthetic_source_test
|
||||
id: "8"
|
||||
body: { "ip_range": { "gte": "10.10.10.10" } }
|
||||
body: { "ip_range": { "gte": "2001:db8::" } }
|
||||
|
||||
- do:
|
||||
indices.refresh: {}
|
||||
|
@ -367,7 +367,7 @@ setup:
|
|||
ip_range: { "gte": "192.168.0.4", "lte": "192.168.0.4" }
|
||||
- match:
|
||||
hits.hits.3._source:
|
||||
ip_range: { "gte": "192.168.0.5", "lte": "192.168.0.7" }
|
||||
ip_range: { "gte": "2001:db8::1", "lte": "200a:ff:ffff:ffff:ffff:ffff:ffff:ffff" }
|
||||
- match:
|
||||
hits.hits.4._source:
|
||||
ip_range: { "gte": "74.125.227.0", "lte": "74.125.227.127" }
|
||||
|
@ -375,10 +375,10 @@ setup:
|
|||
hits.hits.5._source: {}
|
||||
- match:
|
||||
hits.hits.6._source:
|
||||
ip_range: { "gte": "::", "lte": "10.10.10.10" }
|
||||
ip_range: { "gte": "0.0.0.0", "lte": "10.10.10.10" }
|
||||
- match:
|
||||
hits.hits.7._source:
|
||||
ip_range: { "gte": "10.10.10.10", "lte": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" }
|
||||
ip_range: { "gte": "2001:db8::", "lte": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" }
|
||||
|
||||
---
|
||||
"Date range":
|
||||
|
|
|
@ -381,17 +381,37 @@ public class RangeFieldMapper extends FieldMapper {
|
|||
|
||||
@Override
|
||||
protected void parseCreateField(DocumentParserContext context) throws IOException {
|
||||
Range range;
|
||||
XContentParser parser = context.parser();
|
||||
final XContentParser.Token start = parser.currentToken();
|
||||
if (start == XContentParser.Token.VALUE_NULL) {
|
||||
if (parser.currentToken() == XContentParser.Token.VALUE_NULL) {
|
||||
return;
|
||||
} else if (start == XContentParser.Token.START_OBJECT) {
|
||||
}
|
||||
|
||||
Range range = parseRange(parser);
|
||||
context.doc().addAll(fieldType().rangeType.createFields(context, name(), range, index, hasDocValues, store));
|
||||
|
||||
if (hasDocValues == false && (index || store)) {
|
||||
context.addToFieldNames(fieldType().name());
|
||||
}
|
||||
}
|
||||
|
||||
private Range parseRange(XContentParser parser) throws IOException {
|
||||
final XContentParser.Token start = parser.currentToken();
|
||||
if (fieldType().rangeType == RangeType.IP && start == XContentParser.Token.VALUE_STRING) {
|
||||
return parseIpRangeFromCidr(parser);
|
||||
}
|
||||
|
||||
if (start != XContentParser.Token.START_OBJECT) {
|
||||
throw new DocumentParsingException(
|
||||
parser.getTokenLocation(),
|
||||
"error parsing field [" + name() + "], expected an object but got " + parser.currentName()
|
||||
);
|
||||
}
|
||||
|
||||
RangeFieldType fieldType = fieldType();
|
||||
RangeType rangeType = fieldType.rangeType;
|
||||
String fieldName = null;
|
||||
Object from = rangeType.minValue();
|
||||
Object to = rangeType.maxValue();
|
||||
Object parsedFrom = null;
|
||||
Object parsedTo = null;
|
||||
boolean includeFrom = DEFAULT_INCLUDE_LOWER;
|
||||
boolean includeTo = DEFAULT_INCLUDE_UPPER;
|
||||
XContentParser.Token token;
|
||||
|
@ -402,22 +422,22 @@ public class RangeFieldMapper extends FieldMapper {
|
|||
if (fieldName.equals(GT_FIELD.getPreferredName())) {
|
||||
includeFrom = false;
|
||||
if (parser.currentToken() != XContentParser.Token.VALUE_NULL) {
|
||||
from = rangeType.parseFrom(fieldType, parser, coerce.value(), includeFrom);
|
||||
parsedFrom = rangeType.parseFrom(fieldType, parser, coerce.value(), includeFrom);
|
||||
}
|
||||
} else if (fieldName.equals(GTE_FIELD.getPreferredName())) {
|
||||
includeFrom = true;
|
||||
if (parser.currentToken() != XContentParser.Token.VALUE_NULL) {
|
||||
from = rangeType.parseFrom(fieldType, parser, coerce.value(), includeFrom);
|
||||
parsedFrom = rangeType.parseFrom(fieldType, parser, coerce.value(), includeFrom);
|
||||
}
|
||||
} else if (fieldName.equals(LT_FIELD.getPreferredName())) {
|
||||
includeTo = false;
|
||||
if (parser.currentToken() != XContentParser.Token.VALUE_NULL) {
|
||||
to = rangeType.parseTo(fieldType, parser, coerce.value(), includeTo);
|
||||
parsedTo = rangeType.parseTo(fieldType, parser, coerce.value(), includeTo);
|
||||
}
|
||||
} else if (fieldName.equals(LTE_FIELD.getPreferredName())) {
|
||||
includeTo = true;
|
||||
if (parser.currentToken() != XContentParser.Token.VALUE_NULL) {
|
||||
to = rangeType.parseTo(fieldType, parser, coerce.value(), includeTo);
|
||||
parsedTo = rangeType.parseTo(fieldType, parser, coerce.value(), includeTo);
|
||||
}
|
||||
} else {
|
||||
throw new DocumentParsingException(
|
||||
|
@ -427,20 +447,10 @@ public class RangeFieldMapper extends FieldMapper {
|
|||
}
|
||||
}
|
||||
}
|
||||
range = new Range(rangeType, from, to, includeFrom, includeTo);
|
||||
} else if (fieldType().rangeType == RangeType.IP && start == XContentParser.Token.VALUE_STRING) {
|
||||
range = parseIpRangeFromCidr(parser);
|
||||
} else {
|
||||
throw new DocumentParsingException(
|
||||
parser.getTokenLocation(),
|
||||
"error parsing field [" + name() + "], expected an object but got " + parser.currentName()
|
||||
);
|
||||
}
|
||||
context.doc().addAll(fieldType().rangeType.createFields(context, name(), range, index, hasDocValues, store));
|
||||
Object from = parsedFrom != null ? parsedFrom : rangeType.defaultFrom(parsedTo);
|
||||
Object to = parsedTo != null ? parsedTo : rangeType.defaultTo(parsedFrom);
|
||||
|
||||
if (hasDocValues == false && (index || store)) {
|
||||
context.addToFieldNames(fieldType().name());
|
||||
}
|
||||
return new Range(rangeType, from, to, includeFrom, includeTo);
|
||||
}
|
||||
|
||||
private static Range parseIpRangeFromCidr(final XContentParser parser) throws IOException {
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.elasticsearch.lucene.queries.BinaryDocValuesRangeQuery;
|
|||
import org.elasticsearch.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
|
@ -64,6 +65,26 @@ public enum RangeType {
|
|||
return included ? address : nextDown(address);
|
||||
}
|
||||
|
||||
public Object defaultFrom(Object parsedTo) {
|
||||
if (parsedTo == null) {
|
||||
return minValue();
|
||||
}
|
||||
|
||||
// Make sure that we keep the range inside the same address family.
|
||||
// `minValue()` is always IPv6 so we need to adjust it.
|
||||
return parsedTo instanceof Inet4Address ? InetAddressPoint.decode(new byte[4]) : minValue();
|
||||
}
|
||||
|
||||
public Object defaultTo(Object parsedFrom) {
|
||||
if (parsedFrom == null) {
|
||||
return maxValue();
|
||||
}
|
||||
|
||||
// Make sure that we keep the range inside the same address family.
|
||||
// `maxValue()` is always IPv6 so we need to adjust it.
|
||||
return parsedFrom instanceof Inet4Address ? InetAddressPoint.decode(new byte[] { -1, -1, -1, -1 }) : maxValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress parseValue(Object value, boolean coerce, @Nullable DateMathParser dateMathParser) {
|
||||
if (value instanceof InetAddress) {
|
||||
|
@ -844,6 +865,14 @@ public enum RangeType {
|
|||
return included ? value : (Number) nextDown(value);
|
||||
}
|
||||
|
||||
public Object defaultFrom(Object parsedTo) {
|
||||
return minValue();
|
||||
}
|
||||
|
||||
public Object defaultTo(Object parsedFrom) {
|
||||
return maxValue();
|
||||
}
|
||||
|
||||
public abstract Object minValue();
|
||||
|
||||
public abstract Object maxValue();
|
||||
|
|
|
@ -87,6 +87,37 @@ public class IpRangeFieldMapperTests extends RangeFieldMapperTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testNullBounds() throws IOException {
|
||||
DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> {
|
||||
minimalMapping(b);
|
||||
b.field("store", true);
|
||||
}));
|
||||
|
||||
ParsedDocument bothNull = mapper.parse(source(b -> b.startObject("field").nullField("gte").nullField("lte").endObject()));
|
||||
assertThat(storedValue(bothNull), equalTo("[:: : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]"));
|
||||
|
||||
ParsedDocument onlyFromIPv4 = mapper.parse(
|
||||
source(b -> b.startObject("field").field("gte", rangeValue()).nullField("lte").endObject())
|
||||
);
|
||||
assertThat(storedValue(onlyFromIPv4), equalTo("[192.168.1.7 : 255.255.255.255]"));
|
||||
|
||||
ParsedDocument onlyToIPv4 = mapper.parse(
|
||||
source(b -> b.startObject("field").nullField("gte").field("lte", rangeValue()).endObject())
|
||||
);
|
||||
assertThat(storedValue(onlyToIPv4), equalTo("[0.0.0.0 : 192.168.1.7]"));
|
||||
|
||||
ParsedDocument onlyFromIPv6 = mapper.parse(
|
||||
source(b -> b.startObject("field").field("gte", "2001:db8::").nullField("lte").endObject())
|
||||
);
|
||||
assertThat(storedValue(onlyFromIPv6), equalTo("[2001:db8:: : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]"));
|
||||
|
||||
ParsedDocument onlyToIPv6 = mapper.parse(
|
||||
source(b -> b.startObject("field").nullField("gte").field("lte", "2001:db8::").endObject())
|
||||
);
|
||||
assertThat(storedValue(onlyToIPv6), equalTo("[:: : 2001:db8::]"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testValidSyntheticSource() throws IOException {
|
||||
CheckedConsumer<XContentBuilder, IOException> mapping = b -> {
|
||||
|
|
|
@ -236,14 +236,14 @@ public abstract class RangeFieldMapperTests extends MapperTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
private static String storedValue(ParsedDocument doc) {
|
||||
protected static String storedValue(ParsedDocument doc) {
|
||||
assertEquals(3, doc.rootDoc().getFields("field").size());
|
||||
List<IndexableField> fields = doc.rootDoc().getFields("field");
|
||||
IndexableField storedField = fields.get(2);
|
||||
return storedField.stringValue();
|
||||
}
|
||||
|
||||
public final void testNullBounds() throws IOException {
|
||||
public void testNullBounds() throws IOException {
|
||||
|
||||
// null, null => min, max
|
||||
assertNullBounds(b -> b.startObject("field").nullField("gte").nullField("lte").endObject(), true, true);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue