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/124050.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 124050
summary: Use `FallbackSyntheticSourceBlockLoader` for boolean and date fields
area: Mapping
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ public Builder builder(BlockFactory factory, int expectedCount) {
private FallbackSyntheticSourceBlockLoader.Reader<?> fallbackSyntheticSourceBlockLoaderReader() {
var nullValueAdjusted = nullValue != null ? adjustSourceValue(nullValue, scalingFactor) : null;

return new FallbackSyntheticSourceBlockLoader.ReaderWithNullValueSupport<>(nullValue) {
return new FallbackSyntheticSourceBlockLoader.ReaderWithNullValueSupport<Double>(nullValue) {
@Override
public void convertValue(Object value, List<Double> accumulator) {
if (coerce && value.equals("")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
Expand Down Expand Up @@ -162,7 +163,8 @@ public BooleanFieldMapper build(MapperBuilderContext context) {
nullValue.getValue(),
scriptValues(),
meta.getValue(),
dimension.getValue()
dimension.getValue(),
context.isSourceSynthetic()
);
hasScript = script.get() != null;
onScriptError = onScriptErrorParam.getValue();
Expand Down Expand Up @@ -194,6 +196,7 @@ public static final class BooleanFieldType extends TermBasedFieldType {
private final Boolean nullValue;
private final FieldValues<Boolean> scriptValues;
private final boolean isDimension;
private final boolean isSyntheticSource;

public BooleanFieldType(
String name,
Expand All @@ -203,12 +206,14 @@ public BooleanFieldType(
Boolean nullValue,
FieldValues<Boolean> scriptValues,
Map<String, String> meta,
boolean isDimension
boolean isDimension,
boolean isSyntheticSource
) {
super(name, isIndexed, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
this.nullValue = nullValue;
this.scriptValues = scriptValues;
this.isDimension = isDimension;
this.isSyntheticSource = isSyntheticSource;
}

public BooleanFieldType(String name) {
Expand All @@ -220,7 +225,7 @@ public BooleanFieldType(String name, boolean isIndexed) {
}

public BooleanFieldType(String name, boolean isIndexed, boolean hasDocValues) {
this(name, isIndexed, isIndexed, hasDocValues, false, null, Collections.emptyMap(), false);
this(name, isIndexed, isIndexed, hasDocValues, false, null, Collections.emptyMap(), false, false);
}

@Override
Expand Down Expand Up @@ -257,12 +262,16 @@ protected Boolean parseSourceValue(Object value) {
return (Boolean) value;
} else {
String textValue = value.toString();
return Booleans.parseBoolean(textValue.toCharArray(), 0, textValue.length(), false);
return parseBoolean(textValue);
}
}
};
}

private boolean parseBoolean(String text) {
return Booleans.parseBoolean(text.toCharArray(), 0, text.length(), false);
}

@Override
public BytesRef indexedValueForSearch(Object value) {
if (value == null) {
Expand Down Expand Up @@ -310,13 +319,62 @@ public BlockLoader blockLoader(BlockLoaderContext blContext) {
if (hasDocValues()) {
return new BlockDocValuesReader.BooleansBlockLoader(name());
}

if (isSyntheticSource) {
return new FallbackSyntheticSourceBlockLoader(fallbackSyntheticSourceBlockLoaderReader(), name()) {
@Override
public Builder builder(BlockFactory factory, int expectedCount) {
return factory.booleans(expectedCount);
}
};
}

ValueFetcher fetcher = sourceValueFetcher(blContext.sourcePaths(name()));
BlockSourceReader.LeafIteratorLookup lookup = isIndexed() || isStored()
? BlockSourceReader.lookupFromFieldNames(blContext.fieldNames(), name())
: BlockSourceReader.lookupMatchingAll();
return new BlockSourceReader.BooleansBlockLoader(fetcher, lookup);
}

private FallbackSyntheticSourceBlockLoader.Reader<?> fallbackSyntheticSourceBlockLoaderReader() {
return new FallbackSyntheticSourceBlockLoader.ReaderWithNullValueSupport<Boolean>(nullValue) {
@Override
public void convertValue(Object value, List<Boolean> accumulator) {
try {
if (value instanceof Boolean b) {
accumulator.add(b);
} else {
String stringValue = value.toString();
// Matches logic in parser invoked by `parseCreateField`
accumulator.add(parseBoolean(stringValue));
}
} catch (Exception e) {
// Malformed value, skip it
}
}

@Override
protected void parseNonNullValue(XContentParser parser, List<Boolean> accumulator) throws IOException {
// Aligned with implementation of `parseCreateField(XContentParser)`
try {
var value = parser.booleanValue();
accumulator.add(value);
} catch (Exception e) {
// Malformed value, skip it
}
}

@Override
public void writeToBlock(List<Boolean> values, BlockLoader.Builder blockBuilder) {
var longBuilder = (BlockLoader.BooleanBuilder) blockBuilder;

for (var value : values) {
longBuilder.appendBoolean(value);
}
}
};
}

@Override
public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) {
FielddataOperation operation = fieldDataContext.fielddataOperation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.search.runtime.LongScriptFieldDistanceFeatureQuery;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentParser;

import java.io.IOException;
import java.text.NumberFormat;
Expand All @@ -65,6 +66,7 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -370,6 +372,7 @@ public DateFieldMapper build(MapperBuilderContext context) {
index.getValue(),
store.getValue(),
docValues.getValue(),
context.isSourceSynthetic(),
buildFormatter(),
resolution,
nullValue.getValue(),
Expand Down Expand Up @@ -430,6 +433,7 @@ public static final class DateFieldType extends MappedFieldType {
private final String nullValue;
private final FieldValues<Long> scriptValues;
private final boolean pointsMetadataAvailable;
private final boolean isSyntheticSource;

public DateFieldType(
String name,
Expand All @@ -442,6 +446,34 @@ public DateFieldType(
String nullValue,
FieldValues<Long> scriptValues,
Map<String, String> meta
) {
this(
name,
isIndexed,
pointsMetadataAvailable,
isStored,
hasDocValues,
false,
dateTimeFormatter,
resolution,
nullValue,
scriptValues,
meta
);
}

public DateFieldType(
String name,
boolean isIndexed,
boolean pointsMetadataAvailable,
boolean isStored,
boolean hasDocValues,
boolean isSyntheticSource,
DateFormatter dateTimeFormatter,
Resolution resolution,
String nullValue,
FieldValues<Long> scriptValues,
Map<String, String> meta
) {
super(name, isIndexed, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
this.dateTimeFormatter = dateTimeFormatter;
Expand All @@ -450,6 +482,7 @@ public DateFieldType(
this.nullValue = nullValue;
this.scriptValues = scriptValues;
this.pointsMetadataAvailable = pointsMetadataAvailable;
this.isSyntheticSource = isSyntheticSource;
}

public DateFieldType(
Expand All @@ -463,11 +496,23 @@ public DateFieldType(
FieldValues<Long> scriptValues,
Map<String, String> meta
) {
this(name, isIndexed, isIndexed, isStored, hasDocValues, dateTimeFormatter, resolution, nullValue, scriptValues, meta);
this(name, isIndexed, isIndexed, isStored, hasDocValues, false, dateTimeFormatter, resolution, nullValue, scriptValues, meta);
}

public DateFieldType(String name) {
this(name, true, true, false, true, DEFAULT_DATE_TIME_FORMATTER, Resolution.MILLISECONDS, null, null, Collections.emptyMap());
this(
name,
true,
true,
false,
true,
false,
DEFAULT_DATE_TIME_FORMATTER,
Resolution.MILLISECONDS,
null,
null,
Collections.emptyMap()
);
}

public DateFieldType(String name, boolean isIndexed) {
Expand All @@ -477,6 +522,7 @@ public DateFieldType(String name, boolean isIndexed) {
isIndexed,
false,
true,
false,
DEFAULT_DATE_TIME_FORMATTER,
Resolution.MILLISECONDS,
null,
Expand All @@ -486,15 +532,15 @@ public DateFieldType(String name, boolean isIndexed) {
}

public DateFieldType(String name, DateFormatter dateFormatter) {
this(name, true, true, false, true, dateFormatter, Resolution.MILLISECONDS, null, null, Collections.emptyMap());
this(name, true, true, false, true, false, dateFormatter, Resolution.MILLISECONDS, null, null, Collections.emptyMap());
}

public DateFieldType(String name, Resolution resolution) {
this(name, true, true, false, true, DEFAULT_DATE_TIME_FORMATTER, resolution, null, null, Collections.emptyMap());
this(name, true, true, false, true, false, DEFAULT_DATE_TIME_FORMATTER, resolution, null, null, Collections.emptyMap());
}

public DateFieldType(String name, Resolution resolution, DateFormatter dateFormatter) {
this(name, true, true, false, true, dateFormatter, resolution, null, null, Collections.emptyMap());
this(name, true, true, false, true, false, dateFormatter, resolution, null, null, Collections.emptyMap());
}

@Override
Expand Down Expand Up @@ -806,12 +852,63 @@ public BlockLoader blockLoader(BlockLoaderContext blContext) {
if (hasDocValues()) {
return new BlockDocValuesReader.LongsBlockLoader(name());
}

if (isSyntheticSource) {
return new FallbackSyntheticSourceBlockLoader(fallbackSyntheticSourceBlockLoaderReader(), name()) {
@Override
public Builder builder(BlockFactory factory, int expectedCount) {
return factory.longs(expectedCount);
}
};
}

BlockSourceReader.LeafIteratorLookup lookup = isStored() || isIndexed()
? BlockSourceReader.lookupFromFieldNames(blContext.fieldNames(), name())
: BlockSourceReader.lookupMatchingAll();
return new BlockSourceReader.LongsBlockLoader(sourceValueFetcher(blContext.sourcePaths(name())), lookup);
}

private FallbackSyntheticSourceBlockLoader.Reader<?> fallbackSyntheticSourceBlockLoaderReader() {
Function<String, Long> dateParser = this::parse;

return new FallbackSyntheticSourceBlockLoader.ReaderWithNullValueSupport<Long>(nullValue) {
@Override
public void convertValue(Object value, List<Long> accumulator) {
try {
String date = value instanceof Number ? NUMBER_FORMAT.format(value) : value.toString();
accumulator.add(dateParser.apply(date));
} catch (Exception e) {
// Malformed value, skip it
}
}

@Override
protected void parseNonNullValue(XContentParser parser, List<Long> accumulator) throws IOException {
// Aligned with implementation of `parseCreateField(XContentParser)`
try {
String dateAsString = parser.textOrNull();

if (dateAsString == null) {
accumulator.add(dateParser.apply(nullValue));
} else {
accumulator.add(dateParser.apply(dateAsString));
}
} catch (Exception e) {
// Malformed value, skip it
}
}

@Override
public void writeToBlock(List<Long> values, BlockLoader.Builder blockBuilder) {
var longBuilder = (BlockLoader.LongBuilder) blockBuilder;

for (var value : values) {
longBuilder.appendLong(value);
}
}
};
}

@Override
public IndexFieldData.Builder fielddataBuilder(FieldDataContext fieldDataContext) {
FielddataOperation operation = fieldDataContext.fielddataOperation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,9 @@ public interface Reader<T> {
}

public abstract static class ReaderWithNullValueSupport<T> implements Reader<T> {
private final T nullValue;
private final Object nullValue;

public ReaderWithNullValueSupport(T nullValue) {
public ReaderWithNullValueSupport(Object nullValue) {
this.nullValue = nullValue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ public Builder builder(BlockFactory factory, int expectedCount) {

private FallbackSyntheticSourceBlockLoader.Reader<?> fallbackSyntheticSourceBlockLoaderReader() {
var nullValueBytes = nullValue != null ? new BytesRef(nullValue) : null;
return new FallbackSyntheticSourceBlockLoader.ReaderWithNullValueSupport<>(nullValueBytes) {
return new FallbackSyntheticSourceBlockLoader.ReaderWithNullValueSupport<BytesRef>(nullValueBytes) {
@Override
public void convertValue(Object value, List<BytesRef> accumulator) {
String stringValue = ((BytesRef) value).utf8ToString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ public void testRequireDocValuesOnDoubles() {
public void testRequireDocValuesOnBools() {
doTestRequireDocValues(new BooleanFieldMapper.BooleanFieldType("field"));
doTestRequireDocValues(
new BooleanFieldMapper.BooleanFieldType("field", true, false, false, null, null, Collections.emptyMap(), false)
new BooleanFieldMapper.BooleanFieldType("field", true, false, false, null, null, Collections.emptyMap(), false, false)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public void testFetchSourceValue() throws IOException {
true,
null,
Collections.emptyMap(),
false,
false
);
assertEquals(List.of(true), fetchSourceValue(nullFieldType, null));
Expand Down
Loading