diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search/370_ip_field_doc_values.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search/370_ip_field_doc_values.yml new file mode 100644 index 0000000000000..33419c5bb223c --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search/370_ip_field_doc_values.yml @@ -0,0 +1,134 @@ +setup: + - skip: + features: [ "headers" ] + version: " - 2.11.99" + reason: "searching with only doc_values was added in 2.12.0" + +--- +"search on ip fields with doc_values enabled": + - do: + indices.create: + index: test-iodvq + body: + mappings: + dynamic: false + properties: + ip_index: + type: ip + doc_values: false + ip_doc_values: + type: ip + index: false + ip_both: + type: ip + index: true + doc_values: true + + + - do: + headers: + Content-Type: application/json + index: + index: "test-iodvq" + id: 1 + body: + ip_index: "192.168.0.1" + ip_doc_values: "192.168.0.2" + ip_both: "192.168.0.3" + + - do: + headers: + Content-Type: application/json + index: + index: "test-iodvq" + id: 2 + body: + ip_index: "192.168.1.1" + ip_doc_values: "192.168.1.2" + ip_both: "192.168.1.3" + + + - do: + headers: + Content-Type: application/json + index: + index: "test-iodvq" + id: 3 + body: + ip_index: "192.168.2.1" + ip_doc_values: "192.168.2.2" + ip_both: "192.168.2.3" + + + - do: + indices.refresh: {} + + - do: + search: + rest_total_hits_as_int: true + index: test-iodvq + body: + query: + term: + ip_index: "192.168.0.1" + + - match: {hits.total: 1} + + - do: + search: + rest_total_hits_as_int: true + index: test-iodvq + body: + query: + term: + ip_doc_values: "192.168.0.2" + + - match: { hits.total: 1 } + + - do: + search: + rest_total_hits_as_int: true + index: test-iodvq + body: + query: + term: + ip_both: "192.168.0.3" + + - match: { hits.total: 1 } + + - do: + search: + rest_total_hits_as_int: true + index: test-iodvq + body: + query: + terms: + ip_index: ["192.168.0.1", "192.168.1.1"] + + - match: { hits.total: 2 } + + - do: + search: + rest_total_hits_as_int: true + index: test-iodvq + body: + query: + range: + ip_doc_values: + gte: "192.168.0.2" + + - match: { hits.total: 3 } + + + - do: + search: + rest_total_hits_as_int: true + index: test-iodvq + body: + query: + range: + ip_both: + gte: "192.168.0.2" + lte: "192.168.2.2" + + - match: { hits.total: 2 } diff --git a/server/src/main/java/org/opensearch/index/mapper/IpFieldMapper.java b/server/src/main/java/org/opensearch/index/mapper/IpFieldMapper.java index 2a677d8bc1352..4f1f703585fb0 100644 --- a/server/src/main/java/org/opensearch/index/mapper/IpFieldMapper.java +++ b/server/src/main/java/org/opensearch/index/mapper/IpFieldMapper.java @@ -36,7 +36,9 @@ import org.apache.lucene.document.SortedSetDocValuesField; import org.apache.lucene.document.StoredField; import org.apache.lucene.index.SortedSetDocValues; +import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.MatchNoDocsQuery; +import org.apache.lucene.search.PointRangeQuery; import org.apache.lucene.search.Query; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.BytesRef; @@ -222,9 +224,10 @@ protected Object parseSourceValue(Object value) { @Override public Query termQuery(Object value, @Nullable QueryShardContext context) { - failIfNotIndexed(); + failIfNotIndexedAndNoDocValues(); + Query query; if (value instanceof InetAddress) { - return InetAddressPoint.newExactQuery(name(), (InetAddress) value); + query = InetAddressPoint.newExactQuery(name(), (InetAddress) value); } else { if (value instanceof BytesRef) { value = ((BytesRef) value).utf8ToString(); @@ -232,15 +235,39 @@ public Query termQuery(Object value, @Nullable QueryShardContext context) { String term = value.toString(); if (term.contains("/")) { final Tuple cidr = InetAddresses.parseCidr(term); - return InetAddressPoint.newPrefixQuery(name(), cidr.v1(), cidr.v2()); + query = InetAddressPoint.newPrefixQuery(name(), cidr.v1(), cidr.v2()); } InetAddress address = InetAddresses.forString(term); - return InetAddressPoint.newExactQuery(name(), address); + query = InetAddressPoint.newExactQuery(name(), address); } + if (isSearchable() && hasDocValues()) { + return new IndexOrDocValuesQuery( + query, + SortedSetDocValuesField.newSlowRangeQuery( + ((PointRangeQuery) query).getField(), + new BytesRef(((PointRangeQuery) query).getLowerPoint()), + new BytesRef(((PointRangeQuery) query).getUpperPoint()), + true, + true + ) + ); + } + if (hasDocValues()) { + // InetAddressPoint uses a rangeQuery internally for terms + return SortedSetDocValuesField.newSlowRangeQuery( + ((PointRangeQuery) query).getField(), + new BytesRef(((PointRangeQuery) query).getLowerPoint()), + new BytesRef(((PointRangeQuery) query).getUpperPoint()), + true, + true + ); + } + return query; } @Override public Query termsQuery(List values, QueryShardContext context) { + failIfNotIndexedAndNoDocValues(); InetAddress[] addresses = new InetAddress[values.size()]; int i = 0; for (Object value : values) { @@ -265,14 +292,32 @@ public Query termsQuery(List values, QueryShardContext context) { @Override public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, QueryShardContext context) { - failIfNotIndexed(); - return rangeQuery( - lowerTerm, - upperTerm, - includeLower, - includeUpper, - (lower, upper) -> InetAddressPoint.newRangeQuery(name(), lower, upper) - ); + failIfNotIndexedAndNoDocValues(); + return rangeQuery(lowerTerm, upperTerm, includeLower, includeUpper, (lower, upper) -> { + Query query = InetAddressPoint.newRangeQuery(name(), lower, upper); + if (isSearchable() && hasDocValues()) { + return new IndexOrDocValuesQuery( + query, + SortedSetDocValuesField.newSlowRangeQuery( + ((PointRangeQuery) query).getField(), + new BytesRef(((PointRangeQuery) query).getLowerPoint()), + new BytesRef(((PointRangeQuery) query).getUpperPoint()), + true, + true + ) + ); + } + if (hasDocValues()) { + return SortedSetDocValuesField.newSlowRangeQuery( + ((PointRangeQuery) query).getField(), + new BytesRef(((PointRangeQuery) query).getLowerPoint()), + new BytesRef(((PointRangeQuery) query).getUpperPoint()), + true, + true + ); + } + return query; + }); } /**