Add text search information to MappedFieldType (#58230) (#58432)

Now that MappedFieldType no longer extends lucene's FieldType, we need to have a
way of getting the index information about a field necessary for building text queries,
building term vectors, highlighting, etc. This commit introduces a new TextSearchInfo
abstraction that holds this information, and a getTextSearchInfo() method to
MappedFieldType to make it available. Field types that do not support text search can
just return null here.

This allows us to remove the MapperService.getLuceneFieldType() shim method.
This commit is contained in:
Alan Woodward 2020-06-23 14:37:26 +01:00 committed by GitHub
parent 519f41950a
commit 8ebd341710
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 344 additions and 238 deletions

View File

@ -98,7 +98,7 @@ public class RankFeatureFieldMapper extends FieldMapper {
private final boolean positiveScoreImpact;
public RankFeatureFieldType(String name, Map<String, String> meta, boolean positiveScoreImpact) {
super(name, true, false, meta);
super(name, true, false, TextSearchInfo.NONE, meta);
this.positiveScoreImpact = positiveScoreImpact;
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);

View File

@ -89,7 +89,7 @@ public class RankFeatureMetaFieldMapper extends MetadataFieldMapper {
public static final RankFeatureMetaFieldType INSTANCE = new RankFeatureMetaFieldType();
private RankFeatureMetaFieldType() {
super(NAME, false, false, Collections.emptyMap());
super(NAME, false, false, TextSearchInfo.NONE, Collections.emptyMap());
}
protected RankFeatureMetaFieldType(RankFeatureMetaFieldType ref) {

View File

@ -76,7 +76,7 @@ public class RankFeaturesFieldMapper extends FieldMapper {
public static final class RankFeaturesFieldType extends MappedFieldType {
public RankFeaturesFieldType(String name, Map<String, String> meta) {
super(name, false, false, meta);
super(name, false, false, TextSearchInfo.NONE, meta);
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);
}

View File

@ -185,7 +185,7 @@ public class ScaledFloatFieldMapper extends FieldMapper {
private final double scalingFactor;
public ScaledFloatFieldType(String name, boolean indexed, boolean hasDocValues, Map<String, String> meta, double scalingFactor) {
super(name, indexed, hasDocValues, meta);
super(name, indexed, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
this.scalingFactor = scalingFactor;
}

View File

@ -157,16 +157,19 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
@Override
public SearchAsYouTypeFieldMapper build(Mapper.BuilderContext context) {
boolean hasNorms = fieldType.omitNorms() == false;
SearchAsYouTypeFieldType ft = new SearchAsYouTypeFieldType(buildFullName(context), indexed, meta, hasNorms);
SearchAsYouTypeFieldType ft = new SearchAsYouTypeFieldType(buildFullName(context), fieldType, meta);
ft.setIndexAnalyzer(indexAnalyzer);
ft.setSearchAnalyzer(searchAnalyzer);
ft.setSearchQuoteAnalyzer(searchQuoteAnalyzer);
ft.setSimilarity(similarity);
// set up the prefix field
FieldType prefixft = new FieldType(fieldType);
prefixft.setStoreTermVectors(false);
prefixft.setOmitNorms(true);
prefixft.setStored(false);
final String fullName = buildFullName(context);
final PrefixFieldType prefixFieldType = new PrefixFieldType(fullName, Defaults.MIN_GRAM, Defaults.MAX_GRAM);
final PrefixFieldType prefixFieldType = new PrefixFieldType(fullName, prefixft, Defaults.MIN_GRAM, Defaults.MAX_GRAM);
// wrap the root field's index analyzer with shingles and edge ngrams
final SearchAsYouTypeAnalyzer prefixIndexWrapper =
SearchAsYouTypeAnalyzer.withShingleAndPrefix(indexAnalyzer.analyzer(), maxShingleSize);
@ -176,10 +179,6 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
// don't wrap the root field's search quote analyzer as prefix field doesn't support phrase queries
prefixFieldType.setIndexAnalyzer(new NamedAnalyzer(indexAnalyzer.name(), AnalyzerScope.INDEX, prefixIndexWrapper));
prefixFieldType.setSearchAnalyzer(new NamedAnalyzer(searchAnalyzer.name(), AnalyzerScope.INDEX, prefixSearchWrapper));
FieldType prefixft = new FieldType(fieldType);
prefixft.setStoreTermVectors(false);
prefixft.setOmitNorms(true);
prefixft.setStored(false);
final PrefixFieldMapper prefixFieldMapper = new PrefixFieldMapper(prefixft, prefixFieldType);
// set up the shingle fields
@ -187,8 +186,10 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
final ShingleFieldType[] shingleFieldTypes = new ShingleFieldType[maxShingleSize - 1];
for (int i = 0; i < shingleFieldMappers.length; i++) {
final int shingleSize = i + 2;
FieldType shingleft = new FieldType(fieldType);
shingleft.setStored(false);
String fieldName = getShingleFieldName(buildFullName(context), shingleSize);
final ShingleFieldType shingleFieldType = new ShingleFieldType(fieldName, shingleSize, hasNorms);
final ShingleFieldType shingleFieldType = new ShingleFieldType(fieldName, shingleSize, shingleft);
// wrap the root field's index, search, and search quote analyzers with shingles
final SearchAsYouTypeAnalyzer shingleIndexWrapper =
SearchAsYouTypeAnalyzer.withShingle(indexAnalyzer.analyzer(), shingleSize);
@ -202,8 +203,6 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
new NamedAnalyzer(searchQuoteAnalyzer.name(), AnalyzerScope.INDEX, shingleSearchQuoteWrapper));
shingleFieldType.setPrefixFieldType(prefixFieldType);
shingleFieldTypes[i] = shingleFieldType;
FieldType shingleft = new FieldType(fieldType);
shingleft.setStored(false);
shingleFieldMappers[i] = new ShingleFieldMapper(shingleft, shingleFieldType);
}
ft.setPrefixField(prefixFieldType);
@ -235,12 +234,9 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
PrefixFieldType prefixField;
ShingleFieldType[] shingleFields = new ShingleFieldType[0];
final boolean hasNorms;
SearchAsYouTypeFieldType(String name, boolean indexed, Map<String, String> meta, boolean hasNorms) {
super(name, indexed, false, meta);
this.hasNorms = hasNorms;
this.hasPositions = true;
SearchAsYouTypeFieldType(String name, FieldType fieldType, Map<String, String> meta) {
super(name, fieldType.indexOptions() != IndexOptions.NONE, false, new TextSearchInfo(fieldType), meta);
}
SearchAsYouTypeFieldType(SearchAsYouTypeFieldType other) {
@ -257,7 +253,6 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
}
}
}
this.hasNorms = other.hasNorms;
}
public void setPrefixField(PrefixFieldType prefixField) {
@ -285,7 +280,7 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
@Override
public Query existsQuery(QueryShardContext context) {
if (hasNorms == false) {
if (getTextSearchInfo().hasNorms() == false) {
return new TermQuery(new Term(FieldNamesFieldMapper.NAME, name()));
} else {
return new NormsFieldExistsQuery(name());
@ -386,12 +381,11 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
final int maxChars;
final String parentField;
PrefixFieldType(String parentField, int minChars, int maxChars) {
super(parentField + PREFIX_FIELD_SUFFIX, true, false, Collections.emptyMap());
PrefixFieldType(String parentField, FieldType fieldType, int minChars, int maxChars) {
super(parentField + PREFIX_FIELD_SUFFIX, true, false, new TextSearchInfo(fieldType), Collections.emptyMap());
this.minChars = minChars;
this.maxChars = maxChars;
this.parentField = parentField;
this.hasPositions = true;
}
PrefixFieldType(PrefixFieldType other) {
@ -399,7 +393,6 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
this.minChars = other.minChars;
this.maxChars = other.maxChars;
this.parentField = other.parentField;
this.hasPositions = other.hasPositions;
}
boolean termLengthWithinBounds(int length) {
@ -539,21 +532,16 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
*/
static class ShingleFieldType extends StringFieldType {
final int shingleSize;
final boolean hasNorms;
PrefixFieldType prefixFieldType;
ShingleFieldType(String name, int shingleSize, boolean hasNorms) {
super(name, true, false, Collections.emptyMap());
ShingleFieldType(String name, int shingleSize, FieldType fieldType) {
super(name, true, false, new TextSearchInfo(fieldType), Collections.emptyMap());
this.shingleSize = shingleSize;
this.hasNorms = hasNorms;
this.hasPositions = true;
}
ShingleFieldType(ShingleFieldType other) {
super(other);
this.shingleSize = other.shingleSize;
this.hasNorms = other.hasNorms;
this.hasPositions = other.hasPositions;
if (other.prefixFieldType != null) {
this.prefixFieldType = other.prefixFieldType.clone();
}
@ -575,7 +563,7 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
@Override
public Query existsQuery(QueryShardContext context) {
if (hasNorms == false) {
if (getTextSearchInfo().hasNorms() == false) {
return new TermQuery(new Term(FieldNamesFieldMapper.NAME, name()));
} else {
return new NormsFieldExistsQuery(name());

View File

@ -19,6 +19,8 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.PrefixQuery;
@ -41,12 +43,17 @@ import static org.hamcrest.Matchers.equalTo;
public class SearchAsYouTypeFieldTypeTests extends FieldTypeTestCase<MappedFieldType> {
private static final String NAME = "a_field";
private static final FieldType UNSEARCHABLE = new FieldType();
static {
UNSEARCHABLE.setIndexOptions(IndexOptions.NONE);
UNSEARCHABLE.freeze();
}
@Override
protected SearchAsYouTypeFieldType createDefaultFieldType(String name, Map<String, String> meta) {
final SearchAsYouTypeFieldType fieldType = new SearchAsYouTypeFieldType(name, true, meta, true);
fieldType.setPrefixField(new PrefixFieldType(NAME, Defaults.MIN_GRAM, Defaults.MAX_GRAM));
fieldType.setShingleFields(new ShingleFieldType[] { new ShingleFieldType(fieldType.name(), 2, true) });
final SearchAsYouTypeFieldType fieldType = new SearchAsYouTypeFieldType(name, Defaults.FIELD_TYPE, meta);
fieldType.setPrefixField(new PrefixFieldType(NAME, Defaults.FIELD_TYPE, Defaults.MIN_GRAM, Defaults.MAX_GRAM));
fieldType.setShingleFields(new ShingleFieldType[] { new ShingleFieldType(fieldType.name(), 2, Defaults.FIELD_TYPE) });
return fieldType;
}
@ -55,7 +62,7 @@ public class SearchAsYouTypeFieldTypeTests extends FieldTypeTestCase<MappedField
assertThat(fieldType.termQuery("foo", null), equalTo(new TermQuery(new Term(NAME, "foo"))));
SearchAsYouTypeFieldType unsearchable = new SearchAsYouTypeFieldType(NAME, false, Collections.emptyMap(), true);
SearchAsYouTypeFieldType unsearchable = new SearchAsYouTypeFieldType(NAME, UNSEARCHABLE, Collections.emptyMap());
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> unsearchable.termQuery("foo", null));
assertThat(e.getMessage(), equalTo("Cannot search on field [" + NAME + "] since it is not indexed."));
}
@ -66,7 +73,7 @@ public class SearchAsYouTypeFieldTypeTests extends FieldTypeTestCase<MappedField
assertThat(fieldType.termsQuery(asList("foo", "bar"), null),
equalTo(new TermInSetQuery(NAME, asList(new BytesRef("foo"), new BytesRef("bar")))));
SearchAsYouTypeFieldType unsearchable = new SearchAsYouTypeFieldType(NAME, false, Collections.emptyMap(), true);
SearchAsYouTypeFieldType unsearchable = new SearchAsYouTypeFieldType(NAME, UNSEARCHABLE, Collections.emptyMap());
final IllegalArgumentException e =
expectThrows(IllegalArgumentException.class, () -> unsearchable.termsQuery(asList("foo", "bar"), null));
assertThat(e.getMessage(), equalTo("Cannot search on field [" + NAME + "] since it is not indexed."));

View File

@ -28,6 +28,7 @@ import org.elasticsearch.index.fielddata.plain.SortedSetOrdinalsIndexFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.StringFieldType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
@ -77,7 +78,7 @@ public class MetaJoinFieldMapper extends FieldMapper {
private final String joinField;
MetaJoinFieldType(String joinField) {
super(NAME, false, false, Collections.emptyMap());
super(NAME, false, false, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
this.joinField = joinField;
}

View File

@ -38,6 +38,7 @@ import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.StringFieldType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
@ -94,7 +95,7 @@ public final class ParentIdFieldMapper extends FieldMapper {
public static final class ParentIdFieldType extends StringFieldType {
ParentIdFieldType(String name, boolean eagerGlobalOrdinals, Map<String, String> meta) {
super(name, true, true, meta);
super(name, true, true, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);
setEagerGlobalOrdinals(eagerGlobalOrdinals);

View File

@ -43,6 +43,7 @@ import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.StringFieldType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
@ -205,7 +206,7 @@ public final class ParentJoinFieldMapper extends FieldMapper {
public static final class JoinFieldType extends StringFieldType {
public JoinFieldType(String name, Map<String, String> meta) {
super(name, true, true, meta);
super(name, true, true, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);
}

View File

@ -69,6 +69,7 @@ import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.RangeFieldMapper;
import org.elasticsearch.index.mapper.RangeType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.BoostingQueryBuilder;
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
@ -202,7 +203,7 @@ public class PercolatorFieldMapper extends FieldMapper {
boolean mapUnmappedFieldsAsText;
PercolatorFieldType(String name, Map<String, String> meta) {
super(name, false, false, meta);
super(name, false, false, TextSearchInfo.NONE, meta);
}
PercolatorFieldType(PercolatorFieldType ref) {

View File

@ -77,7 +77,7 @@ public class ICUCollationKeywordFieldMapper extends FieldMapper {
private final Collator collator;
public CollationFieldType(String name, boolean isSearchable, boolean hasDocValues, Collator collator, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, meta);
super(name, isSearchable, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);
this.collator = collator;

View File

@ -124,7 +124,7 @@ public class AnnotatedTextFieldMapper extends FieldMapper {
} else {
//Using the analyzer's default BUT need to do the same thing AnalysisRegistry.processAnalyzerFactory
// does to splice in new default of posIncGap=100 by wrapping the analyzer
if (fieldType.indexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) >= 0) {
if (hasPositions) {
int overrideInc = TextFieldMapper.Defaults.POSITION_INCREMENT_GAP;
ft.setIndexAnalyzer(indexAnalyzer, overrideInc);
ft.setSearchAnalyzer(new NamedAnalyzer(searchAnalyzer, overrideInc));
@ -522,7 +522,7 @@ public class AnnotatedTextFieldMapper extends FieldMapper {
public static final class AnnotatedTextFieldType extends TextFieldMapper.TextFieldType {
public AnnotatedTextFieldType(String name, boolean hasPositions, Map<String, String> meta) {
super(name, true, hasPositions, meta);
super(name, hasPositions, meta);
}
protected AnnotatedTextFieldType(AnnotatedTextFieldType ref) {

View File

@ -35,6 +35,7 @@ import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.mapper.TypeParsers;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
@ -92,7 +93,7 @@ public class Murmur3FieldMapper extends FieldMapper {
// this only exists so a check can be done to match the field type to using murmur3 hashing...
public static class Murmur3FieldType extends MappedFieldType {
public Murmur3FieldType(String name, Map<String, String> meta) {
super(name, false, true, meta);
super(name, false, true, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
}
protected Murmur3FieldType(Murmur3FieldType ref) {

View File

@ -22,7 +22,7 @@ package org.elasticsearch.index.fielddata.plain;
import org.apache.lucene.index.BinaryDocValues;
import org.elasticsearch.index.fielddata.ScriptDocValues;
final class StringBinaryDVLeafFieldData extends AbstractBinaryDVLeafFieldData{
final class StringBinaryDVLeafFieldData extends AbstractBinaryDVLeafFieldData {
StringBinaryDVLeafFieldData(BinaryDocValues values) {
super(values);
}
@ -31,4 +31,4 @@ final class StringBinaryDVLeafFieldData extends AbstractBinaryDVLeafFieldData{
public ScriptDocValues<String> getScriptValues() {
return new ScriptDocValues.Strings(getBytesValues());
}
}
}

View File

@ -175,7 +175,6 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
}
@Override
@SuppressWarnings("rawtypes")
public T parse(String name, Map<String, Object> node, ParserContext parserContext)
throws MapperParsingException {
Map<String, Object> params = new HashMap<>();
@ -189,7 +188,7 @@ public abstract class AbstractGeometryFieldMapper<Parsed, Processed> extends Fie
protected QueryProcessor geometryQueryBuilder;
protected AbstractGeometryFieldType(String name, boolean indexed, boolean hasDocValues, Map<String, String> meta) {
super(name, indexed, hasDocValues, meta);
super(name, indexed, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
}
protected AbstractGeometryFieldType(AbstractGeometryFieldType ref) {

View File

@ -99,7 +99,7 @@ public class AllFieldMapper extends MetadataFieldMapper {
static final class AllFieldType extends StringFieldType {
AllFieldType() {
super(NAME, false, false, Collections.emptyMap());
super(NAME, false, false, TextSearchInfo.NONE, Collections.emptyMap());
}
protected AllFieldType(AllFieldType ref) {

View File

@ -99,7 +99,7 @@ public class BinaryFieldMapper extends FieldMapper {
public static final class BinaryFieldType extends MappedFieldType {
public BinaryFieldType(String name, boolean hasDocValues, Map<String, String> meta) {
super(name, false, hasDocValues, meta);
super(name, false, hasDocValues, TextSearchInfo.NONE, meta);
}
public BinaryFieldType(String name) {

View File

@ -118,7 +118,7 @@ public class BooleanFieldMapper extends FieldMapper {
public static final class BooleanFieldType extends TermBasedFieldType {
public BooleanFieldType(String name, boolean isSearchable, boolean hasDocValues, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, meta);
super(name, isSearchable, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
}
public BooleanFieldType(String name) {

View File

@ -194,12 +194,12 @@ public class CompletionFieldMapper extends FieldMapper {
private boolean preservePositionIncrements = Defaults.DEFAULT_POSITION_INCREMENTS;
private ContextMappings contextMappings = null;
public CompletionFieldType(String name, Map<String, String> meta) {
super(name, true, false, meta);
public CompletionFieldType(String name, FieldType luceneFieldType, Map<String, String> meta) {
super(name, true, false, new TextSearchInfo(luceneFieldType), meta);
}
public CompletionFieldType(String name) {
this(name, Collections.emptyMap());
this(name, Defaults.FIELD_TYPE, Collections.emptyMap());
}
private CompletionFieldType(CompletionFieldType ref) {
@ -395,7 +395,7 @@ public class CompletionFieldMapper extends FieldMapper {
@Override
public CompletionFieldMapper build(BuilderContext context) {
checkCompletionContextsLimit(context);
CompletionFieldType ft = new CompletionFieldType(buildFullName(context), meta);
CompletionFieldType ft = new CompletionFieldType(buildFullName(context), this.fieldType, meta);
ft.setContextMappings(contextMappings);
ft.setPreservePositionIncrements(preservePositionIncrements);
ft.setPreserveSep(preserveSeparators);

View File

@ -42,7 +42,7 @@ import java.util.Map;
public abstract class ConstantFieldType extends MappedFieldType {
public ConstantFieldType(String name, Map<String, String> meta) {
super(name, true, true, meta);
super(name, true, true, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
}
public ConstantFieldType(ConstantFieldType other) {

View File

@ -308,7 +308,7 @@ public final class DateFieldMapper extends FieldMapper {
public DateFieldType(String name, boolean isSearchable, boolean hasDocValues,
DateFormatter dateTimeFormatter, Resolution resolution, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, meta);
super(name, isSearchable, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
this.dateTimeFormatter = dateTimeFormatter;
this.dateMathParser = dateTimeFormatter.toDateMathParser();
this.resolution = resolution;

View File

@ -132,7 +132,7 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
private boolean enabled = Defaults.ENABLED;
public FieldNamesFieldType() {
super(Defaults.NAME, true, false, Collections.emptyMap());
super(Defaults.NAME, true, false, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
}
protected FieldNamesFieldType(FieldNamesFieldType ref) {

View File

@ -117,7 +117,7 @@ public class IdFieldMapper extends MetadataFieldMapper {
public static final IdFieldType INSTANCE = new IdFieldType();
private IdFieldType() {
super(NAME, true, false, Collections.emptyMap());
super(NAME, true, false, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);
}

View File

@ -84,7 +84,7 @@ public final class IgnoredFieldMapper extends MetadataFieldMapper {
public static final IgnoredFieldType INSTANCE = new IgnoredFieldType();
private IgnoredFieldType() {
super(NAME, true, false, Collections.emptyMap());
super(NAME, true, false, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
}
protected IgnoredFieldType(IgnoredFieldType ref) {

View File

@ -141,7 +141,7 @@ public class IpFieldMapper extends FieldMapper {
public static final class IpFieldType extends SimpleMappedFieldType {
public IpFieldType(String name, boolean indexed, boolean hasDocValues, Map<String, String> meta) {
super(name, indexed, hasDocValues, meta);
super(name, indexed, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
}
public IpFieldType(String name) {

View File

@ -165,7 +165,7 @@ public final class KeywordFieldMapper extends FieldMapper {
// TODO should this be a Lucene global analyzer as well?
searchAnalyzer = new NamedAnalyzer("whitespace", AnalyzerScope.INDEX, new WhitespaceAnalyzer());
}
return new KeywordFieldType(buildFullName(context), indexed, hasDocValues, fieldType.omitNorms() == false,
return new KeywordFieldType(buildFullName(context), hasDocValues, fieldType,
eagerGlobalOrdinals, normalizer, searchAnalyzer, similarity, meta, boost);
}
@ -219,11 +219,12 @@ public final class KeywordFieldMapper extends FieldMapper {
boolean hasNorms;
public KeywordFieldType(String name, boolean isSearchable, boolean hasDocValues, boolean hasNorms,
public KeywordFieldType(String name, boolean hasDocValues, FieldType fieldType,
boolean eagerGlobalOrdinals, NamedAnalyzer normalizer, NamedAnalyzer searchAnalyzer,
SimilarityProvider similarity, Map<String, String> meta, float boost) {
super(name, isSearchable, hasDocValues, meta);
this.hasNorms = hasNorms;
super(name, fieldType.indexOptions() != IndexOptions.NONE,
hasDocValues, new TextSearchInfo(fieldType), meta);
this.hasNorms = fieldType.omitNorms() == false;
setEagerGlobalOrdinals(eagerGlobalOrdinals);
setIndexAnalyzer(normalizer);
setSearchAnalyzer(searchAnalyzer);
@ -232,11 +233,14 @@ public final class KeywordFieldMapper extends FieldMapper {
}
public KeywordFieldType(String name, boolean isSearchable, boolean hasDocValues, Map<String, String> meta) {
this(name, isSearchable, hasDocValues, true, false, Lucene.KEYWORD_ANALYZER, Lucene.KEYWORD_ANALYZER, null, meta, 1.0f);
super(name, isSearchable, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);
}
public KeywordFieldType(String name) {
this(name, true, true, Collections.emptyMap());
this(name, true, Defaults.FIELD_TYPE, false,
Lucene.KEYWORD_ANALYZER, Lucene.KEYWORD_ANALYZER, null, Collections.emptyMap(), 1f);
}
protected KeywordFieldType(KeywordFieldType ref) {

View File

@ -63,11 +63,11 @@ public abstract class MappedFieldType {
private final String name;
private final boolean docValues;
private final boolean isIndexed;
private final TextSearchInfo textSearchInfo;
private float boost;
private NamedAnalyzer indexAnalyzer;
private NamedAnalyzer searchAnalyzer;
private NamedAnalyzer searchQuoteAnalyzer;
protected boolean hasPositions;
private SimilarityProvider similarity;
private boolean eagerGlobalOrdinals;
private Map<String, String> meta;
@ -83,14 +83,15 @@ public abstract class MappedFieldType {
this.similarity = ref.similarity();
this.eagerGlobalOrdinals = ref.eagerGlobalOrdinals;
this.meta = ref.meta;
this.hasPositions = ref.hasPositions;
this.textSearchInfo = ref.textSearchInfo;
}
public MappedFieldType(String name, boolean isIndexed, boolean hasDocValues, Map<String, String> meta) {
public MappedFieldType(String name, boolean isIndexed, boolean hasDocValues, TextSearchInfo textSearchInfo, Map<String, String> meta) {
setBoost(1.0f);
this.name = Objects.requireNonNull(name);
this.isIndexed = isIndexed;
this.docValues = hasDocValues;
this.textSearchInfo = Objects.requireNonNull(textSearchInfo);
this.meta = meta;
}
@ -151,10 +152,6 @@ public abstract class MappedFieldType {
this.boost = boost;
}
public boolean hasPositions() {
return hasPositions;
}
public boolean hasDocValues() {
return docValues;
}
@ -411,4 +408,16 @@ public abstract class MappedFieldType {
public void updateMeta(Map<String, String> meta) {
this.meta = meta;
}
/**
* Returns information on how any text in this field is indexed
*
* Fields that do not support any text-based queries should return
* {@link TextSearchInfo#NONE}. Some fields (eg numeric) may support
* only simple match queries, and can return
* {@link TextSearchInfo#SIMPLE_MATCH_ONLY}
*/
public TextSearchInfo getTextSearchInfo() {
return textSearchInfo;
}
}

View File

@ -24,7 +24,6 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.DelegatingAnalyzerWrapper;
import org.apache.lucene.document.FieldType;
import org.elasticsearch.Assertions;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetadata;
@ -198,20 +197,6 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
return this.documentParser;
}
public FieldType getLuceneFieldType(String field) {
Mapper mapper = documentMapper().mappers().getMapper(field);
if (mapper == null) {
return null;
}
if (mapper instanceof FieldAliasMapper) {
return getLuceneFieldType(((FieldAliasMapper)mapper).path());
}
if (mapper instanceof FieldMapper == false) {
return null;
}
return ((FieldMapper) mapper).fieldType;
}
/**
* Parses the mappings (formatted as JSON) into a map
*/

View File

@ -904,7 +904,7 @@ public class NumberFieldMapper extends FieldMapper {
private final NumberType type;
public NumberFieldType(String name, NumberType type, boolean isSearchable, boolean hasDocValues, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, meta);
super(name, isSearchable, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
this.type = Objects.requireNonNull(type);
this.setIndexAnalyzer(Lucene.KEYWORD_ANALYZER); // allows number fields in significant text aggs - do we need this?
this.setSearchAnalyzer(Lucene.KEYWORD_ANALYZER); // allows match queries on number fields

View File

@ -193,7 +193,7 @@ public class RangeFieldMapper extends FieldMapper {
protected final DateMathParser dateMathParser;
public RangeFieldType(String name, RangeType type, boolean indexed, boolean hasDocValues, Map<String, String> meta) {
super(name, indexed, hasDocValues, meta);
super(name, indexed, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
assert type != RangeType.DATE;
this.rangeType = Objects.requireNonNull(type);
dateTimeFormatter = null;
@ -207,7 +207,7 @@ public class RangeFieldMapper extends FieldMapper {
}
public RangeFieldType(String name, boolean indexed, boolean hasDocValues, DateFormatter formatter, Map<String, String> meta) {
super(name, indexed, hasDocValues, meta);
super(name, indexed, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
this.rangeType = RangeType.DATE;
this.dateTimeFormatter = Objects.requireNonNull(formatter);
this.dateMathParser = dateTimeFormatter.toDateMathParser();

View File

@ -110,7 +110,7 @@ public class RoutingFieldMapper extends MetadataFieldMapper {
static RoutingFieldType INSTANCE = new RoutingFieldType();
private RoutingFieldType() {
super(NAME, true, false, Collections.emptyMap());
super(NAME, true, false, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);
}

View File

@ -122,7 +122,7 @@ public class SeqNoFieldMapper extends MetadataFieldMapper {
static final class SeqNoFieldType extends SimpleMappedFieldType {
SeqNoFieldType() {
super(NAME, true, true, Collections.emptyMap());
super(NAME, true, true, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
}
protected SeqNoFieldType(SeqNoFieldType ref) {

View File

@ -32,8 +32,9 @@ import java.util.Map;
*/
public abstract class SimpleMappedFieldType extends MappedFieldType {
protected SimpleMappedFieldType(String name, boolean isSearchable, boolean hasDocValues, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, meta);
protected SimpleMappedFieldType(String name, boolean isSearchable, boolean hasDocValues,
TextSearchInfo textSearchInfo, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, textSearchInfo, meta);
}
protected SimpleMappedFieldType(MappedFieldType ref) {

View File

@ -149,7 +149,7 @@ public class SourceFieldMapper extends MetadataFieldMapper {
public static final SourceFieldType INSTANCE = new SourceFieldType();
private SourceFieldType() {
super(NAME, false, false, Collections.emptyMap());
super(NAME, false, false, TextSearchInfo.NONE, Collections.emptyMap());
}
protected SourceFieldType(SourceFieldType ref) {

View File

@ -50,8 +50,9 @@ public abstract class StringFieldType extends TermBasedFieldType {
private static final Pattern WILDCARD_PATTERN = Pattern.compile("(\\\\.)|([?*]+)");
public StringFieldType(String name, boolean isSearchable, boolean hasDocValues, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, meta);
public StringFieldType(String name, boolean isSearchable, boolean hasDocValues,
TextSearchInfo textSearchInfo, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, textSearchInfo, meta);
}
protected StringFieldType(MappedFieldType ref) {

View File

@ -35,8 +35,8 @@ import java.util.Map;
* with the inverted index. */
abstract class TermBasedFieldType extends SimpleMappedFieldType {
TermBasedFieldType(String name, boolean isSearchable, boolean hasDocValues, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, meta);
TermBasedFieldType(String name, boolean isSearchable, boolean hasDocValues, TextSearchInfo textSearchInfo, Map<String, String> meta) {
super(name, isSearchable, hasDocValues, textSearchInfo, meta);
}
protected TermBasedFieldType(MappedFieldType ref) {

View File

@ -187,8 +187,7 @@ public class TextFieldMapper extends FieldMapper {
}
private TextFieldType buildFieldType(BuilderContext context) {
TextFieldType ft = new TextFieldType(buildFullName(context), indexed,
fieldType.indexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) >= 0, meta);
TextFieldType ft = new TextFieldType(buildFullName(context), fieldType, meta);
ft.setIndexAnalyzer(indexAnalyzer);
ft.setSearchAnalyzer(searchAnalyzer);
ft.setSearchQuoteAnalyzer(searchQuoteAnalyzer);
@ -203,7 +202,7 @@ public class TextFieldMapper extends FieldMapper {
return ft;
}
private PrefixFieldMapper buildPrefixMapper(BuilderContext context) {
private PrefixFieldMapper buildPrefixMapper(BuilderContext context, TextFieldType tft) {
if (minPrefixChars == -1) {
return null;
}
@ -231,7 +230,7 @@ public class TextFieldMapper extends FieldMapper {
if (fieldType.storeTermVectorOffsets()) {
pft.setStoreTermVectorOffsets(true);
}
PrefixFieldType prefixFieldType = new PrefixFieldType(fullName, fullName + "._index_prefix",
PrefixFieldType prefixFieldType = new PrefixFieldType(tft, fullName + "._index_prefix",
minPrefixChars, maxPrefixChars, pft.indexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) >= 0);
prefixFieldType.setAnalyzer(indexAnalyzer);
return new PrefixFieldMapper(pft, prefixFieldType);
@ -264,7 +263,7 @@ public class TextFieldMapper extends FieldMapper {
}
TextFieldType tft = buildFieldType(context);
return new TextFieldMapper(name,
fieldType, tft, positionIncrementGap, buildPrefixMapper(context), buildPhraseMapper(context, tft),
fieldType, tft, positionIncrementGap, buildPrefixMapper(context, tft), buildPhraseMapper(context, tft),
multiFieldsBuilder.build(this, context), copyTo);
}
}
@ -367,7 +366,7 @@ public class TextFieldMapper extends FieldMapper {
final TextFieldType parent;
PhraseFieldType(TextFieldType parent) {
super(parent.name() + FAST_PHRASE_SUFFIX, true, false, Collections.emptyMap());
super(parent.name() + FAST_PHRASE_SUFFIX, true, false, parent.getTextSearchInfo(), Collections.emptyMap());
setAnalyzer(parent.indexAnalyzer().name(), parent.indexAnalyzer().analyzer());
this.parent = parent;
}
@ -396,10 +395,11 @@ public class TextFieldMapper extends FieldMapper {
final int minChars;
final int maxChars;
final String parentField;
final TextFieldType parentField;
final boolean hasPositions;
PrefixFieldType(String parentField, String name, int minChars, int maxChars, boolean hasPositions) {
super(name, true, false, Collections.emptyMap());
PrefixFieldType(TextFieldType parentField, String name, int minChars, int maxChars, boolean hasPositions) {
super(name, true, false, parentField.getTextSearchInfo(), Collections.emptyMap());
this.minChars = minChars;
this.maxChars = maxChars;
this.parentField = parentField;
@ -437,7 +437,7 @@ public class TextFieldMapper extends FieldMapper {
query.setRewriteMethod(method);
return new BooleanQuery.Builder()
.add(query, BooleanClause.Occur.SHOULD)
.add(new TermQuery(new Term(parentField, value)), BooleanClause.Occur.SHOULD)
.add(new TermQuery(new Term(parentField.name(), value)), BooleanClause.Occur.SHOULD)
.build();
}
@ -556,18 +556,26 @@ public class TextFieldMapper extends FieldMapper {
private int fielddataMinSegmentSize;
private PrefixFieldType prefixFieldType;
private boolean indexPhrases = false;
private final FieldType indexedFieldType;
public TextFieldType(String name, boolean indexed, boolean hasPositions, Map<String, String> meta) {
super(name, indexed, false, meta);
this.hasPositions = hasPositions;
public TextFieldType(String name, FieldType indexedFieldType, Map<String, String> meta) {
super(name, indexedFieldType.indexOptions() != IndexOptions.NONE, false,
new TextSearchInfo(indexedFieldType), meta);
this.indexedFieldType = indexedFieldType;
fielddata = false;
fielddataMinFrequency = Defaults.FIELDDATA_MIN_FREQUENCY;
fielddataMaxFrequency = Defaults.FIELDDATA_MAX_FREQUENCY;
fielddataMinSegmentSize = Defaults.FIELDDATA_MIN_SEGMENT_SIZE;
}
public TextFieldType(String name, boolean indexed, Map<String, String> meta) {
super(name, indexed, false, new TextSearchInfo(Defaults.FIELD_TYPE), meta);
this.indexedFieldType = Defaults.FIELD_TYPE;
fielddata = false;
}
public TextFieldType(String name) {
this(name, true, true, Collections.emptyMap());
this(name, Defaults.FIELD_TYPE, Collections.emptyMap());
}
protected TextFieldType(TextFieldType ref) {
@ -580,7 +588,7 @@ public class TextFieldMapper extends FieldMapper {
if (ref.prefixFieldType != null) {
this.prefixFieldType = ref.prefixFieldType.clone();
}
this.hasPositions = ref.hasPositions;
this.indexedFieldType = ref.indexedFieldType;
}
@Override
@ -652,10 +660,6 @@ public class TextFieldMapper extends FieldMapper {
return this.prefixFieldType;
}
public boolean hasPositions() {
return this.hasPositions;
}
@Override
public String typeName() {
return CONTENT_TYPE;
@ -680,7 +684,7 @@ public class TextFieldMapper extends FieldMapper {
if (prefixFieldType != null
&& value.length() >= prefixFieldType.minChars
&& value.length() <= prefixFieldType.maxChars
&& prefixFieldType.hasPositions()) {
&& prefixFieldType.getTextSearchInfo().hasPositions()) {
return new FieldMaskingSpanQuery(new SpanTermQuery(new Term(prefixFieldType.name(), indexedValueForSearch(value))), name());
} else {
@ -693,7 +697,7 @@ public class TextFieldMapper extends FieldMapper {
@Override
public Query existsQuery(QueryShardContext context) {
if (context.getMapperService().getLuceneFieldType(name()).omitNorms()) {
if (indexedFieldType.omitNorms()) {
return new TermQuery(new Term(FieldNamesFieldMapper.NAME, name()));
} else {
return new NormsFieldExistsQuery(name());
@ -703,7 +707,7 @@ public class TextFieldMapper extends FieldMapper {
@Override
public IntervalsSource intervals(String text, int maxGaps, boolean ordered,
NamedAnalyzer analyzer, boolean prefix) throws IOException {
if (hasPositions() == false) {
if (getTextSearchInfo().hasPositions() == false) {
throw new IllegalArgumentException("Cannot create intervals over field [" + name() + "] with no positions indexed");
}
if (analyzer == null) {

View File

@ -0,0 +1,114 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexOptions;
/**
* Encapsulates information about how to perform text searches over a field
*/
public class TextSearchInfo {
private static final FieldType SIMPLE_MATCH_ONLY_FIELD_TYPE = new FieldType();
static {
SIMPLE_MATCH_ONLY_FIELD_TYPE.setTokenized(false);
SIMPLE_MATCH_ONLY_FIELD_TYPE.setOmitNorms(true);
SIMPLE_MATCH_ONLY_FIELD_TYPE.freeze();
}
/**
* Defines indexing information for fields that support only simple match text queries
*
* Note that the results of {@link #isStored()} for this may not be accurate
*/
public static final TextSearchInfo SIMPLE_MATCH_ONLY = new TextSearchInfo(SIMPLE_MATCH_ONLY_FIELD_TYPE);
/**
* Specifies that this field does not support text searching of any kind
*/
public static final TextSearchInfo NONE = new TextSearchInfo(SIMPLE_MATCH_ONLY_FIELD_TYPE);
private final FieldType luceneFieldType;
/**
* Create a TextSearchInfo by wrapping a lucene FieldType
*/
public TextSearchInfo(FieldType luceneFieldType) {
this.luceneFieldType = luceneFieldType;
}
/**
* @return whether or not this field supports positional queries
*/
public boolean hasPositions() {
return luceneFieldType.indexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) >= 0;
}
/**
* @return whether or not this field has indexed offsets for highlighting
*/
public boolean hasOffsets() {
return luceneFieldType.indexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) >= 0;
}
/**
* @return whether or not this field has indexed norms
*/
public boolean hasNorms() {
return luceneFieldType.omitNorms() == false;
}
/**
* @return whether or not this field is tokenized
*/
public boolean isTokenized() {
return luceneFieldType.tokenized();
}
/**
* @return whether or not this field is stored
*/
public boolean isStored() {
return luceneFieldType.stored(); // TODO move this directly to MappedFieldType? It's not text specific...
}
/**
* What sort of term vectors are available
*/
public enum TermVector { NONE, DOCS, POSITIONS, OFFSETS }
/**
* @return the type of term vectors available for this field
*/
public TermVector termVectors() {
if (luceneFieldType.storeTermVectors() == false) {
return TermVector.NONE;
}
if (luceneFieldType.storeTermVectorOffsets()) {
return TermVector.OFFSETS;
}
if (luceneFieldType.storeTermVectorPositions()) {
return TermVector.POSITIONS;
}
return TermVector.DOCS;
}
}

View File

@ -101,7 +101,7 @@ public class TypeFieldMapper extends MetadataFieldMapper {
public static final TypeFieldType INSTANCE = new TypeFieldType();
private TypeFieldType() {
super(NAME, true, false, Collections.emptyMap());
super(NAME, true, false, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
}
protected TypeFieldType(TypeFieldType ref) {

View File

@ -72,7 +72,7 @@ public class VersionFieldMapper extends MetadataFieldMapper {
public static final VersionFieldType INSTANCE = new VersionFieldType();
private VersionFieldType() {
super(NAME, false, true, Collections.emptyMap());
super(NAME, false, true, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
}
protected VersionFieldType(VersionFieldType ref) {

View File

@ -663,7 +663,7 @@ public abstract class IntervalsSourceProvider implements NamedWriteable, ToXCont
}
private void checkPositions(MappedFieldType type) {
if (type.hasPositions() == false) {
if (type.getTextSearchInfo().hasPositions() == false) {
throw new IllegalArgumentException("Cannot create intervals over field [" + type.name() + "] with no positions indexed");
}
}
@ -801,7 +801,7 @@ public abstract class IntervalsSourceProvider implements NamedWriteable, ToXCont
}
private void checkPositions(MappedFieldType type) {
if (type.hasPositions() == false) {
if (type.getTextSearchInfo().hasPositions() == false) {
throw new IllegalArgumentException("Cannot create intervals over field [" + type.name() + "] with no positions indexed");
}
}

View File

@ -368,7 +368,7 @@ public class MatchQuery {
super(analyzer);
this.fieldType = fieldType;
setEnablePositionIncrements(enablePositionIncrements);
if (fieldType.hasPositions()) {
if (fieldType.getTextSearchInfo().hasPositions()) {
setAutoGenerateMultiTermSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery);
} else {
setAutoGenerateMultiTermSynonymsPhraseQuery(false);
@ -840,7 +840,7 @@ public class MatchQuery {
}
private void checkForPositions(String field) {
if (fieldType.hasPositions() == false) {
if (fieldType.getTextSearchInfo().hasPositions() == false) {
throw new IllegalStateException("field:[" + field + "] was indexed without position data; cannot run PhraseQuery");
}
}

View File

@ -23,7 +23,6 @@ import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.Token;
@ -53,6 +52,7 @@ import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType;
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.ExistsQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryShardContext;
@ -518,13 +518,12 @@ public class QueryStringQueryParser extends XQueryParser {
Analyzer oldAnalyzer = getAnalyzer();
try {
MappedFieldType currentFieldType = context.fieldMapper(field);
if (currentFieldType == null) {
if (currentFieldType == null || currentFieldType.getTextSearchInfo() == TextSearchInfo.NONE) {
return newUnmappedFieldQuery(field);
}
setAnalyzer(forceAnalyzer == null ? queryBuilder.context.getSearchAnalyzer(currentFieldType) : forceAnalyzer);
FieldType ft = context.getMapperService().getLuceneFieldType(field);
Query query = null;
if (ft.tokenized() == false) {
if (currentFieldType.getTextSearchInfo().isTokenized() == false) {
query = currentFieldType.prefixQuery(termStr, getMultiTermRewriteMethod(), context);
} else {
query = getPossiblyAnalyzedPrefixQuery(currentFieldType.name(), termStr, currentFieldType);

View File

@ -51,6 +51,7 @@ import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.SourceFieldMapper;
import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.mapper.StringFieldType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.search.dfs.AggregatedDfs;
@ -201,7 +202,7 @@ public class TermVectorsService {
continue;
}
// already retrieved, only if the analyzer hasn't been overridden at the field
if (indexShard.mapperService().getLuceneFieldType(field).storeTermVectors() &&
if (fieldType.getTextSearchInfo().termVectors() != TextSearchInfo.TermVector.NONE &&
(request.perFieldAnalyzer() == null || !request.perFieldAnalyzer().containsKey(field))) {
continue;
}

View File

@ -18,7 +18,6 @@
*/
package org.elasticsearch.search.fetch.subphase.highlight;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.search.highlight.Encoder;
import org.apache.lucene.search.vectorhighlight.BaseFragmentsBuilder;
import org.apache.lucene.search.vectorhighlight.BoundaryScanner;
@ -39,6 +38,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.fetch.FetchPhaseExecutionException;
import org.elasticsearch.search.fetch.FetchSubPhase;
@ -75,11 +75,12 @@ public class FastVectorHighlighter implements Highlighter {
FetchSubPhase.HitContext hitContext = highlighterContext.hitContext;
MappedFieldType fieldType = highlighterContext.fieldType;
if (canHighlight(highlighterContext.luceneFieldType) == false) {
if (canHighlight(fieldType) == false) {
throw new IllegalArgumentException("the field [" + highlighterContext.fieldName +
"] should be indexed with term vector with position offsets to be used with fast vector highlighter");
}
TextSearchInfo tsi = fieldType.getTextSearchInfo();
Encoder encoder = field.fieldOptions().encoder().equals("html") ?
HighlightUtils.Encoders.HTML : HighlightUtils.Encoders.DEFAULT;
@ -99,7 +100,7 @@ public class FastVectorHighlighter implements Highlighter {
if (field.fieldOptions().numberOfFragments() == 0) {
fragListBuilder = new SingleFragListBuilder();
if (!forceSource && highlighterContext.luceneFieldType.stored()) {
if (!forceSource && tsi.isStored()) {
fragmentsBuilder = new SimpleFragmentsBuilder(fieldType, field.fieldOptions().preTags(),
field.fieldOptions().postTags(), boundaryScanner);
} else {
@ -110,7 +111,7 @@ public class FastVectorHighlighter implements Highlighter {
fragListBuilder = field.fieldOptions().fragmentOffset() == -1 ?
new SimpleFragListBuilder() : new SimpleFragListBuilder(field.fieldOptions().fragmentOffset());
if (field.fieldOptions().scoreOrdered()) {
if (!forceSource && highlighterContext.luceneFieldType.stored()) {
if (!forceSource && tsi.isStored()) {
fragmentsBuilder = new ScoreOrderFragmentsBuilder(field.fieldOptions().preTags(),
field.fieldOptions().postTags(), boundaryScanner);
} else {
@ -118,7 +119,7 @@ public class FastVectorHighlighter implements Highlighter {
field.fieldOptions().preTags(), field.fieldOptions().postTags(), boundaryScanner);
}
} else {
if (!forceSource && highlighterContext.luceneFieldType.stored()) {
if (!forceSource && tsi.isStored()) {
fragmentsBuilder = new SimpleFragmentsBuilder(fieldType, field.fieldOptions().preTags(),
field.fieldOptions().postTags(), boundaryScanner);
} else {
@ -211,10 +212,8 @@ public class FastVectorHighlighter implements Highlighter {
}
@Override
public boolean canHighlight(FieldType fieldType) {
return fieldType.storeTermVectors()
&& fieldType.storeTermVectorOffsets()
&& fieldType.storeTermVectorPositions();
public boolean canHighlight(MappedFieldType ft) {
return ft.getTextSearchInfo().termVectors() == TextSearchInfo.TermVector.OFFSETS;
}
private static BoundaryScanner getBoundaryScanner(Field field) {

View File

@ -108,10 +108,9 @@ public class HighlightPhase implements FetchSubPhase {
highlightQuery = query;
}
HighlighterContext highlighterContext = new HighlighterContext(fieldType.name(),
field, fieldType, shardTarget, context, highlight, hitContext, highlightQuery,
context.getMapperService().getLuceneFieldType(fieldType.name()));
field, fieldType, shardTarget, context, highlight, hitContext, highlightQuery);
if ((highlighter.canHighlight(highlighterContext.luceneFieldType) == false) && fieldNameContainsWildcards) {
if ((highlighter.canHighlight(fieldType) == false) && fieldNameContainsWildcards) {
// if several fieldnames matched the wildcard then we want to skip those that we cannot highlight
continue;
}

View File

@ -18,12 +18,12 @@
*/
package org.elasticsearch.search.fetch.subphase.highlight;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.search.highlight.DefaultEncoder;
import org.apache.lucene.search.highlight.Encoder;
import org.apache.lucene.search.highlight.SimpleHTMLEncoder;
import org.elasticsearch.index.fieldvisitor.CustomFieldsVisitor;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.fetch.FetchSubPhase;
import org.elasticsearch.search.lookup.SourceLookup;
@ -53,8 +53,8 @@ public final class HighlightUtils {
boolean forceSource) throws IOException {
//percolator needs to always load from source, thus it sets the global force source to true
List<Object> textsToHighlight;
FieldType luceneFieldType = context.getMapperService().getLuceneFieldType(fieldType.name());
if (forceSource == false && luceneFieldType.stored()) {
TextSearchInfo tsi = fieldType.getTextSearchInfo();
if (forceSource == false && tsi.isStored()) {
CustomFieldsVisitor fieldVisitor = new CustomFieldsVisitor(singleton(fieldType.name()), false);
hitContext.reader().document(hitContext.docId(), fieldVisitor);
textsToHighlight = fieldVisitor.fields().get(fieldType.name());

View File

@ -18,7 +18,7 @@
*/
package org.elasticsearch.search.fetch.subphase.highlight;
import org.apache.lucene.document.FieldType;
import org.elasticsearch.index.mapper.MappedFieldType;
/**
* Highlights a search result.
@ -27,5 +27,5 @@ public interface Highlighter {
HighlightField highlight(HighlighterContext highlighterContext);
boolean canHighlight(FieldType fieldType);
boolean canHighlight(MappedFieldType fieldType);
}

View File

@ -18,7 +18,6 @@
*/
package org.elasticsearch.search.fetch.subphase.highlight;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.search.Query;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.query.QueryShardContext;
@ -35,7 +34,6 @@ public class HighlighterContext {
public final SearchContextHighlight highlight;
public final FetchSubPhase.HitContext hitContext;
public final Query query;
public final FieldType luceneFieldType;
public HighlighterContext(String fieldName,
SearchContextHighlight.Field field,
@ -44,7 +42,7 @@ public class HighlighterContext {
QueryShardContext context,
SearchContextHighlight highlight,
FetchSubPhase.HitContext hitContext,
Query query, FieldType luceneFieldType) {
Query query) {
this.fieldName = fieldName;
this.field = field;
this.fieldType = fieldType;
@ -53,6 +51,5 @@ public class HighlighterContext {
this.highlight = highlight;
this.hitContext = hitContext;
this.query = query;
this.luceneFieldType = luceneFieldType;
}
}

View File

@ -22,7 +22,6 @@ import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.search.highlight.Encoder;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Fragmenter;
@ -203,7 +202,7 @@ public class PlainHighlighter implements Highlighter {
}
@Override
public boolean canHighlight(FieldType fieldType) {
public boolean canHighlight(MappedFieldType fieldType) {
return true;
}

View File

@ -19,9 +19,6 @@
package org.elasticsearch.search.fetch.subphase.highlight;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.highlight.Encoder;
import org.apache.lucene.search.uhighlight.BoundedBreakIteratorScanner;
@ -40,6 +37,7 @@ import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.IdFieldMapper;
import org.elasticsearch.index.mapper.KeywordFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.fetch.FetchPhaseExecutionException;
import org.elasticsearch.search.fetch.FetchSubPhase;
@ -56,7 +54,7 @@ import static org.apache.lucene.search.uhighlight.CustomUnifiedHighlighter.MULTI
public class UnifiedHighlighter implements Highlighter {
@Override
public boolean canHighlight(FieldType fieldType) {
public boolean canHighlight(MappedFieldType fieldType) {
return true;
}
@ -89,8 +87,7 @@ public class UnifiedHighlighter implements Highlighter {
final IndexSearcher searcher = new IndexSearcher(hitContext.reader());
final CustomUnifiedHighlighter highlighter;
final String fieldValue = mergeFieldValues(fieldValues, MULTIVAL_SEP_CHAR);
FieldInfo fi = hitContext.reader().getFieldInfos().fieldInfo(field.field());
final OffsetSource offsetSource = getOffsetSource(highlighterContext.luceneFieldType);
final OffsetSource offsetSource = getOffsetSource(fieldType);
int fieldValueLength = fieldValue.length();
if (keywordIgnoreAbove != null && fieldValueLength > keywordIgnoreAbove) {
return null; // skip highlighting keyword terms that were ignored during indexing
@ -105,7 +102,7 @@ public class UnifiedHighlighter implements Highlighter {
}
if (numberOfFragments == 0
// non-tokenized fields should not use any break iterator (ignore boundaryScannerType)
|| highlighterContext.luceneFieldType.tokenized() == false) {
|| fieldType.getTextSearchInfo().isTokenized() == false) {
// we use a control char to separate values, which is the only char that the custom break iterator
// breaks the text on, so we don't lose the distinction between the different values of a field and we
// get back a snippet per value
@ -220,11 +217,13 @@ public class UnifiedHighlighter implements Highlighter {
return rawValue.substring(0, Math.min(rawValue.length(), Integer.MAX_VALUE - 1));
}
protected OffsetSource getOffsetSource(FieldType fieldType) {
if (fieldType.indexOptions() == IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) {
return fieldType.storeTermVectors() ? OffsetSource.POSTINGS_WITH_TERM_VECTORS : OffsetSource.POSTINGS;
protected OffsetSource getOffsetSource(MappedFieldType fieldType) {
TextSearchInfo tsi = fieldType.getTextSearchInfo();
if (tsi.hasOffsets()) {
return tsi.termVectors() != TextSearchInfo.TermVector.NONE
? OffsetSource.POSTINGS_WITH_TERM_VECTORS : OffsetSource.POSTINGS;
}
if (fieldType.storeTermVectorOffsets()) {
if (tsi.termVectors() == TextSearchInfo.TermVector.OFFSETS) {
return OffsetSource.TERM_VECTORS;
}
return OffsetSource.ANALYSIS;

View File

@ -390,7 +390,8 @@ public class DateFieldMapperTests extends FieldMapperTestCase<DateFieldMapper.Bu
MapperService.MergeReason.MAPPING_UPDATE);
assertThat(indexService.mapperService().fieldType("release_date"), notNullValue());
assertFalse(indexService.mapperService().getLuceneFieldType("release_date").stored());
assertFalse(indexService.mapperService().fieldType("release_date")
.getTextSearchInfo().isStored());
String updateFormatMapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("movie")
.startObject("properties")

View File

@ -73,7 +73,7 @@ public class DocumentFieldMapperTests extends LuceneTestCase {
static class FakeFieldType extends TermBasedFieldType {
FakeFieldType(String name) {
super(name, true, true, Collections.emptyMap());
super(name, true, true, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
}
FakeFieldType(FakeFieldType other) {

View File

@ -127,7 +127,7 @@ public class ExternalMapper extends FieldMapper {
static class ExternalFieldType extends TermBasedFieldType {
ExternalFieldType(String name, boolean indexed, boolean hasDocValues) {
super(name, indexed, hasDocValues, Collections.emptyMap());
super(name, indexed, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
}
protected ExternalFieldType(ExternalFieldType ref) {

View File

@ -86,7 +86,7 @@ public class FakeStringFieldMapper extends FieldMapper {
public FakeStringFieldType(String name) {
super(name, true, true, Collections.emptyMap());
super(name, true, true, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
setIndexAnalyzer(Lucene.STANDARD_ANALYZER);
setSearchAnalyzer(Lucene.STANDARD_ANALYZER);
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexableField;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.xcontent.XContentType;
@ -51,16 +50,12 @@ public class GenericStoreDynamicTemplateTests extends ESSingleNodeTestCase {
assertThat(f.stringValue(), equalTo("some name"));
assertThat(f.fieldType().stored(), equalTo(true));
FieldType fieldType = mapperService.getLuceneFieldType("name");
assertThat(fieldType.stored(), equalTo(true));
assertTrue(mapperService.fieldType("name").getTextSearchInfo().isStored());
boolean stored = false;
for (IndexableField field : doc.getFields("age")) {
stored |= field.fieldType().stored();
}
assertTrue(stored);
fieldType = mapperService.getLuceneFieldType("age");
assertThat(fieldType.stored(), equalTo(true));
}
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexableField;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressedXContent;
@ -40,7 +39,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
mapperService.merge("person", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name").indexOptions());
assertTrue(mapperService.fieldType("name").isSearchable());
assertThat(mapperService.fieldType("name.indexed"), nullValue());
BytesReference json = BytesReference.bytes(XContentFactory.jsonBuilder().startObject().field("name", "some name").endObject());
@ -54,7 +53,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/test-mapping2.json");
mapperService.merge("person", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name").indexOptions());
assertTrue(mapperService.fieldType("name").isSearchable());
assertThat(mapperService.fieldType("name.indexed"), notNullValue());
assertThat(mapperService.fieldType("name.not_indexed"), notNullValue());
@ -70,7 +69,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/test-mapping3.json");
mapperService.merge("person", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name").indexOptions());
assertTrue(mapperService.fieldType("name").isSearchable());
assertThat(mapperService.fieldType("name.indexed"), notNullValue());
assertThat(mapperService.fieldType("name.not_indexed"), notNullValue());
@ -80,7 +79,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/test-mapping4.json");
mapperService.merge("person", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name").indexOptions());
assertTrue(mapperService.fieldType("name").isSearchable());
assertThat(mapperService.fieldType("name.indexed"), notNullValue());
assertThat(mapperService.fieldType("name.not_indexed"), notNullValue());
@ -94,7 +93,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
mapperService.merge("person", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name").indexOptions());
assertTrue(mapperService.fieldType("name").isSearchable());
assertThat(mapperService.fieldType("name.indexed"), nullValue());
BytesReference json = BytesReference.bytes(XContentFactory.jsonBuilder().startObject().field("name", "some name").endObject());
@ -109,7 +108,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/upgrade1.json");
mapperService.merge("person", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name").indexOptions());
assertTrue(mapperService.fieldType("name").isSearchable());
assertThat(mapperService.fieldType("name.indexed"), notNullValue());
assertThat(mapperService.fieldType("name.not_indexed"), notNullValue());
@ -126,7 +125,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/upgrade2.json");
mapperService.merge("person", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name").indexOptions());
assertTrue(mapperService.fieldType("name").isSearchable());
assertThat(mapperService.fieldType("name.indexed"), notNullValue());
assertThat(mapperService.fieldType("name.not_indexed"), notNullValue());
@ -144,7 +143,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
}
// There are conflicts, so the `name.not_indexed3` has not been added
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name").indexOptions());
assertTrue(mapperService.fieldType("name").isSearchable());
assertThat(mapperService.fieldType("name.indexed"), notNullValue());
assertThat(mapperService.fieldType("name.not_indexed"), notNullValue());
assertThat(mapperService.fieldType("name.not_indexed2"), notNullValue());

View File

@ -93,35 +93,36 @@ public class MultiFieldTests extends ESSingleNodeTestCase {
assertThat(mapperService.fieldType("name"), notNullValue());
assertThat(mapperService.fieldType("name"), instanceOf(TextFieldType.class));
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name").indexOptions());
assertThat(mapperService.getLuceneFieldType("name").stored(), equalTo(true));
assertThat(mapperService.getLuceneFieldType("name").tokenized(), equalTo(true));
assertTrue(mapperService.fieldType("name").isSearchable());
assertTrue(mapperService.fieldType("name").getTextSearchInfo().isStored());
assertTrue(mapperService.fieldType("name").getTextSearchInfo().isTokenized());
assertThat(mapperService.fieldType("name.indexed"), notNullValue());
assertThat(mapperService.fieldType("name"), instanceOf(TextFieldType.class));
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name.indexed").indexOptions());
assertThat(mapperService.getLuceneFieldType("name.indexed").stored(), equalTo(false));
assertThat(mapperService.getLuceneFieldType("name.indexed").tokenized(), equalTo(true));
assertTrue(mapperService.fieldType("name.indexed").isSearchable());
assertFalse(mapperService.fieldType("name.indexed").getTextSearchInfo().isStored());
assertTrue(mapperService.fieldType("name.indexed").getTextSearchInfo().isTokenized());
assertThat(mapperService.fieldType("name.not_indexed"), notNullValue());
assertThat(mapperService.fieldType("name"), instanceOf(TextFieldType.class));
assertEquals(IndexOptions.NONE, mapperService.getLuceneFieldType("name.not_indexed").indexOptions());
assertThat(mapperService.getLuceneFieldType("name.not_indexed").stored(), equalTo(true));
assertThat(mapperService.getLuceneFieldType("name.not_indexed").tokenized(), equalTo(true));
assertFalse(mapperService.fieldType("name.not_indexed").isSearchable());
assertTrue(mapperService.fieldType("name.not_indexed").getTextSearchInfo().isStored());
assertTrue(mapperService.fieldType("name.not_indexed").getTextSearchInfo().isTokenized());
assertThat(mapperService.fieldType("name.test1"), notNullValue());
assertThat(mapperService.fieldType("name"), instanceOf(TextFieldType.class));
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("name.test1").indexOptions());
assertThat(mapperService.getLuceneFieldType("name.test1").stored(), equalTo(true));
assertThat(mapperService.getLuceneFieldType("name.test1").tokenized(), equalTo(true));
assertTrue(mapperService.fieldType("name.test1").isSearchable());
assertTrue(mapperService.fieldType("name.test1").getTextSearchInfo().isStored());
assertTrue(mapperService.fieldType("name.test1").getTextSearchInfo().isTokenized());
assertThat(mapperService.fieldType("name.test1").eagerGlobalOrdinals(), equalTo(true));
assertThat(mapperService.fieldType("object1.multi1"), notNullValue());
assertThat(mapperService.fieldType("object1.multi1"), instanceOf(DateFieldMapper.DateFieldType.class));
assertThat(mapperService.fieldType("object1.multi1.string"), notNullValue());
assertThat(mapperService.fieldType("object1.multi1.string"), instanceOf(KeywordFieldMapper.KeywordFieldType.class));
assertNotSame(IndexOptions.NONE, mapperService.getLuceneFieldType("object1.multi1.string").indexOptions());
assertThat(mapperService.getLuceneFieldType("object1.multi1.string").tokenized(), equalTo(false));
assertTrue(mapperService.fieldType("object1.multi1.string").isSearchable());
assertNotNull(mapperService.fieldType("object1.multi1.string").getTextSearchInfo());
assertFalse(mapperService.fieldType("object1.multi1.string").getTextSearchInfo().isTokenized());
}
public void testBuildThenParse() throws Exception {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.IndexableField;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.xcontent.XContentType;
@ -51,26 +50,21 @@ public class PathMatchDynamicTemplateTests extends ESSingleNodeTestCase {
assertThat(f.stringValue(), equalTo("top_level"));
assertThat(f.fieldType().stored(), equalTo(false));
FieldType fieldType = mapperService.getLuceneFieldType("name");
assertThat(fieldType.stored(), equalTo(false));
assertThat(mapperService.fieldType("name").getTextSearchInfo().isStored(), equalTo(false));
f = doc.getField("obj1.name");
assertThat(f.name(), equalTo("obj1.name"));
assertThat(f.fieldType().stored(), equalTo(true));
fieldType = mapperService.getLuceneFieldType("obj1.name");
assertThat(fieldType.stored(), equalTo(true));
assertThat(mapperService.fieldType("obj1.name").getTextSearchInfo().isStored(), equalTo(true));
f = doc.getField("obj1.obj2.name");
assertThat(f.name(), equalTo("obj1.obj2.name"));
assertThat(f.fieldType().stored(), equalTo(false));
fieldType = mapperService.getLuceneFieldType("obj1.obj2.name");
assertThat(fieldType.stored(), equalTo(false));
assertThat(mapperService.fieldType("obj1.obj2.name").getTextSearchInfo().isStored(), equalTo(false));
// verify more complex path_match expressions
fieldType = mapperService.getLuceneFieldType("obj3.obj4.prop1");
assertNotNull(fieldType);
assertNotNull(mapperService.fieldType("obj3.obj4.prop1").getTextSearchInfo());
}
}

View File

@ -77,14 +77,14 @@ public class TextFieldTypeTests extends FieldTypeTestCase<TextFieldType> {
@Override
protected TextFieldType createDefaultFieldType(String name, Map<String, String> meta) {
return new TextFieldType(name, true, true, meta);
return new TextFieldType(name, true, meta);
}
public void testTermQuery() {
MappedFieldType ft = new TextFieldType("field");
assertEquals(new TermQuery(new Term("field", "foo")), ft.termQuery("foo", null));
MappedFieldType unsearchable = new TextFieldType("field", false, true, Collections.emptyMap());
MappedFieldType unsearchable = new TextFieldType("field", false, Collections.emptyMap());
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> unsearchable.termQuery("bar", null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
@ -98,7 +98,7 @@ public class TextFieldTypeTests extends FieldTypeTestCase<TextFieldType> {
assertEquals(new TermInSetQuery("field", terms),
ft.termsQuery(Arrays.asList("foo", "bar"), null));
MappedFieldType unsearchable = new TextFieldType("field", false, true, Collections.emptyMap());
MappedFieldType unsearchable = new TextFieldType("field", false, Collections.emptyMap());
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> unsearchable.termsQuery(Arrays.asList("foo", "bar"), null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
@ -120,7 +120,7 @@ public class TextFieldTypeTests extends FieldTypeTestCase<TextFieldType> {
assertEquals(new RegexpQuery(new Term("field","foo.*")),
ft.regexpQuery("foo.*", 0, 10, null, MOCK_QSC));
MappedFieldType unsearchable = new TextFieldType("field", false, true, Collections.emptyMap());
MappedFieldType unsearchable = new TextFieldType("field", false, Collections.emptyMap());
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> unsearchable.regexpQuery("foo.*", 0, 10, null, MOCK_QSC));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
@ -136,7 +136,7 @@ public class TextFieldTypeTests extends FieldTypeTestCase<TextFieldType> {
assertEquals(new FuzzyQuery(new Term("field","foo"), 2, 1, 50, true),
ft.fuzzyQuery("foo", Fuzziness.fromEdits(2), 1, 50, true, MOCK_QSC));
MappedFieldType unsearchable = new TextFieldType("field", false, true, Collections.emptyMap());
MappedFieldType unsearchable = new TextFieldType("field", false, Collections.emptyMap());
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> unsearchable.fuzzyQuery("foo", Fuzziness.fromEdits(2), 1, 50, true, MOCK_QSC));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
@ -150,7 +150,7 @@ public class TextFieldTypeTests extends FieldTypeTestCase<TextFieldType> {
public void testIndexPrefixes() {
TextFieldType ft = new TextFieldType("field");
ft.setPrefixFieldType(new TextFieldMapper.PrefixFieldType("field", "field._index_prefix", 2, 10, true));
ft.setPrefixFieldType(new TextFieldMapper.PrefixFieldType(ft, "field._index_prefix", 2, 10, true));
Query q = ft.prefixQuery("goin", CONSTANT_SCORE_REWRITE, randomMockShardContext());
assertEquals(new ConstantScoreQuery(new TermQuery(new Term("field._index_prefix", "goin"))), q);

View File

@ -104,7 +104,7 @@ public class ExistsQueryBuilderTests extends AbstractQueryTestCase<ExistsQueryBu
assertThat(constantScoreQuery.getQuery(), instanceOf(DocValuesFieldExistsQuery.class));
DocValuesFieldExistsQuery dvExistsQuery = (DocValuesFieldExistsQuery) constantScoreQuery.getQuery();
assertEquals(field, dvExistsQuery.getField());
} else if (context.getMapperService().getLuceneFieldType(field).omitNorms() == false) {
} else if (context.getMapperService().fieldType(field).getTextSearchInfo().hasNorms()) {
assertThat(constantScoreQuery.getQuery(), instanceOf(NormsFieldExistsQuery.class));
NormsFieldExistsQuery normsExistsQuery = (NormsFieldExistsQuery) constantScoreQuery.getQuery();
assertEquals(field, normsExistsQuery.getField());

View File

@ -1046,7 +1046,7 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
QueryStringQueryBuilder queryBuilder = new QueryStringQueryBuilder(TEXT_FIELD_NAME + ":*");
Query query = queryBuilder.toQuery(context);
if (context.getIndexSettings().getIndexVersionCreated().onOrAfter(Version.V_6_1_0)
&& (context.getMapperService().getLuceneFieldType(TEXT_FIELD_NAME).omitNorms() == false)) {
&& (context.getMapperService().fieldType(TEXT_FIELD_NAME).getTextSearchInfo().hasNorms())) {
assertThat(query, equalTo(new ConstantScoreQuery(new NormsFieldExistsQuery(TEXT_FIELD_NAME))));
} else {
assertThat(query, equalTo(new ConstantScoreQuery(new TermQuery(new Term("_field_names", TEXT_FIELD_NAME)))));
@ -1057,7 +1057,7 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
queryBuilder = new QueryStringQueryBuilder("_exists_:" + value);
query = queryBuilder.toQuery(context);
if (context.getIndexSettings().getIndexVersionCreated().onOrAfter(Version.V_6_1_0)
&& (context.getMapperService().getLuceneFieldType(TEXT_FIELD_NAME).omitNorms() == false)) {
&& (context.getMapperService().fieldType(TEXT_FIELD_NAME).getTextSearchInfo().hasNorms())) {
assertThat(query, equalTo(new ConstantScoreQuery(new NormsFieldExistsQuery(TEXT_FIELD_NAME))));
} else {
assertThat(query, equalTo(new ConstantScoreQuery(new TermQuery(new Term("_field_names", TEXT_FIELD_NAME)))));

View File

@ -141,8 +141,7 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuil
&& context.getMapperService().fieldType(queryBuilder.fieldName()).hasDocValues()) {
expectedQuery = new ConstantScoreQuery(new DocValuesFieldExistsQuery(expectedFieldName));
} else if (context.getIndexSettings().getIndexVersionCreated().onOrAfter(Version.V_6_1_0) &&
context.getMapperService().getLuceneFieldType(queryBuilder.fieldName()) != null &&
context.getMapperService().getLuceneFieldType(queryBuilder.fieldName()).omitNorms() == false) {
context.getMapperService().fieldType(queryBuilder.fieldName()).getTextSearchInfo().hasNorms()) {
expectedQuery = new ConstantScoreQuery(new NormsFieldExistsQuery(expectedFieldName));
} else {
expectedQuery = new ConstantScoreQuery(new TermQuery(new Term(FieldNamesFieldMapper.NAME, expectedFieldName)));

View File

@ -33,6 +33,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.KeywordFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.InnerHitBuilderTests;
import org.elasticsearch.index.query.QueryShardContext;
@ -196,7 +197,7 @@ public class CollapseBuilderTests extends AbstractSerializingTestCase<CollapseBu
}
{
MappedFieldType fieldType = new MappedFieldType("field", true, true, Collections.emptyMap()) {
MappedFieldType fieldType = new MappedFieldType("field", true, true, TextSearchInfo.NONE, Collections.emptyMap()) {
@Override
public MappedFieldType clone() {
return null;

View File

@ -18,8 +18,8 @@
*/
package org.elasticsearch.search.fetch.subphase.highlight;
import org.apache.lucene.document.FieldType;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.mapper.MappedFieldType;
import java.util.ArrayList;
import java.util.List;
@ -64,7 +64,7 @@ public class CustomHighlighter implements Highlighter {
}
@Override
public boolean canHighlight(FieldType fieldType) {
public boolean canHighlight(MappedFieldType fieldType) {
return true;
}

View File

@ -52,6 +52,7 @@ import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.IdFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.search.internal.ShardSearchRequest;
@ -118,7 +119,7 @@ public class SliceBuilderTests extends ESTestCase {
private QueryShardContext createShardContext(Version indexVersionCreated, IndexReader reader,
String fieldName, DocValuesType dvType, int numShards, int shardId) {
MappedFieldType fieldType = new MappedFieldType(fieldName, true, dvType != null, Collections.emptyMap()) {
MappedFieldType fieldType = new MappedFieldType(fieldName, true, dvType != null, TextSearchInfo.NONE, Collections.emptyMap()) {
@Override
public MappedFieldType clone() {
return null;

View File

@ -49,7 +49,7 @@ public class MockFieldMapper extends FieldMapper {
public static class FakeFieldType extends TermBasedFieldType {
public FakeFieldType(String name) {
super(name, true, false, Collections.emptyMap());
super(name, true, false, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
}
protected FakeFieldType(FakeFieldType ref) {

View File

@ -44,6 +44,7 @@ import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.mapper.TypeParsers;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
@ -163,7 +164,7 @@ public class HistogramFieldMapper extends FieldMapper {
public static class HistogramFieldType extends MappedFieldType {
public HistogramFieldType(String name, boolean hasDocValues, Map<String, String> meta) {
super(name, false, hasDocValues, meta);
super(name, false, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
}
HistogramFieldType(HistogramFieldType ref) {

View File

@ -47,6 +47,7 @@ import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.StringFieldType;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.search.DocValueFormat;
@ -231,7 +232,7 @@ public final class FlatObjectFieldMapper extends DynamicKeyFieldMapper {
public KeyedFlatObjectFieldType(String name, boolean indexed, boolean hasDocValues, String key,
boolean splitQueriesOnWhitespace, Map<String, String> meta) {
super(name, indexed, hasDocValues, meta);
super(name, indexed, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
if (splitQueriesOnWhitespace == false) {
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);
@ -482,7 +483,7 @@ public final class FlatObjectFieldMapper extends DynamicKeyFieldMapper {
public RootFlatObjectFieldType(String name, boolean indexed, boolean hasDocValues, Map<String, String> meta,
boolean splitQueriesOnWhitespace) {
super(name, indexed, hasDocValues, meta);
super(name, indexed, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
this.splitQueriesOnWhitespace = splitQueriesOnWhitespace;
setIndexAnalyzer(Lucene.KEYWORD_ANALYZER);
if (splitQueriesOnWhitespace) {

View File

@ -24,6 +24,7 @@ import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
@ -99,7 +100,7 @@ public class DenseVectorFieldMapper extends FieldMapper {
private final int dims;
public DenseVectorFieldType(String name, int dims, Map<String, String> meta) {
super(name, false, false, meta);
super(name, false, false, TextSearchInfo.NONE, meta);
this.dims = dims;
}

View File

@ -24,6 +24,7 @@ import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
@ -86,7 +87,7 @@ public class SparseVectorFieldMapper extends FieldMapper {
public static final class SparseVectorFieldType extends MappedFieldType {
public SparseVectorFieldType(String name, Map<String, String> meta) {
super(name, false, false, meta);
super(name, false, false, TextSearchInfo.NONE, meta);
}
protected SparseVectorFieldType(SparseVectorFieldType ref) {

View File

@ -61,6 +61,7 @@ import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.index.mapper.TextSearchInfo;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.similarity.SimilarityProvider;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
@ -175,7 +176,7 @@ public class WildcardFieldMapper extends FieldMapper {
@Override
public WildcardFieldMapper build(BuilderContext context) {
return new WildcardFieldMapper(
name, fieldType, new WildcardFieldType(buildFullName(context), meta), ignoreAbove,
name, fieldType, new WildcardFieldType(buildFullName(context), fieldType, meta), ignoreAbove,
multiFieldsBuilder.build(this, context), copyTo, nullValue);
}
}
@ -215,8 +216,8 @@ public class WildcardFieldMapper extends FieldMapper {
static Analyzer lowercaseNormalizer = new LowercaseNormalizer();
public WildcardFieldType(String name, Map<String, String> meta) {
super(name, true, true, meta);
public WildcardFieldType(String name, FieldType fieldType, Map<String, String> meta) {
super(name, true, true, new TextSearchInfo(fieldType), meta);
setIndexAnalyzer(WILDCARD_ANALYZER);
setSearchAnalyzer(Lucene.KEYWORD_ANALYZER);
}

View File

@ -16,6 +16,6 @@ public class WildcardFieldTypeTests extends FieldTypeTestCase<MappedFieldType> {
@Override
protected MappedFieldType createDefaultFieldType(String name, Map<String, String> meta) {
return new WildcardFieldMapper.WildcardFieldType(name, meta);
return new WildcardFieldMapper.WildcardFieldType(name, WildcardFieldMapper.Defaults.FIELD_TYPE, meta);
}
}