Skip to content

Commit 725a860

Browse files
authored
Fixed a bug where text fields in LogsDB indices did not use their keyword multi fields for block loading (#134253) (#134591)
1 parent ad66854 commit 725a860

File tree

20 files changed

+907
-140
lines changed

20 files changed

+907
-140
lines changed

docs/changelog/134253.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 134253
2+
summary: Fixed a bug where text fields in LogsDB indices did not use their keyword multi fields for block loading
3+
area: Mapping
4+
type: bug
5+
issues: []

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/MatchOnlyTextFieldMapper.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,7 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
247247
String parentField = searchExecutionContext.parentPath(name());
248248
var parent = searchExecutionContext.lookup().fieldType(parentField);
249249

250-
if (parent instanceof KeywordFieldMapper.KeywordFieldType keywordParent
251-
&& keywordParent.ignoreAbove() != Integer.MAX_VALUE) {
250+
if (parent instanceof KeywordFieldMapper.KeywordFieldType keywordParent && keywordParent.ignoreAbove().isSet()) {
252251
if (parent.isStored()) {
253252
return storedFieldFetcher(parentField, keywordParent.originalName());
254253
} else if (parent.hasDocValues()) {
@@ -272,7 +271,7 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
272271
if (kwd != null) {
273272
var fieldType = kwd.fieldType();
274273

275-
if (fieldType.ignoreAbove() != Integer.MAX_VALUE) {
274+
if (fieldType.ignoreAbove().isSet()) {
276275
if (fieldType.isStored()) {
277276
return storedFieldFetcher(fieldType.name(), fieldType.originalName());
278277
} else if (fieldType.hasDocValues()) {

plugins/analysis-icu/src/main/java/org/elasticsearch/plugin/analysis/icu/ICUCollationKeywordFieldMapper.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -250,12 +250,10 @@ public static class Builder extends FieldMapper.Builder {
250250
false
251251
).acceptsNull();
252252

253-
final Parameter<Integer> ignoreAbove = Parameter.intParam("ignore_above", true, m -> toType(m).ignoreAbove, Integer.MAX_VALUE)
254-
.addValidator(v -> {
255-
if (v < 0) {
256-
throw new IllegalArgumentException("[ignore_above] must be positive, got [" + v + "]");
257-
}
258-
});
253+
final Parameter<Integer> ignoreAbove = Parameter.ignoreAboveParam(
254+
m -> toType(m).ignoreAbove,
255+
IgnoreAbove.IGNORE_ABOVE_DEFAULT_VALUE
256+
);
259257
final Parameter<String> nullValue = Parameter.stringParam("null_value", false, m -> toType(m).nullValue, null).acceptsNull();
260258

261259
public Builder(String name) {

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -812,20 +812,21 @@ public Iterator<Setting<?>> settings() {
812812

813813
public static final Setting<Integer> IGNORE_ABOVE_SETTING = Setting.intSetting(
814814
"index.mapping.ignore_above",
815-
IndexSettings::getIgnoreAboveDefaultValue,
815+
settings -> String.valueOf(getIgnoreAboveDefaultValue(settings)),
816816
0,
817817
Integer.MAX_VALUE,
818818
Property.IndexScope,
819819
Property.ServerlessPublic
820820
);
821821

822-
private static String getIgnoreAboveDefaultValue(final Settings settings) {
823-
if (IndexSettings.MODE.get(settings) == IndexMode.LOGSDB
824-
&& IndexMetadata.SETTING_INDEX_VERSION_CREATED.get(settings).onOrAfter(IndexVersions.ENABLE_IGNORE_ABOVE_LOGSDB)) {
825-
return "8191";
826-
} else {
827-
return String.valueOf(Integer.MAX_VALUE);
822+
private static int getIgnoreAboveDefaultValue(final Settings settings) {
823+
if (settings == null) {
824+
return Mapper.IgnoreAbove.IGNORE_ABOVE_DEFAULT_VALUE;
828825
}
826+
return Mapper.IgnoreAbove.getIgnoreAboveDefaultValue(
827+
IndexSettings.MODE.get(settings),
828+
IndexMetadata.SETTING_INDEX_VERSION_CREATED.get(settings)
829+
);
829830
}
830831

831832
public static final NodeFeature IGNORE_ABOVE_INDEX_LEVEL_SETTING = new NodeFeature("mapper.ignore_above_index_level_setting", true);

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,14 @@ public static Parameter<Boolean> docValuesParam(Function<FieldMapper, Boolean> i
13111311
return Parameter.boolParam("doc_values", false, initializer, defaultValue);
13121312
}
13131313

1314+
public static Parameter<Integer> ignoreAboveParam(Function<FieldMapper, Integer> initializer, int defaultValue) {
1315+
return Parameter.intParam("ignore_above", true, initializer, defaultValue).addValidator(v -> {
1316+
if (v < 0) {
1317+
throw new IllegalArgumentException("[ignore_above] must be positive, got [" + v + "]");
1318+
}
1319+
});
1320+
}
1321+
13141322
/**
13151323
* Defines a script parameter
13161324
* @param initializer retrieves the equivalent parameter from an existing FieldMapper for use in merges
@@ -1681,6 +1689,12 @@ public TypeParser(
16811689
this(builderFunction, (n, c) -> contextValidator.forEach(v -> v.accept(n, c)), IndexVersions.MINIMUM_COMPATIBLE);
16821690
}
16831691

1692+
private static final IndexVersion MINIMUM_LEGACY_COMPATIBILITY_VERSION = IndexVersion.fromId(5000099);
1693+
1694+
public static TypeParser createTypeParserWithLegacySupport(BiFunction<String, MappingParserContext, Builder> builderFunction) {
1695+
return new TypeParser(builderFunction, MINIMUM_LEGACY_COMPATIBILITY_VERSION);
1696+
}
1697+
16841698
private TypeParser(
16851699
BiFunction<String, MappingParserContext, Builder> builderFunction,
16861700
BiConsumer<String, MappingParserContext> contextValidator,

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

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.elasticsearch.common.unit.Fuzziness;
4343
import org.elasticsearch.core.Nullable;
4444
import org.elasticsearch.features.NodeFeature;
45+
import org.elasticsearch.index.IndexMode;
4546
import org.elasticsearch.index.IndexVersion;
4647
import org.elasticsearch.index.IndexVersions;
4748
import org.elasticsearch.index.analysis.IndexAnalyzers;
@@ -90,6 +91,7 @@
9091
import static org.elasticsearch.core.Strings.format;
9192
import static org.elasticsearch.index.IndexSettings.IGNORE_ABOVE_SETTING;
9293
import static org.elasticsearch.index.mapper.FieldArrayContext.getOffsetsFieldName;
94+
import static org.elasticsearch.index.mapper.Mapper.IgnoreAbove.getIgnoreAboveDefaultValue;
9395

9496
/**
9597
* A field mapper for keywords. This mapper accepts strings and indexes them as-is.
@@ -169,6 +171,7 @@ public static final class Builder extends FieldMapper.DimensionBuilder {
169171
);
170172
private final Parameter<Integer> ignoreAbove;
171173
private final int ignoreAboveDefault;
174+
private final IndexMode indexMode;
172175

173176
private final Parameter<String> indexOptions = TextParams.keywordIndexOptions(m -> toType(m).indexOptions);
174177
private final Parameter<Boolean> hasNorms = TextParams.norms(false, m -> toType(m).fieldType.omitNorms() == false);
@@ -206,16 +209,36 @@ public Builder(final String name, final MappingParserContext mappingParserContex
206209
mappingParserContext.scriptCompiler(),
207210
IGNORE_ABOVE_SETTING.get(mappingParserContext.getSettings()),
208211
mappingParserContext.getIndexSettings().getIndexVersionCreated(),
212+
mappingParserContext.getIndexSettings().getMode(),
209213
mappingParserContext.getIndexSettings().sourceKeepMode()
210214
);
211215
}
212216

213217
Builder(
218+
String name,
219+
IndexAnalyzers indexAnalyzers,
220+
ScriptCompiler scriptCompiler,
221+
IndexVersion indexCreatedVersion,
222+
SourceKeepMode sourceKeepMode
223+
) {
224+
this(
225+
name,
226+
indexAnalyzers,
227+
scriptCompiler,
228+
getIgnoreAboveDefaultValue(IndexMode.STANDARD, indexCreatedVersion),
229+
indexCreatedVersion,
230+
IndexMode.STANDARD,
231+
sourceKeepMode
232+
);
233+
}
234+
235+
private Builder(
214236
String name,
215237
IndexAnalyzers indexAnalyzers,
216238
ScriptCompiler scriptCompiler,
217239
int ignoreAboveDefault,
218240
IndexVersion indexCreatedVersion,
241+
IndexMode indexMode,
219242
SourceKeepMode indexSourceKeepMode
220243
) {
221244
super(name);
@@ -245,17 +268,13 @@ public Builder(final String name, final MappingParserContext mappingParserContex
245268
}
246269
}).precludesParameters(normalizer);
247270
this.ignoreAboveDefault = ignoreAboveDefault;
248-
this.ignoreAbove = Parameter.intParam("ignore_above", true, m -> toType(m).fieldType().ignoreAbove(), ignoreAboveDefault)
249-
.addValidator(v -> {
250-
if (v < 0) {
251-
throw new IllegalArgumentException("[ignore_above] must be positive, got [" + v + "]");
252-
}
253-
});
271+
this.ignoreAbove = Parameter.ignoreAboveParam(m -> toType(m).fieldType().ignoreAbove().get(), ignoreAboveDefault);
272+
this.indexMode = indexMode;
254273
this.indexSourceKeepMode = indexSourceKeepMode;
255274
}
256275

257276
public Builder(String name, IndexVersion indexCreatedVersion) {
258-
this(name, null, ScriptCompiler.NONE, Integer.MAX_VALUE, indexCreatedVersion, SourceKeepMode.NONE);
277+
this(name, null, ScriptCompiler.NONE, indexCreatedVersion, SourceKeepMode.NONE);
259278
}
260279

261280
public Builder ignoreAbove(int ignoreAbove) {
@@ -418,7 +437,9 @@ public KeywordFieldMapper build(MapperBuilderContext context) {
418437

419438
public static final class KeywordFieldType extends StringFieldType {
420439

421-
private final int ignoreAbove;
440+
private static final IgnoreAbove IGNORE_ABOVE_DEFAULT = new IgnoreAbove(null, IndexMode.STANDARD);
441+
442+
private final IgnoreAbove ignoreAbove;
422443
private final String nullValue;
423444
private final NamedAnalyzer normalizer;
424445
private final boolean eagerGlobalOrdinals;
@@ -446,18 +467,22 @@ public KeywordFieldType(
446467
);
447468
this.eagerGlobalOrdinals = builder.eagerGlobalOrdinals.getValue();
448469
this.normalizer = normalizer;
449-
this.ignoreAbove = builder.ignoreAbove.getValue();
470+
this.ignoreAbove = new IgnoreAbove(builder.ignoreAbove.getValue(), builder.indexMode, builder.indexCreatedVersion);
450471
this.nullValue = builder.nullValue.getValue();
451472
this.scriptValues = builder.scriptValues();
452473
this.isDimension = builder.dimension.getValue();
453474
this.isSyntheticSource = isSyntheticSource;
454475
this.originalName = isSyntheticSource ? name + "._original" : null;
455476
}
456477

478+
public KeywordFieldType(String name) {
479+
this(name, true, true, Collections.emptyMap());
480+
}
481+
457482
public KeywordFieldType(String name, boolean isIndexed, boolean hasDocValues, Map<String, String> meta) {
458483
super(name, isIndexed, false, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
459484
this.normalizer = Lucene.KEYWORD_ANALYZER;
460-
this.ignoreAbove = Integer.MAX_VALUE;
485+
this.ignoreAbove = IGNORE_ABOVE_DEFAULT;
461486
this.nullValue = null;
462487
this.eagerGlobalOrdinals = false;
463488
this.scriptValues = null;
@@ -466,10 +491,6 @@ public KeywordFieldType(String name, boolean isIndexed, boolean hasDocValues, Ma
466491
this.originalName = null;
467492
}
468493

469-
public KeywordFieldType(String name) {
470-
this(name, true, true, Collections.emptyMap());
471-
}
472-
473494
public KeywordFieldType(String name, FieldType fieldType) {
474495
super(
475496
name,
@@ -480,7 +501,7 @@ public KeywordFieldType(String name, FieldType fieldType) {
480501
Collections.emptyMap()
481502
);
482503
this.normalizer = Lucene.KEYWORD_ANALYZER;
483-
this.ignoreAbove = Integer.MAX_VALUE;
504+
this.ignoreAbove = IGNORE_ABOVE_DEFAULT;
484505
this.nullValue = null;
485506
this.eagerGlobalOrdinals = false;
486507
this.scriptValues = null;
@@ -492,7 +513,7 @@ public KeywordFieldType(String name, FieldType fieldType) {
492513
public KeywordFieldType(String name, NamedAnalyzer analyzer) {
493514
super(name, true, false, true, textSearchInfo(Defaults.FIELD_TYPE, null, analyzer, analyzer), Collections.emptyMap());
494515
this.normalizer = Lucene.KEYWORD_ANALYZER;
495-
this.ignoreAbove = Integer.MAX_VALUE;
516+
this.ignoreAbove = IGNORE_ABOVE_DEFAULT;
496517
this.nullValue = null;
497518
this.eagerGlobalOrdinals = false;
498519
this.scriptValues = null;
@@ -800,10 +821,7 @@ protected String parseSourceValue(Object value) {
800821
}
801822

802823
private String applyIgnoreAboveAndNormalizer(String value) {
803-
if (value.length() > ignoreAbove) {
804-
return null;
805-
}
806-
824+
if (ignoreAbove.isIgnored(value)) return null;
807825
return normalizeValue(normalizer(), name(), value);
808826
}
809827

@@ -922,7 +940,7 @@ public CollapseType collapseType() {
922940

923941
/** Values that have more chars than the return value of this method will
924942
* be skipped at parsing time. */
925-
public int ignoreAbove() {
943+
public IgnoreAbove ignoreAbove() {
926944
return ignoreAbove;
927945
}
928946

@@ -974,7 +992,7 @@ public String originalName() {
974992

975993
private final IndexAnalyzers indexAnalyzers;
976994
private final int ignoreAboveDefault;
977-
private final int ignoreAbove;
995+
private final IndexMode indexMode;
978996
private final String offsetsFieldName;
979997
private final SourceKeepMode indexSourceKeepMode;
980998
private final String originalName;
@@ -1003,7 +1021,7 @@ private KeywordFieldMapper(
10031021
this.indexCreatedVersion = builder.indexCreatedVersion;
10041022
this.isSyntheticSource = isSyntheticSource;
10051023
this.ignoreAboveDefault = builder.ignoreAboveDefault;
1006-
this.ignoreAbove = builder.ignoreAbove.getValue();
1024+
this.indexMode = builder.indexMode;
10071025
this.offsetsFieldName = offsetsFieldName;
10081026
this.indexSourceKeepMode = indexSourceKeepMode;
10091027
this.originalName = mappedFieldType.originalName();
@@ -1060,7 +1078,7 @@ private boolean indexValue(DocumentParserContext context, XContentString value)
10601078
return false;
10611079
}
10621080

1063-
if (value.stringLength() > fieldType().ignoreAbove()) {
1081+
if (fieldType().ignoreAbove().isIgnored(value)) {
10641082
context.addIgnoredField(fullPath());
10651083
if (isSyntheticSource) {
10661084
// Save a copy of the field so synthetic source can load it
@@ -1151,9 +1169,15 @@ public Map<String, NamedAnalyzer> indexAnalyzers() {
11511169

11521170
@Override
11531171
public FieldMapper.Builder getMergeBuilder() {
1154-
return new Builder(leafName(), indexAnalyzers, scriptCompiler, ignoreAboveDefault, indexCreatedVersion, indexSourceKeepMode)
1155-
.dimension(fieldType().isDimension())
1156-
.init(this);
1172+
return new Builder(
1173+
leafName(),
1174+
indexAnalyzers,
1175+
scriptCompiler,
1176+
ignoreAboveDefault,
1177+
indexCreatedVersion,
1178+
indexMode,
1179+
indexSourceKeepMode
1180+
).dimension(fieldType().isDimension()).init(this);
11571181
}
11581182

11591183
@Override
@@ -1216,7 +1240,7 @@ protected BytesRef preserve(BytesRef value) {
12161240
}
12171241
}
12181242

1219-
if (fieldType().ignoreAbove != Integer.MAX_VALUE) {
1243+
if (fieldType().ignoreAbove.isSet()) {
12201244
layers.add(new CompositeSyntheticFieldLoader.StoredFieldLayer(originalName) {
12211245
@Override
12221246
protected void writeValue(Object value, XContentBuilder b) throws IOException {

0 commit comments

Comments
 (0)