Skip to content

Commit 8154007

Browse files
jordan-powerssmalyshev
authored andcommitted
Natively store synthetic source array offsets for numeric fields (elastic#124594)
This patch builds on the work in elastic#122999 and elastic#113757 to natively store array offsets for numeric fields instead of falling back to ignored source when `source_keep_mode: arrays`.
1 parent 7971727 commit 8154007

File tree

42 files changed

+1093
-137
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1093
-137
lines changed

docs/changelog/124594.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 124594
2+
summary: Store arrays offsets for numeric fields natively with synthetic source
3+
area: Mapping
4+
type: enhancement
5+
issues: []

server/src/main/java/org/elasticsearch/index/IndexVersions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ private static Version parseUnchecked(String version) {
152152
public static final IndexVersion SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_KEYWORD = def(9_013_0_00, Version.LUCENE_10_1_0);
153153
public static final IndexVersion SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_IP = def(9_014_0_00, Version.LUCENE_10_1_0);
154154
public static final IndexVersion ADD_RESCORE_PARAMS_TO_QUANTIZED_VECTORS = def(9_015_0_00, Version.LUCENE_10_1_0);
155+
public static final IndexVersion SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_NUMBER = def(9_016_0_00, Version.LUCENE_10_1_0);
155156
/*
156157
* STOP! READ THIS FIRST! No, really,
157158
* ____ _____ ___ ____ _ ____ _____ _ ____ _____ _ _ ___ ____ _____ ___ ____ ____ _____ _

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ public boolean newDynamicLongField(DocumentParserContext context, String name) t
353353
ScriptCompiler.NONE,
354354
context.indexSettings().getSettings(),
355355
context.indexSettings().getIndexVersionCreated(),
356-
context.indexSettings().getMode()
356+
context.indexSettings().getMode(),
357+
context.indexSettings().sourceKeepMode()
357358
),
358359
context
359360
);
@@ -371,7 +372,8 @@ public boolean newDynamicDoubleField(DocumentParserContext context, String name)
371372
ScriptCompiler.NONE,
372373
context.indexSettings().getSettings(),
373374
context.indexSettings().getIndexVersionCreated(),
374-
context.indexSettings().getMode()
375+
context.indexSettings().getMode(),
376+
context.indexSettings().sourceKeepMode()
375377
),
376378
context
377379
);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ static String getOffsetsFieldName(
9797
&& sourceKeepMode == Mapper.SourceKeepMode.ARRAYS
9898
&& hasDocValues
9999
&& isStored == false
100+
&& context.isInNestedContext() == false
100101
&& fieldMapperBuilder.copyTo.copyToFields().isEmpty()
101102
&& fieldMapperBuilder.multiFieldsBuilder.hasMultiFields() == false
102103
&& indexVersionSupportStoringArraysNatively(indexCreatedVersion, minSupportedVersionMain)) {

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

Lines changed: 106 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.elasticsearch.common.settings.Settings;
3838
import org.elasticsearch.index.IndexMode;
3939
import org.elasticsearch.index.IndexVersion;
40+
import org.elasticsearch.index.IndexVersions;
4041
import org.elasticsearch.index.fielddata.FieldDataContext;
4142
import org.elasticsearch.index.fielddata.IndexFieldData;
4243
import org.elasticsearch.index.fielddata.IndexNumericFieldData.NumericType;
@@ -70,6 +71,7 @@
7071
import java.io.IOException;
7172
import java.math.BigDecimal;
7273
import java.time.ZoneId;
74+
import java.util.ArrayList;
7375
import java.util.Arrays;
7476
import java.util.Collection;
7577
import java.util.Collections;
@@ -80,6 +82,8 @@
8082
import java.util.function.BiFunction;
8183
import java.util.function.Function;
8284

85+
import static org.elasticsearch.index.mapper.FieldArrayContext.getOffsetsFieldName;
86+
8387
/** A {@link FieldMapper} for numeric types: byte, short, int, long, float and double. */
8488
public class NumberFieldMapper extends FieldMapper {
8589

@@ -127,20 +131,31 @@ public static final class Builder extends FieldMapper.DimensionBuilder {
127131
private final IndexVersion indexCreatedVersion;
128132

129133
private final IndexMode indexMode;
134+
private final SourceKeepMode indexSourceKeepMode;
130135

131136
public Builder(
132137
String name,
133138
NumberType type,
134139
ScriptCompiler compiler,
135140
Settings settings,
136141
IndexVersion indexCreatedVersion,
137-
IndexMode mode
142+
IndexMode mode,
143+
SourceKeepMode indexSourceKeepMode
138144
) {
139-
this(name, type, compiler, IGNORE_MALFORMED_SETTING.get(settings), COERCE_SETTING.get(settings), indexCreatedVersion, mode);
145+
this(
146+
name,
147+
type,
148+
compiler,
149+
IGNORE_MALFORMED_SETTING.get(settings),
150+
COERCE_SETTING.get(settings),
151+
indexCreatedVersion,
152+
mode,
153+
indexSourceKeepMode
154+
);
140155
}
141156

142157
public static Builder docValuesOnly(String name, NumberType type, IndexVersion indexCreatedVersion) {
143-
Builder builder = new Builder(name, type, ScriptCompiler.NONE, false, false, indexCreatedVersion, null);
158+
Builder builder = new Builder(name, type, ScriptCompiler.NONE, false, false, indexCreatedVersion, null, null);
144159
builder.indexed.setValue(false);
145160
builder.dimension.setValue(false);
146161
return builder;
@@ -153,7 +168,8 @@ public Builder(
153168
boolean ignoreMalformedByDefault,
154169
boolean coerceByDefault,
155170
IndexVersion indexCreatedVersion,
156-
IndexMode mode
171+
IndexMode mode,
172+
SourceKeepMode indexSourceKeepMode
157173
) {
158174
super(name);
159175
this.type = type;
@@ -209,6 +225,8 @@ public Builder(
209225

210226
this.script.precludesParameters(ignoreMalformed, coerce, nullValue);
211227
addScriptValidation(script, indexed, hasDocValues);
228+
229+
this.indexSourceKeepMode = indexSourceKeepMode;
212230
}
213231

214232
Builder nullValue(Number number) {
@@ -272,7 +290,16 @@ public NumberFieldMapper build(MapperBuilderContext context) {
272290
MappedFieldType ft = new NumberFieldType(context.buildFullName(leafName()), this, context.isSourceSynthetic());
273291
hasScript = script.get() != null;
274292
onScriptError = onScriptErrorParam.getValue();
275-
return new NumberFieldMapper(leafName(), ft, builderParams(this, context), context.isSourceSynthetic(), this);
293+
String offsetsFieldName = getOffsetsFieldName(
294+
context,
295+
indexSourceKeepMode,
296+
hasDocValues.getValue(),
297+
stored.getValue(),
298+
this,
299+
indexCreatedVersion,
300+
IndexVersions.SYNTHETIC_SOURCE_STORE_ARRAYS_NATIVELY_NUMBER
301+
);
302+
return new NumberFieldMapper(leafName(), ft, builderParams(this, context), context.isSourceSynthetic(), this, offsetsFieldName);
276303
}
277304
}
278305

@@ -445,13 +472,8 @@ private static void validateFiniteValue(float value) {
445472
}
446473

447474
@Override
448-
SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName, boolean ignoreMalformed) {
449-
return new SortedNumericDocValuesSyntheticFieldLoader(fieldName, fieldSimpleName, ignoreMalformed) {
450-
@Override
451-
protected void writeValue(XContentBuilder b, long value) throws IOException {
452-
b.value(HalfFloatPoint.sortableShortToHalfFloat((short) value));
453-
}
454-
};
475+
public void writeValue(XContentBuilder b, long value) throws IOException {
476+
b.value(HalfFloatPoint.sortableShortToHalfFloat((short) value));
455477
}
456478

457479
@Override
@@ -634,13 +656,8 @@ private static void validateFiniteValue(float value) {
634656
}
635657

636658
@Override
637-
SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName, boolean ignoreMalformed) {
638-
return new SortedNumericDocValuesSyntheticFieldLoader(fieldName, fieldSimpleName, ignoreMalformed) {
639-
@Override
640-
protected void writeValue(XContentBuilder b, long value) throws IOException {
641-
b.value(NumericUtils.sortableIntToFloat((int) value));
642-
}
643-
};
659+
public void writeValue(XContentBuilder b, long value) throws IOException {
660+
b.value(NumericUtils.sortableIntToFloat((int) value));
644661
}
645662

646663
@Override
@@ -789,13 +806,8 @@ private static void validateParsed(double value) {
789806
}
790807

791808
@Override
792-
SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName, boolean ignoreMalformed) {
793-
return new SortedNumericDocValuesSyntheticFieldLoader(fieldName, fieldSimpleName, ignoreMalformed) {
794-
@Override
795-
protected void writeValue(XContentBuilder b, long value) throws IOException {
796-
b.value(NumericUtils.sortableLongToDouble(value));
797-
}
798-
};
809+
public void writeValue(XContentBuilder b, long value) throws IOException {
810+
b.value(NumericUtils.sortableLongToDouble(value));
799811
}
800812

801813
@Override
@@ -838,12 +850,12 @@ public Number parsePoint(byte[] value) {
838850
}
839851

840852
@Override
841-
public Short parse(XContentParser parser, boolean coerce) throws IOException {
853+
public Byte parse(XContentParser parser, boolean coerce) throws IOException {
842854
int value = parser.intValue(coerce);
843855
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
844856
throw new IllegalArgumentException("Value [" + value + "] is out of range for a byte");
845857
}
846-
return (short) value;
858+
return (byte) value;
847859
}
848860

849861
@Override
@@ -912,8 +924,8 @@ public IndexFieldData.Builder getValueFetcherFieldDataBuilder(
912924
}
913925

914926
@Override
915-
SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName, boolean ignoreMalformed) {
916-
return NumberType.syntheticLongFieldLoader(fieldName, fieldSimpleName, ignoreMalformed);
927+
public void writeValue(XContentBuilder b, long value) throws IOException {
928+
b.value(value);
917929
}
918930

919931
@Override
@@ -1030,8 +1042,8 @@ public IndexFieldData.Builder getValueFetcherFieldDataBuilder(
10301042
}
10311043

10321044
@Override
1033-
SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName, boolean ignoreMalformed) {
1034-
return NumberType.syntheticLongFieldLoader(fieldName, fieldSimpleName, ignoreMalformed);
1045+
public void writeValue(XContentBuilder b, long value) throws IOException {
1046+
b.value(value);
10351047
}
10361048

10371049
@Override
@@ -1222,8 +1234,8 @@ public IndexFieldData.Builder getValueFetcherFieldDataBuilder(
12221234
}
12231235

12241236
@Override
1225-
SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName, boolean ignoreMalformed) {
1226-
return NumberType.syntheticLongFieldLoader(fieldName, fieldSimpleName, ignoreMalformed);
1237+
public void writeValue(XContentBuilder b, long value) throws IOException {
1238+
b.value(value);
12271239
}
12281240

12291241
@Override
@@ -1374,8 +1386,8 @@ public IndexFieldData.Builder getValueFetcherFieldDataBuilder(
13741386
}
13751387

13761388
@Override
1377-
SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName, boolean ignoreMalformed) {
1378-
return syntheticLongFieldLoader(fieldName, fieldSimpleName, ignoreMalformed);
1389+
public void writeValue(XContentBuilder b, long value) throws IOException {
1390+
b.value(value);
13791391
}
13801392

13811393
@Override
@@ -1427,7 +1439,15 @@ private boolean isOutOfRange(Object value) {
14271439
this.name = name;
14281440
this.numericType = numericType;
14291441
this.parser = createTypeParserWithLegacySupport(
1430-
(n, c) -> new Builder(n, this, c.scriptCompiler(), c.getSettings(), c.indexVersionCreated(), c.getIndexSettings().getMode())
1442+
(n, c) -> new Builder(
1443+
n,
1444+
this,
1445+
c.scriptCompiler(),
1446+
c.getSettings(),
1447+
c.indexVersionCreated(),
1448+
c.getIndexSettings().getMode(),
1449+
c.getIndexSettings().sourceKeepMode()
1450+
)
14311451
);
14321452
}
14331453

@@ -1658,17 +1678,13 @@ public double reduceToStoredPrecision(double value) {
16581678
return ((Number) value).doubleValue();
16591679
}
16601680

1661-
abstract SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName, boolean ignoreMalformed);
1681+
abstract void writeValue(XContentBuilder builder, long longValue) throws IOException;
16621682

1663-
private static SourceLoader.SyntheticFieldLoader syntheticLongFieldLoader(
1664-
String fieldName,
1665-
String fieldSimpleName,
1666-
boolean ignoreMalformed
1667-
) {
1683+
SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName, boolean ignoreMalformed) {
16681684
return new SortedNumericDocValuesSyntheticFieldLoader(fieldName, fieldSimpleName, ignoreMalformed) {
16691685
@Override
1670-
protected void writeValue(XContentBuilder b, long value) throws IOException {
1671-
b.value(value);
1686+
public void writeValue(XContentBuilder b, long value) throws IOException {
1687+
NumberType.this.writeValue(b, value);
16721688
}
16731689
};
16741690
}
@@ -2036,15 +2052,18 @@ public MetricType getMetricType() {
20362052
private boolean allowMultipleValues;
20372053
private final IndexVersion indexCreatedVersion;
20382054
private final boolean isSyntheticSource;
2055+
private final String offsetsFieldName;
20392056

20402057
private final IndexMode indexMode;
2058+
private final SourceKeepMode indexSourceKeepMode;
20412059

20422060
private NumberFieldMapper(
20432061
String simpleName,
20442062
MappedFieldType mappedFieldType,
20452063
BuilderParams builderParams,
20462064
boolean isSyntheticSource,
2047-
Builder builder
2065+
Builder builder,
2066+
String offsetsFieldName
20482067
) {
20492068
super(simpleName, mappedFieldType, builderParams);
20502069
this.type = builder.type;
@@ -2065,6 +2084,8 @@ private NumberFieldMapper(
20652084
this.indexCreatedVersion = builder.indexCreatedVersion;
20662085
this.isSyntheticSource = isSyntheticSource;
20672086
this.indexMode = builder.indexMode;
2087+
this.offsetsFieldName = offsetsFieldName;
2088+
this.indexSourceKeepMode = builder.indexSourceKeepMode;
20682089
}
20692090

20702091
boolean coerce() {
@@ -2081,6 +2102,11 @@ public NumberFieldType fieldType() {
20812102
return (NumberFieldType) super.fieldType();
20822103
}
20832104

2105+
@Override
2106+
public String getOffsetFieldName() {
2107+
return offsetsFieldName;
2108+
}
2109+
20842110
public NumberType type() {
20852111
return type;
20862112
}
@@ -2109,7 +2135,17 @@ protected void parseCreateField(DocumentParserContext context) throws IOExceptio
21092135
}
21102136
if (value != null) {
21112137
indexValue(context, value);
2138+
} else {
2139+
value = fieldType().nullValue;
2140+
}
2141+
if (offsetsFieldName != null && context.isImmediateParentAnArray() && context.canAddIgnoredField()) {
2142+
if (value != null) {
2143+
context.getOffSetContext().recordOffset(offsetsFieldName, (Comparable<?>) value);
2144+
} else {
2145+
context.getOffSetContext().recordNull(offsetsFieldName);
2146+
}
21122147
}
2148+
21132149
}
21142150

21152151
/**
@@ -2170,11 +2206,16 @@ protected void indexScriptValues(
21702206

21712207
@Override
21722208
public FieldMapper.Builder getMergeBuilder() {
2173-
return new Builder(leafName(), type, scriptCompiler, ignoreMalformedByDefault, coerceByDefault, indexCreatedVersion, indexMode)
2174-
.dimension(dimension)
2175-
.metric(metricType)
2176-
.allowMultipleValues(allowMultipleValues)
2177-
.init(this);
2209+
return new Builder(
2210+
leafName(),
2211+
type,
2212+
scriptCompiler,
2213+
ignoreMalformedByDefault,
2214+
coerceByDefault,
2215+
indexCreatedVersion,
2216+
indexMode,
2217+
indexSourceKeepMode
2218+
).dimension(dimension).metric(metricType).allowMultipleValues(allowMultipleValues).init(this);
21782219
}
21792220

21802221
@Override
@@ -2186,10 +2227,23 @@ public void doValidate(MappingLookup lookup) {
21862227
}
21872228
}
21882229

2230+
private SourceLoader.SyntheticFieldLoader docValuesSyntheticFieldLoader() {
2231+
if (offsetsFieldName != null) {
2232+
var layers = new ArrayList<CompositeSyntheticFieldLoader.Layer>();
2233+
layers.add(new SortedNumericWithOffsetsDocValuesSyntheticFieldLoaderLayer(fullPath(), offsetsFieldName, type::writeValue));
2234+
if (ignoreMalformed.value()) {
2235+
layers.add(new CompositeSyntheticFieldLoader.MalformedValuesLayer(fullPath()));
2236+
}
2237+
return new CompositeSyntheticFieldLoader(leafName(), fullPath(), layers);
2238+
} else {
2239+
return type.syntheticFieldLoader(fullPath(), leafName(), ignoreMalformed.value());
2240+
}
2241+
}
2242+
21892243
@Override
21902244
protected SyntheticSourceSupport syntheticSourceSupport() {
21912245
if (hasDocValues) {
2192-
return new SyntheticSourceSupport.Native(() -> type.syntheticFieldLoader(fullPath(), leafName(), ignoreMalformed.value()));
2246+
return new SyntheticSourceSupport.Native(this::docValuesSyntheticFieldLoader);
21932247
}
21942248

21952249
return super.syntheticSourceSupport();

0 commit comments

Comments
 (0)