|
@@ -14,6 +14,7 @@ import org.apache.lucene.document.StoredField;
|
|
|
import org.apache.lucene.index.IndexOptions;
|
|
|
import org.apache.lucene.search.Query;
|
|
|
import org.apache.lucene.util.BytesRef;
|
|
|
+import org.elasticsearch.common.Explicit;
|
|
|
import org.elasticsearch.common.Strings;
|
|
|
import org.elasticsearch.common.bytes.BytesReference;
|
|
|
import org.elasticsearch.common.util.CollectionUtils;
|
|
@@ -28,6 +29,7 @@ import java.io.IOException;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.Collections;
|
|
|
import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
|
|
|
public class SourceFieldMapper extends MetadataFieldMapper {
|
|
|
public static final String NAME = "_source";
|
|
@@ -36,17 +38,22 @@ public class SourceFieldMapper extends MetadataFieldMapper {
|
|
|
public static final String CONTENT_TYPE = "_source";
|
|
|
private final XContentFieldFilter filter;
|
|
|
|
|
|
+ /** The source mode */
|
|
|
+ private enum Mode {
|
|
|
+ DISABLED,
|
|
|
+ STORED,
|
|
|
+ SYNTHETIC
|
|
|
+ }
|
|
|
+
|
|
|
private static final SourceFieldMapper DEFAULT = new SourceFieldMapper(
|
|
|
- Defaults.ENABLED,
|
|
|
- Defaults.SYNTHETIC,
|
|
|
+ null,
|
|
|
+ Explicit.IMPLICIT_TRUE,
|
|
|
Strings.EMPTY_ARRAY,
|
|
|
Strings.EMPTY_ARRAY
|
|
|
);
|
|
|
|
|
|
public static class Defaults {
|
|
|
public static final String NAME = SourceFieldMapper.NAME;
|
|
|
- public static final boolean ENABLED = true;
|
|
|
- public static final boolean SYNTHETIC = false;
|
|
|
|
|
|
public static final FieldType FIELD_TYPE = new FieldType();
|
|
|
|
|
@@ -64,10 +71,22 @@ public class SourceFieldMapper extends MetadataFieldMapper {
|
|
|
|
|
|
public static class Builder extends MetadataFieldMapper.Builder {
|
|
|
|
|
|
- private final Parameter<Boolean> enabled = Parameter.boolParam("enabled", false, m -> toType(m).enabled, Defaults.ENABLED)
|
|
|
+ private final Parameter<Explicit<Boolean>> enabled = Parameter.explicitBoolParam("enabled", false, m -> toType(m).enabled, true)
|
|
|
+ .setSerializerCheck((includeDefaults, isConfigured, value) -> value.explicit())
|
|
|
// this field mapper may be enabled but once enabled, may not be disabled
|
|
|
- .setMergeValidator((previous, current, conflicts) -> (previous == current) || (previous && current == false));
|
|
|
- private final Parameter<Boolean> synthetic = Parameter.boolParam("synthetic", false, m -> toType(m).synthetic, false);
|
|
|
+ .setMergeValidator(
|
|
|
+ (previous, current, conflicts) -> (previous.value() == current.value()) || (previous.value() && current.value() == false)
|
|
|
+ );
|
|
|
+ private final Parameter<Mode> mode = new Parameter<>(
|
|
|
+ "mode",
|
|
|
+ true,
|
|
|
+ () -> null,
|
|
|
+ (n, c, o) -> Mode.valueOf(o.toString().toUpperCase(Locale.ROOT)),
|
|
|
+ m -> toType(m).enabled.explicit() ? null : toType(m).mode,
|
|
|
+ (b, n, v) -> b.field(n, v.toString().toLowerCase(Locale.ROOT)),
|
|
|
+ v -> v.toString().toLowerCase(Locale.ROOT)
|
|
|
+ ).setMergeValidator((previous, current, conflicts) -> (previous == current) || current != Mode.STORED)
|
|
|
+ .setSerializerCheck((includeDefaults, isConfigured, value) -> value != null); // don't emit if `enabled` is configured
|
|
|
private final Parameter<List<String>> includes = Parameter.stringArrayParam(
|
|
|
"includes",
|
|
|
false,
|
|
@@ -86,25 +105,32 @@ public class SourceFieldMapper extends MetadataFieldMapper {
|
|
|
@Override
|
|
|
protected Parameter<?>[] getParameters() {
|
|
|
if (IndexSettings.isTimeSeriesModeEnabled()) {
|
|
|
- return new Parameter<?>[] { enabled, synthetic, includes, excludes };
|
|
|
+ return new Parameter<?>[] { enabled, mode, includes, excludes };
|
|
|
}
|
|
|
return new Parameter<?>[] { enabled, includes, excludes };
|
|
|
}
|
|
|
|
|
|
+ private boolean isDefault() {
|
|
|
+ if (mode.get() != null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (enabled.get().value() == false) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return includes.getValue().isEmpty() && excludes.getValue().isEmpty();
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public SourceFieldMapper build() {
|
|
|
- if (enabled.getValue() == Defaults.ENABLED
|
|
|
- && synthetic.getValue() == Defaults.SYNTHETIC
|
|
|
- && includes.getValue().isEmpty()
|
|
|
- && excludes.getValue().isEmpty()) {
|
|
|
- return DEFAULT;
|
|
|
+ if (enabled.getValue().explicit() && mode.get() != null) {
|
|
|
+ throw new MapperParsingException("Cannot set both [mode] and [enabled] parameters");
|
|
|
}
|
|
|
- if (enabled.getValue() == false && synthetic.getValue()) {
|
|
|
- throw new IllegalArgumentException("_source may not be disabled when setting [synthetic: true]");
|
|
|
+ if (isDefault()) {
|
|
|
+ return DEFAULT;
|
|
|
}
|
|
|
return new SourceFieldMapper(
|
|
|
- enabled.getValue(),
|
|
|
- synthetic.getValue(),
|
|
|
+ mode.get(),
|
|
|
+ enabled.get(),
|
|
|
includes.getValue().toArray(String[]::new),
|
|
|
excludes.getValue().toArray(String[]::new)
|
|
|
);
|
|
@@ -140,32 +166,48 @@ public class SourceFieldMapper extends MetadataFieldMapper {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private final boolean enabled;
|
|
|
+ // nullable for bwc reasons
|
|
|
+ private final @Nullable Mode mode;
|
|
|
+ private final Explicit<Boolean> enabled;
|
|
|
+
|
|
|
/** indicates whether the source will always exist and be complete, for use by features like the update API */
|
|
|
private final boolean complete;
|
|
|
- private final boolean synthetic;
|
|
|
|
|
|
private final String[] includes;
|
|
|
private final String[] excludes;
|
|
|
|
|
|
- private SourceFieldMapper(boolean enabled, boolean synthetic, String[] includes, String[] excludes) {
|
|
|
- super(new SourceFieldType(enabled));
|
|
|
+ private SourceFieldMapper(Mode mode, Explicit<Boolean> enabled, String[] includes, String[] excludes) {
|
|
|
+ super(new SourceFieldType((enabled.explicit() && enabled.value()) || (enabled.explicit() == false && mode != Mode.DISABLED)));
|
|
|
+ assert enabled.explicit() == false || mode == null;
|
|
|
+ this.mode = mode;
|
|
|
this.enabled = enabled;
|
|
|
- this.synthetic = synthetic;
|
|
|
this.includes = includes;
|
|
|
this.excludes = excludes;
|
|
|
final boolean filtered = CollectionUtils.isEmpty(includes) == false || CollectionUtils.isEmpty(excludes) == false;
|
|
|
- if (filtered && synthetic) {
|
|
|
+ if (filtered && mode == Mode.SYNTHETIC) {
|
|
|
throw new IllegalArgumentException("filtering the stored _source is incompatible with synthetic source");
|
|
|
}
|
|
|
- this.filter = enabled && filtered
|
|
|
+ this.filter = stored() && filtered
|
|
|
? XContentFieldFilter.newFieldFilter(includes, excludes)
|
|
|
: (sourceBytes, contentType) -> sourceBytes;
|
|
|
- this.complete = enabled && synthetic == false && CollectionUtils.isEmpty(includes) && CollectionUtils.isEmpty(excludes);
|
|
|
+ this.complete = stored() && CollectionUtils.isEmpty(includes) && CollectionUtils.isEmpty(excludes);
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean stored() {
|
|
|
+ if (enabled.explicit() || mode == null) {
|
|
|
+ return enabled.value();
|
|
|
+ }
|
|
|
+ return mode == Mode.STORED;
|
|
|
}
|
|
|
|
|
|
public boolean enabled() {
|
|
|
- return enabled;
|
|
|
+ if (enabled.explicit()) {
|
|
|
+ return enabled.value();
|
|
|
+ }
|
|
|
+ if (mode != null) {
|
|
|
+ return mode != Mode.DISABLED;
|
|
|
+ }
|
|
|
+ return enabled.value();
|
|
|
}
|
|
|
|
|
|
public boolean isComplete() {
|
|
@@ -193,7 +235,7 @@ public class SourceFieldMapper extends MetadataFieldMapper {
|
|
|
|
|
|
@Nullable
|
|
|
public BytesReference applyFilters(@Nullable BytesReference originalSource, @Nullable XContentType contentType) throws IOException {
|
|
|
- if (enabled && synthetic == false && originalSource != null) {
|
|
|
+ if (stored() && originalSource != null) {
|
|
|
// Percolate and tv APIs may not set the source and that is ok, because these APIs will not index any data
|
|
|
return filter.apply(originalSource, contentType);
|
|
|
} else {
|
|
@@ -215,13 +257,13 @@ public class SourceFieldMapper extends MetadataFieldMapper {
|
|
|
* Build something to load source {@code _source}.
|
|
|
*/
|
|
|
public <T> SourceLoader newSourceLoader(Mapping mapping) {
|
|
|
- if (synthetic) {
|
|
|
+ if (mode == Mode.SYNTHETIC) {
|
|
|
return new SourceLoader.Synthetic(mapping);
|
|
|
}
|
|
|
return SourceLoader.FROM_STORED_SOURCE;
|
|
|
}
|
|
|
|
|
|
public boolean isSynthetic() {
|
|
|
- return synthetic;
|
|
|
+ return mode == Mode.SYNTHETIC;
|
|
|
}
|
|
|
}
|