Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/81396.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 81396
summary: "Script: fields API for IP mapped type"
area: Infra/Scripting
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
# Side Public License, v 1.
#

class org.elasticsearch.script.field.IPAddress {
(String)
boolean isV4()
boolean isV6()
}

class org.elasticsearch.painless.api.CIDR {
(String)
boolean contains(String)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,11 @@ class org.elasticsearch.script.field.KeywordDocValuesField @dynamic_type {
String get(String)
String get(int, String)
}

class org.elasticsearch.script.field.IpDocValuesField @dynamic_type {
IPAddress get(IPAddress)
IPAddress get(int, IPAddress)
List asStrings()
String asString(String)
String asString(int, String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,6 @@ class org.apache.lucene.util.BytesRef {
String utf8ToString()
}

class org.elasticsearch.index.mapper.IpFieldMapper$IpFieldType$IpScriptDocValues {
String get(int)
String getValue()
}

class org.elasticsearch.search.lookup.FieldLookup {
def getValue()
List getValues()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ setup:
date: 2017-01-01T12:11:12
nanos: 2015-01-01T12:10:30.123456789Z
geo_point: 41.12,-71.34
ip: 192.168.0.1
ip: 192.168.0.19
keyword: not split at all
long: 12348732141234
integer: 134134566
Expand All @@ -79,6 +79,7 @@ setup:
body:
rank: 3
boolean: [true, false, true]
ip: ["10.1.2.3", "2001:db8::2:1"]
date: [2017-01-01T12:11:12, 2018-01-01T12:11:12]
nanos: [2015-01-01T12:10:30.123456789Z, 2015-01-01T12:10:30.987654321Z]
keyword: ["one string", "another string"]
Expand Down Expand Up @@ -526,7 +527,7 @@ setup:
field:
script:
source: "doc['ip'].get(0)"
- match: { hits.hits.0.fields.field.0: "192.168.0.1" }
- match: { hits.hits.0.fields.field.0: "192.168.0.19" }

- do:
search:
Expand All @@ -537,7 +538,76 @@ setup:
field:
script:
source: "doc['ip'].value"
- match: { hits.hits.0.fields.field.0: "192.168.0.1" }
- match: { hits.hits.0.fields.field.0: "192.168.0.19" }

- do:
search:
rest_total_hits_as_int: true
body:
sort: [ { rank: asc } ]
script_fields:
field:
script:
source: "field('ip').get(new IPAddress('127.0.0.1'))"
field_string:
script:
source: "field('ip').asString('127.0.0.1')"
- match: { hits.hits.0.fields.field.0: "192.168.0.19" }
- match: { hits.hits.0.fields.field_string.0: "192.168.0.19" }
- match: { hits.hits.1.fields.field.0: "127.0.0.1" }
- match: { hits.hits.1.fields.field_string.0: "127.0.0.1" }
- match: { hits.hits.2.fields.field.0: "10.1.2.3" }
- match: { hits.hits.2.fields.field_string.0: "10.1.2.3" }

- do:
search:
rest_total_hits_as_int: true
body:
sort: [ { rank: asc } ]
script_fields:
field:
script:
source: "field('ip').get(1, new IPAddress('127.0.0.1'))"
field_string:
script:
source: "field('ip').asString(1, '127.0.0.1')"
- match: { hits.hits.0.fields.field.0: "127.0.0.1" }
- match: { hits.hits.0.fields.field_string.0: "127.0.0.1" }
- match: { hits.hits.1.fields.field.0: "127.0.0.1" }
- match: { hits.hits.1.fields.field_string.0: "127.0.0.1" }
- match: { hits.hits.2.fields.field.0: "2001:db8::2:1" }
- match: { hits.hits.2.fields.field_string.0: "2001:db8::2:1" }

- do:
search:
rest_total_hits_as_int: true
body:
sort: [ { rank: asc } ]
script_fields:
field:
script:
source: "String.join(',', field('ip').asStrings())"
- match: { hits.hits.0.fields.field.0: "192.168.0.19" }
- match: { hits.hits.1.fields.field.0: "" }
- match: { hits.hits.2.fields.field.0: "10.1.2.3,2001:db8::2:1" }

- do:
search:
rest_total_hits_as_int: true
body:
sort: [ { rank: asc } ]
runtime_mappings:
ip_script_field:
type: ip
script:
source: "for (IPAddress addr : field('ip')) { String ip = addr.toString(); emit(ip.substring(0, ip.length() - 1) + field('ip').size()) }"
script_fields:
field:
script:
source: "field('ip_script_field').get(new IPAddress('1.2.3.4'))"
- match: { hits.hits.0.fields.field.0: "192.168.0.11" }
- match: { hits.hits.1.fields.field.0: "1.2.3.4" }
- match: { hits.hits.2.fields.field.0: "10.1.2.2" }

---
"keyword":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,45 +8,39 @@

package org.elasticsearch.index.fielddata;

import org.apache.lucene.document.InetAddressPoint;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.index.fielddata.ScriptDocValues.Strings;
import org.elasticsearch.index.fielddata.ScriptDocValues.StringsSupplier;
import org.elasticsearch.index.mapper.IpFieldMapper;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.script.IpFieldScript;
import org.elasticsearch.script.field.DelegateDocValuesField;
import org.elasticsearch.script.field.DocValuesField;
import org.elasticsearch.script.field.ToScriptField;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.search.aggregations.support.ValuesSourceType;

import java.net.InetAddress;

public class IpScriptFieldData extends BinaryScriptFieldData {
public static class Builder implements IndexFieldData.Builder {
private final String name;
private final IpFieldScript.LeafFactory leafFactory;
private final ToScriptField<SortedBinaryDocValues> toScriptField;

public Builder(String name, IpFieldScript.LeafFactory leafFactory) {
public Builder(String name, IpFieldScript.LeafFactory leafFactory, ToScriptField<SortedBinaryDocValues> toScriptField) {
this.name = name;
this.leafFactory = leafFactory;
this.toScriptField = toScriptField;
}

@Override
public IpScriptFieldData build(IndexFieldDataCache cache, CircuitBreakerService breakerService) {
return new IpScriptFieldData(name, leafFactory);
return new IpScriptFieldData(name, leafFactory, toScriptField);
}
}

private final IpFieldScript.LeafFactory leafFactory;
private final ToScriptField<SortedBinaryDocValues> toScriptField;

private IpScriptFieldData(String fieldName, IpFieldScript.LeafFactory leafFactory) {
private IpScriptFieldData(String fieldName, IpFieldScript.LeafFactory leafFactory, ToScriptField<SortedBinaryDocValues> toScriptField) {
super(fieldName);
this.leafFactory = leafFactory;
this.toScriptField = toScriptField;
}

@Override
Expand All @@ -55,7 +49,7 @@ public BinaryScriptLeafFieldData loadDirect(LeafReaderContext context) throws Ex
return new BinaryScriptLeafFieldData() {
@Override
public DocValuesField<?> getScriptField(String name) {
return new DelegateDocValuesField(new Strings(new IpSupplier(getBytesValues())), name);
return toScriptField.getScriptField(getBytesValues(), name);
}

@Override
Expand All @@ -69,22 +63,4 @@ public SortedBinaryDocValues getBytesValues() {
public ValuesSourceType getValuesSourceType() {
return CoreValuesSourceType.IP;
}

/**
* Doc values supplier implementation for ips. We can't share
* {@link IpFieldMapper.IpFieldType.IpScriptDocValues} because it is based
* on global ordinals and we don't have those.
*/
public static class IpSupplier extends StringsSupplier {

public IpSupplier(SortedBinaryDocValues in) {
super(in);
}

@Override
protected String bytesToString(BytesRef bytesRef) {
InetAddress addr = InetAddressPoint.decode(BytesReference.toBytes(new BytesArray(bytesRef)));
return InetAddresses.toAddrString(addr);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@
import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.ArrayUtil;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.Version;
import org.elasticsearch.common.bytes.BytesReference;
Expand All @@ -27,14 +25,12 @@
import org.elasticsearch.core.Nullable;
import org.elasticsearch.core.Tuple;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.ScriptDocValues;
import org.elasticsearch.index.fielddata.plain.SortedSetOrdinalsIndexFieldData;
import org.elasticsearch.index.mapper.IpFieldMapper.IpFieldType.IpScriptDocValues.IpSupplier;
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.script.IpFieldScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptCompiler;
import org.elasticsearch.script.field.DelegateDocValuesField;
import org.elasticsearch.script.field.IpDocValuesField;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.search.lookup.FieldValues;
Expand All @@ -44,7 +40,6 @@
import java.io.IOException;
import java.net.InetAddress;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -351,79 +346,10 @@ public static Query rangeQuery(
return builder.apply(lower, upper);
}

public static final class IpScriptDocValues extends ScriptDocValues<String> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for clarity, this all can be deleted because we use the other version now for doc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved it to IpDocValuesField.SortedSetIpSupplier. Seemed to make more sense there.


public static final class IpSupplier implements ScriptDocValues.Supplier<String> {

private final SortedSetDocValues in;
private long[] ords = new long[0];
private int count;

public IpSupplier(SortedSetDocValues in) {
this.in = in;
}

@Override
public void setNextDocId(int docId) throws IOException {
count = 0;
if (in.advanceExact(docId)) {
for (long ord = in.nextOrd(); ord != SortedSetDocValues.NO_MORE_ORDS; ord = in.nextOrd()) {
ords = ArrayUtil.grow(ords, count + 1);
ords[count++] = ord;
}
}
}

@Override
public String getInternal(int index) {
try {
BytesRef encoded = in.lookupOrd(ords[index]);
InetAddress address = InetAddressPoint.decode(
Arrays.copyOfRange(encoded.bytes, encoded.offset, encoded.offset + encoded.length)
);
return InetAddresses.toAddrString(address);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Override
public int size() {
return count;
}
}

public IpScriptDocValues(IpSupplier supplier) {
super(supplier);
}

public String getValue() {
if (supplier.size() == 0) {
return null;
} else {
return get(0);
}
}

@Override
public String get(int index) {
return supplier.getInternal(index);
}

@Override
public int size() {
return supplier.size();
}
}

@Override
public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
failIfNoDocValues();
return new SortedSetOrdinalsIndexFieldData.Builder(
name(),
CoreValuesSourceType.IP,
(dv, n) -> new DelegateDocValuesField(new IpScriptDocValues(new IpSupplier(dv)), n)
);
return new SortedSetOrdinalsIndexFieldData.Builder(name(), CoreValuesSourceType.IP, IpDocValuesField::new);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.elasticsearch.script.CompositeFieldScript;
import org.elasticsearch.script.IpFieldScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.field.IpDocValuesField;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.search.runtime.IpScriptFieldExistsQuery;
Expand Down Expand Up @@ -91,7 +92,7 @@ public DocValueFormat docValueFormat(String format, ZoneId timeZone) {

@Override
public IpScriptFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName, Supplier<SearchLookup> searchLookup) {
return new IpScriptFieldData.Builder(name(), leafFactory(searchLookup.get()));
return new IpScriptFieldData.Builder(name(), leafFactory(searchLookup.get()), IpDocValuesField::new);
}

@Override
Expand Down
Loading