-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Store arrays offsets for ip fields natively with synthetic source #122999
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
62a3b50
2286562
581fc2a
2136120
061e791
2a72a77
86a1aa0
77c30b1
d6e23da
17432fe
951a0b0
75de0d0
b530453
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| pr: 122999 | ||
| summary: Store arrays offsets for ip fields natively with synthetic source | ||
| area: Mapping | ||
| type: enhancement | ||
| issues: [] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,6 +55,7 @@ | |
| import java.util.Objects; | ||
| import java.util.function.BiFunction; | ||
|
|
||
| import static org.elasticsearch.index.mapper.FieldArrayContext.getOffsetsFieldName; | ||
| import static org.elasticsearch.index.mapper.IpPrefixAutomatonUtil.buildIpPrefixAutomaton; | ||
|
|
||
| /** | ||
|
|
@@ -92,8 +93,15 @@ public static final class Builder extends FieldMapper.DimensionBuilder { | |
| private final boolean ignoreMalformedByDefault; | ||
| private final IndexVersion indexCreatedVersion; | ||
| private final ScriptCompiler scriptCompiler; | ||
| private final SourceKeepMode indexSourceKeepMode; | ||
|
|
||
| public Builder(String name, ScriptCompiler scriptCompiler, boolean ignoreMalformedByDefault, IndexVersion indexCreatedVersion) { | ||
| public Builder( | ||
| String name, | ||
| ScriptCompiler scriptCompiler, | ||
| boolean ignoreMalformedByDefault, | ||
| IndexVersion indexCreatedVersion, | ||
| SourceKeepMode indexSourceKeepMode | ||
| ) { | ||
| super(name); | ||
| this.scriptCompiler = Objects.requireNonNull(scriptCompiler); | ||
| this.ignoreMalformedByDefault = ignoreMalformedByDefault; | ||
|
|
@@ -114,6 +122,7 @@ public Builder(String name, ScriptCompiler scriptCompiler, boolean ignoreMalform | |
| ); | ||
| } | ||
| }); | ||
| this.indexSourceKeepMode = indexSourceKeepMode; | ||
| } | ||
|
|
||
| Builder nullValue(String nullValue) { | ||
|
|
@@ -184,6 +193,15 @@ public IpFieldMapper build(MapperBuilderContext context) { | |
| } | ||
| hasScript = script.get() != null; | ||
| onScriptError = onScriptErrorParam.getValue(); | ||
|
|
||
| String offsetsFieldName = getOffsetsFieldName( | ||
| context, | ||
| indexSourceKeepMode, | ||
| hasDocValues.getValue(), | ||
| stored.getValue(), | ||
| indexCreatedVersion, | ||
| this | ||
| ); | ||
| return new IpFieldMapper( | ||
| leafName(), | ||
| new IpFieldType( | ||
|
|
@@ -198,15 +216,16 @@ public IpFieldMapper build(MapperBuilderContext context) { | |
| ), | ||
| builderParams(this, context), | ||
| context.isSourceSynthetic(), | ||
| this | ||
| this, | ||
| offsetsFieldName | ||
| ); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| public static final TypeParser PARSER = createTypeParserWithLegacySupport((n, c) -> { | ||
| boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(c.getSettings()); | ||
| return new Builder(n, c.scriptCompiler(), ignoreMalformedByDefault, c.indexVersionCreated()); | ||
| return new Builder(n, c.scriptCompiler(), ignoreMalformedByDefault, c.indexVersionCreated(), c.getIndexSettings().sourceKeepMode()); | ||
| }); | ||
|
|
||
| public static final class IpFieldType extends SimpleMappedFieldType { | ||
|
|
@@ -501,13 +520,16 @@ public TermsEnum getTerms(IndexReader reader, String prefix, boolean caseInsensi | |
| private final Script script; | ||
| private final FieldValues<InetAddress> scriptValues; | ||
| private final ScriptCompiler scriptCompiler; | ||
| private final SourceKeepMode indexSourceKeepMode; | ||
| private final String offsetsFieldName; | ||
|
|
||
| private IpFieldMapper( | ||
| String simpleName, | ||
| MappedFieldType mappedFieldType, | ||
| BuilderParams builderParams, | ||
| boolean storeIgnored, | ||
| Builder builder | ||
| Builder builder, | ||
| String offsetsFieldName | ||
| ) { | ||
| super(simpleName, mappedFieldType, builderParams); | ||
| this.ignoreMalformedByDefault = builder.ignoreMalformedByDefault; | ||
|
|
@@ -523,6 +545,8 @@ private IpFieldMapper( | |
| this.scriptCompiler = builder.scriptCompiler; | ||
| this.dimension = builder.dimension.getValue(); | ||
| this.storeIgnored = storeIgnored; | ||
| this.indexSourceKeepMode = builder.indexSourceKeepMode; | ||
| this.offsetsFieldName = offsetsFieldName; | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -561,6 +585,14 @@ protected void parseCreateField(DocumentParserContext context) throws IOExceptio | |
| if (address != null) { | ||
| indexValue(context, address); | ||
| } | ||
| if (offsetsFieldName != null && context.isImmediateParentAnArray() && context.getRecordedSource() == false) { | ||
|
||
| if (address != null) { | ||
| BytesRef sortableValue = new BytesRef(InetAddressPoint.encode(address)); | ||
| context.getOffSetContext().recordOffset(offsetsFieldName, sortableValue); | ||
| } else { | ||
| context.getOffSetContext().recordNull(offsetsFieldName); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void indexValue(DocumentParserContext context, InetAddress address) { | ||
|
|
@@ -593,7 +625,9 @@ protected void indexScriptValues( | |
|
|
||
| @Override | ||
| public FieldMapper.Builder getMergeBuilder() { | ||
| return new Builder(leafName(), scriptCompiler, ignoreMalformedByDefault, indexCreatedVersion).dimension(dimension).init(this); | ||
| return new Builder(leafName(), scriptCompiler, ignoreMalformedByDefault, indexCreatedVersion, indexSourceKeepMode).dimension( | ||
| dimension | ||
| ).init(this); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -610,19 +644,24 @@ protected SyntheticSourceSupport syntheticSourceSupport() { | |
| if (hasDocValues) { | ||
| return new SyntheticSourceSupport.Native(() -> { | ||
| var layers = new ArrayList<CompositeSyntheticFieldLoader.Layer>(); | ||
| layers.add(new SortedSetDocValuesSyntheticFieldLoaderLayer(fullPath()) { | ||
| @Override | ||
| protected BytesRef convert(BytesRef value) { | ||
| byte[] bytes = Arrays.copyOfRange(value.bytes, value.offset, value.offset + value.length); | ||
| return new BytesRef(NetworkAddress.format(InetAddressPoint.decode(bytes))); | ||
| } | ||
|
|
||
| @Override | ||
| protected BytesRef preserve(BytesRef value) { | ||
| // No need to copy because convert has made a deep copy | ||
| return value; | ||
| } | ||
| }); | ||
| if (offsetsFieldName != null) { | ||
| layers.add( | ||
| new SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer(fullPath(), offsetsFieldName, IpFieldMapper::convert) | ||
| ); | ||
| } else { | ||
| layers.add(new SortedSetDocValuesSyntheticFieldLoaderLayer(fullPath()) { | ||
| @Override | ||
| protected BytesRef convert(BytesRef value) { | ||
| return IpFieldMapper.convert(value); | ||
| } | ||
|
|
||
| @Override | ||
| protected BytesRef preserve(BytesRef value) { | ||
| // No need to copy because convert has made a deep copy | ||
| return value; | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| if (ignoreMalformed) { | ||
| layers.add(new CompositeSyntheticFieldLoader.MalformedValuesLayer(fullPath())); | ||
|
|
@@ -633,4 +672,14 @@ protected BytesRef preserve(BytesRef value) { | |
|
|
||
| return super.syntheticSourceSupport(); | ||
| } | ||
|
|
||
| static BytesRef convert(BytesRef value) { | ||
| byte[] bytes = Arrays.copyOfRange(value.bytes, value.offset, value.offset + value.length); | ||
| return new BytesRef(NetworkAddress.format(InetAddressPoint.decode(bytes))); | ||
| } | ||
|
|
||
| @Override | ||
| public String getOffsetFieldName() { | ||
| return offsetsFieldName; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
|
|
||
| import java.io.IOException; | ||
| import java.util.Objects; | ||
| import java.util.function.Function; | ||
|
|
||
| /** | ||
| * Load {@code _source} fields from {@link SortedSetDocValues} and associated {@link BinaryDocValues}. The former contains the unique values | ||
|
|
@@ -30,11 +31,17 @@ final class SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer implements Co | |
|
|
||
| private final String name; | ||
| private final String offsetsFieldName; | ||
| private final Function<BytesRef, BytesRef> converter; | ||
| private DocValuesWithOffsetsLoader docValues; | ||
|
|
||
| SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer(String name, String offsetsFieldName) { | ||
| this(name, offsetsFieldName, Function.identity()); | ||
| } | ||
|
|
||
| SortedSetWithOffsetsDocValuesSyntheticFieldLoaderLayer(String name, String offsetsFieldName, Function<BytesRef, BytesRef> converter) { | ||
| this.name = Objects.requireNonNull(name); | ||
| this.offsetsFieldName = Objects.requireNonNull(offsetsFieldName); | ||
| this.converter = Objects.requireNonNull(converter); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -47,7 +54,7 @@ public DocValuesLoader docValuesLoader(LeafReader leafReader, int[] docIdsInLeaf | |
| SortedSetDocValues valueDocValues = DocValues.getSortedSet(leafReader, name); | ||
| SortedDocValues offsetDocValues = DocValues.getSorted(leafReader, offsetsFieldName); | ||
|
|
||
| return docValues = new DocValuesWithOffsetsLoader(valueDocValues, offsetDocValues); | ||
| return docValues = new DocValuesWithOffsetsLoader(valueDocValues, offsetDocValues, converter); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -78,15 +85,21 @@ public void write(XContentBuilder b) throws IOException { | |
| static final class DocValuesWithOffsetsLoader implements DocValuesLoader { | ||
| private final SortedDocValues offsetDocValues; | ||
| private final SortedSetDocValues valueDocValues; | ||
| private final Function<BytesRef, BytesRef> converter; | ||
| private final ByteArrayStreamInput scratch = new ByteArrayStreamInput(); | ||
|
|
||
| private boolean hasValue; | ||
| private boolean hasOffset; | ||
| private int[] offsetToOrd; | ||
|
|
||
| DocValuesWithOffsetsLoader(SortedSetDocValues valueDocValues, SortedDocValues offsetDocValues) { | ||
| DocValuesWithOffsetsLoader( | ||
| SortedSetDocValues valueDocValues, | ||
| SortedDocValues offsetDocValues, | ||
| Function<BytesRef, BytesRef> converter | ||
| ) { | ||
| this.valueDocValues = valueDocValues; | ||
| this.offsetDocValues = offsetDocValues; | ||
| this.converter = converter; | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -146,7 +159,7 @@ public void write(XContentBuilder b) throws IOException { | |
|
|
||
| long ord = ords[offset]; | ||
| BytesRef c = valueDocValues.lookupOrd(ord); | ||
| // This is keyword specific and needs to be updated once support is added for other field types: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We still need a comment, as the value is written as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done: 86a1aa0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we enforce utf8 if this goes to xcontentbuilder anyway that has a generic |
||
| c = converter.apply(c); | ||
| b.utf8Value(c.bytes, c.offset, c.length); | ||
| } | ||
| } else if (offsetToOrd != null) { | ||
|
|
@@ -158,6 +171,7 @@ public void write(XContentBuilder b) throws IOException { | |
| } else { | ||
| for (int i = 0; i < valueDocValues.docValueCount(); i++) { | ||
| BytesRef c = valueDocValues.lookupOrd(valueDocValues.nextOrd()); | ||
| c = converter.apply(c); | ||
| b.utf8Value(c.bytes, c.offset, c.length); | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is address set to null, ever? It's set to
nullValueor value, iiuc.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nullValueis null by default, soaddresscan be set to null.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But then, should we be comparing to
nullValuehere and below?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point: 77c30b1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually that change fails the build. If we only check
nullValuethen alsovalueneeds to be checked...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pushed another commit