Skip to content

Commit

Permalink
Add a new all meta field that keyword fields use for inverted index i…
Browse files Browse the repository at this point in the history
…f all field is enabled.
  • Loading branch information
martijnvg committed Jan 26, 2024
1 parent 75ccc9d commit ee0b545
Show file tree
Hide file tree
Showing 16 changed files with 368 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ public final class IndexScopedSettings extends AbstractScopedSettings {
MapperService.INDEX_MAPPING_DEPTH_LIMIT_SETTING,
MapperService.INDEX_MAPPING_DIMENSION_FIELDS_LIMIT_SETTING,
MapperService.INDEX_MAPPING_FIELD_NAME_LENGTH_LIMIT_SETTING,
MapperService.INDEX_MAPPING_NON_TEXT_FIELDS_SHARED_INVERTED_INDEX,
BitsetFilterCache.INDEX_LOAD_RANDOM_ACCESS_FILTERS_EAGERLY_SETTING,
IndexModule.INDEX_STORE_TYPE_SETTING,
IndexModule.INDEX_STORE_PRE_LOAD_SETTING,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import static org.elasticsearch.index.mapper.MapperService.INDEX_MAPPING_FIELD_NAME_LENGTH_LIMIT_SETTING;
import static org.elasticsearch.index.mapper.MapperService.INDEX_MAPPING_NESTED_DOCS_LIMIT_SETTING;
import static org.elasticsearch.index.mapper.MapperService.INDEX_MAPPING_NESTED_FIELDS_LIMIT_SETTING;
import static org.elasticsearch.index.mapper.MapperService.INDEX_MAPPING_NON_TEXT_FIELDS_SHARED_INVERTED_INDEX;
import static org.elasticsearch.index.mapper.MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING;

/**
Expand Down Expand Up @@ -757,7 +756,6 @@ private void setRetentionLeaseMillis(final TimeValue retentionLease) {
private volatile long mappingDepthLimit;
private volatile long mappingFieldNameLengthLimit;
private volatile long mappingDimensionFieldsLimit;
private final boolean mappingNonTextFieldsSharedInvertedIndex;

/**
* The maximum number of refresh listeners allows on this shard.
Expand Down Expand Up @@ -902,7 +900,6 @@ public IndexSettings(final IndexMetadata indexMetadata, final Settings nodeSetti
mappingDepthLimit = scopedSettings.get(INDEX_MAPPING_DEPTH_LIMIT_SETTING);
mappingFieldNameLengthLimit = scopedSettings.get(INDEX_MAPPING_FIELD_NAME_LENGTH_LIMIT_SETTING);
mappingDimensionFieldsLimit = scopedSettings.get(INDEX_MAPPING_DIMENSION_FIELDS_LIMIT_SETTING);
mappingNonTextFieldsSharedInvertedIndex = scopedSettings.get(INDEX_MAPPING_NON_TEXT_FIELDS_SHARED_INVERTED_INDEX);
indexRouting = IndexRouting.fromIndexMetadata(indexMetadata);
es87TSDBCodecEnabled = scopedSettings.get(TIME_SERIES_ES87TSDB_CODEC_ENABLED_SETTING);

Expand Down Expand Up @@ -1546,10 +1543,6 @@ private void setMappingDimensionFieldsLimit(long value) {
this.mappingDimensionFieldsLimit = value;
}

public boolean isMappingNonTextFieldsSharedInvertedIndex() {
return mappingNonTextFieldsSharedInvertedIndex;
}

/**
* The bounds for {@code @timestamp} on this index or
* {@code null} if there are no bounds.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

package org.elasticsearch.index.mapper;

import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.index.query.SearchExecutionContext;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

import static org.apache.lucene.index.IndexWriter.MAX_TERM_LENGTH;

public class AllFieldMapper extends MetadataFieldMapper {

static final byte FIELD_VALUE_SEPARATOR = 0; // nul code point
public static final String NAME = "_all";
public static final AllFieldMapper ENABLED_INSTANCE = new AllFieldMapper(true);
private static final AllFieldMapper DISABLED_INSTANCE = new AllFieldMapper(false);

private final boolean enabled;

public static class Defaults {
public static final FieldType FIELD_TYPE;

static {
FieldType ft = new FieldType();
ft.setTokenized(false);
ft.setOmitNorms(true);
ft.setIndexOptions(IndexOptions.DOCS);
ft.setDocValuesType(DocValuesType.NONE);
ft.setStored(false);
FIELD_TYPE = freezeAndDeduplicateFieldType(ft);
}

public static TextSearchInfo TEXT_SEARCH_INFO = new TextSearchInfo(
FIELD_TYPE,
null,
Lucene.KEYWORD_ANALYZER,
Lucene.KEYWORD_ANALYZER
);

}

public static class Builder extends MetadataFieldMapper.Builder {

private final Parameter<Boolean> enabled;

public Builder() {
super(NAME);
this.enabled = Parameter.boolParam("enabled", true, m -> toType(m).enabled, false)
.setMergeValidator((previous, current, conflicts) -> previous == current);
}

@Override
protected Parameter<?>[] getParameters() {
return new Parameter<?>[] { enabled };
}

@Override
public MetadataFieldMapper build() {
return enabled.getValue() ? ENABLED_INSTANCE : DISABLED_INSTANCE;
}

private static AllFieldMapper toType(FieldMapper in) {
return (AllFieldMapper) in;
}
}

public static final class AllFieldType extends MappedFieldType {

static final AllFieldType INSTANCE = new AllFieldType();

private AllFieldType() {
super(NAME, true, false, false, Defaults.TEXT_SEARCH_INFO, Collections.emptyMap());
}

@Override
public String typeName() {
return NAME;
}

@Override
public Query termQuery(Object value, SearchExecutionContext context) {
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] does not support term queries");
}

@Override
public Query existsQuery(SearchExecutionContext context) {
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] does not support exists queries");
}

@Override
public ValueFetcher valueFetcher(SearchExecutionContext context, String format) {
throw new UnsupportedOperationException();
}
}

public static final TypeParser PARSER = new ConfigurableTypeParser(c -> DISABLED_INSTANCE, c -> new AllFieldMapper.Builder());

private AllFieldMapper(boolean enabled) {
super(AllFieldType.INSTANCE);
this.enabled = enabled;
}

public boolean isEnabled() {
return enabled;
}

@Override
public FieldMapper.Builder getMergeBuilder() {
return new Builder().init(this);
}

@Override
public void postParse(DocumentParserContext context) throws IOException {
if (enabled == false) {
// not configured, so skip the validation
return;
}

final List<IndexableField> fields = context.rootDoc().getFields();
for (int i = 0; i < fields.size(); i++) {
IndexableField indexableField = fields.get(i);
var mappedFieldType = context.mappingLookup().getFieldType(indexableField.name());
if (mappedFieldType != null && "keyword".equals(mappedFieldType.typeName())) {
BytesRef value = toAllFieldTerm(indexableField.binaryValue(), new BytesRef(indexableField.name()));
if (value.length > MAX_TERM_LENGTH) {
// TODO
}
context.doc().add(new KeywordFieldMapper.KeywordField(NAME, value, Defaults.FIELD_TYPE));
}
}

}

public static BytesRef toAllFieldTerm(BytesRef fieldValueBytes, BytesRef fieldNameBytes) {
BytesRefBuilder builder = new BytesRefBuilder();
builder.append(fieldValueBytes);
builder.append(FIELD_VALUE_SEPARATOR);
builder.append(fieldNameBytes);
return builder.toBytesRef();
}

@Override
protected String contentType() {
return NAME;
}

@Override
public SourceLoader.SyntheticFieldLoader syntheticFieldLoader() {
return SourceLoader.SyntheticFieldLoader.NOTHING;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,8 @@ static Mapping createDynamicUpdate(DocumentParserContext context) {
for (RuntimeField runtimeField : context.getDynamicRuntimeFields()) {
rootBuilder.addRuntimeField(runtimeField);
}
boolean nonTextFieldsSharedInvertedIndex = context.indexSettings().isMappingNonTextFieldsSharedInvertedIndex();
RootObjectMapper root = rootBuilder.build(
MapperBuilderContext.root(context.mappingLookup().isSourceSynthetic(), false, nonTextFieldsSharedInvertedIndex)
MapperBuilderContext.root(context.mappingLookup().isSourceSynthetic(), false, context.mappingLookup().isALlFieldEnabled())
);
return context.mappingLookup().getMapping().mappingUpdate(root);
}
Expand Down
Loading

0 comments on commit ee0b545

Please sign in to comment.