Rename index_prefix to index_prefixes (#30932)

This commit also adds index_prefixes tests to TextFieldMapperTests to ensure that cloning and wire-serialization work correctly
This commit is contained in:
Alan Woodward 2018-05-30 08:32:31 +01:00 committed by GitHub
parent a0af0e7f1e
commit 67905c85a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 26 deletions

View File

@ -89,7 +89,7 @@ The following parameters are accepted by `text` fields:
What information should be stored in the index, for search and highlighting purposes. What information should be stored in the index, for search and highlighting purposes.
Defaults to `positions`. Defaults to `positions`.
<<index-prefix-config,`index_prefix`>>:: <<index-prefix-config,`index_prefixes`>>::
If enabled, term prefixes of between 2 and 5 characters are indexed into a If enabled, term prefixes of between 2 and 5 characters are indexed into a
separate field. This allows prefix searches to run more efficiently, at separate field. This allows prefix searches to run more efficiently, at
@ -138,7 +138,7 @@ The following parameters are accepted by `text` fields:
[[index-prefix-config]] [[index-prefix-config]]
==== Index Prefix configuration ==== Index Prefix configuration
Text fields may also index term prefixes to speed up prefix searches. The `index_prefix` Text fields may also index term prefixes to speed up prefix searches. The `index_prefixes`
parameter is configured as below. Either or both of `min_chars` and `max_chars` may be excluded. parameter is configured as below. Either or both of `min_chars` and `max_chars` may be excluded.
Both values are treated as inclusive Both values are treated as inclusive
@ -151,7 +151,7 @@ PUT my_index
"properties": { "properties": {
"full_name": { "full_name": {
"type": "text", "type": "text",
"index_prefix" : { "index_prefixes" : {
"min_chars" : 1, <1> "min_chars" : 1, <1>
"max_chars" : 10 <2> "max_chars" : 10 <2>
} }

View File

@ -2,7 +2,7 @@
"search with index prefixes": "search with index prefixes":
- skip: - skip:
version: " - 6.99.99" version: " - 6.99.99"
reason: index_prefix is only available as of 6.3.0 reason: index_prefixes is only available as of 6.3.0
- do: - do:
indices.create: indices.create:
index: test index: test
@ -12,7 +12,7 @@
properties: properties:
text: text:
type: text type: text
index_prefix: index_prefixes:
min_chars: 1 min_chars: 1
max_chars: 10 max_chars: 10

View File

@ -156,7 +156,7 @@ public class TextFieldMapper extends FieldMapper {
PrefixFieldMapper prefixMapper = null; PrefixFieldMapper prefixMapper = null;
if (prefixFieldType != null) { if (prefixFieldType != null) {
if (fieldType().isSearchable() == false) { if (fieldType().isSearchable() == false) {
throw new IllegalArgumentException("Cannot set index_prefix on unindexed field [" + name() + "]"); throw new IllegalArgumentException("Cannot set index_prefixes on unindexed field [" + name() + "]");
} }
if (fieldType.indexOptions() == IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) { if (fieldType.indexOptions() == IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) {
prefixFieldType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS); prefixFieldType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
@ -203,7 +203,7 @@ public class TextFieldMapper extends FieldMapper {
builder.fielddataFrequencyFilter(minFrequency, maxFrequency, minSegmentSize); builder.fielddataFrequencyFilter(minFrequency, maxFrequency, minSegmentSize);
DocumentMapperParser.checkNoRemainingFields(propName, frequencyFilter, parserContext.indexVersionCreated()); DocumentMapperParser.checkNoRemainingFields(propName, frequencyFilter, parserContext.indexVersionCreated());
iterator.remove(); iterator.remove();
} else if (propName.equals("index_prefix")) { } else if (propName.equals("index_prefixes")) {
Map<?, ?> indexPrefix = (Map<?, ?>) propNode; Map<?, ?> indexPrefix = (Map<?, ?>) propNode;
int minChars = XContentMapValues.nodeIntegerValue(indexPrefix.remove("min_chars"), int minChars = XContentMapValues.nodeIntegerValue(indexPrefix.remove("min_chars"),
Defaults.INDEX_PREFIX_MIN_CHARS); Defaults.INDEX_PREFIX_MIN_CHARS);
@ -243,7 +243,7 @@ public class TextFieldMapper extends FieldMapper {
} }
} }
private static final class PrefixFieldType extends StringFieldType { static final class PrefixFieldType extends StringFieldType {
final int minChars; final int minChars;
final int maxChars; final int maxChars;
@ -268,14 +268,14 @@ public class TextFieldMapper extends FieldMapper {
} }
void doXContent(XContentBuilder builder) throws IOException { void doXContent(XContentBuilder builder) throws IOException {
builder.startObject("index_prefix"); builder.startObject("index_prefixes");
builder.field("min_chars", minChars); builder.field("min_chars", minChars);
builder.field("max_chars", maxChars); builder.field("max_chars", maxChars);
builder.endObject(); builder.endObject();
} }
@Override @Override
public MappedFieldType clone() { public PrefixFieldType clone() {
return new PrefixFieldType(name(), minChars, maxChars); return new PrefixFieldType(name(), minChars, maxChars);
} }
@ -305,6 +305,22 @@ public class TextFieldMapper extends FieldMapper {
public Query existsQuery(QueryShardContext context) { public Query existsQuery(QueryShardContext context) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
PrefixFieldType that = (PrefixFieldType) o;
return minChars == that.minChars &&
maxChars == that.maxChars;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), minChars, maxChars);
}
} }
private static final class PrefixFieldMapper extends FieldMapper { private static final class PrefixFieldMapper extends FieldMapper {
@ -355,6 +371,9 @@ public class TextFieldMapper extends FieldMapper {
this.fielddataMinFrequency = ref.fielddataMinFrequency; this.fielddataMinFrequency = ref.fielddataMinFrequency;
this.fielddataMaxFrequency = ref.fielddataMaxFrequency; this.fielddataMaxFrequency = ref.fielddataMaxFrequency;
this.fielddataMinSegmentSize = ref.fielddataMinSegmentSize; this.fielddataMinSegmentSize = ref.fielddataMinSegmentSize;
if (ref.prefixFieldType != null) {
this.prefixFieldType = ref.prefixFieldType.clone();
}
} }
public TextFieldType clone() { public TextFieldType clone() {
@ -368,6 +387,7 @@ public class TextFieldMapper extends FieldMapper {
} }
TextFieldType that = (TextFieldType) o; TextFieldType that = (TextFieldType) o;
return fielddata == that.fielddata return fielddata == that.fielddata
&& Objects.equals(prefixFieldType, that.prefixFieldType)
&& fielddataMinFrequency == that.fielddataMinFrequency && fielddataMinFrequency == that.fielddataMinFrequency
&& fielddataMaxFrequency == that.fielddataMaxFrequency && fielddataMaxFrequency == that.fielddataMaxFrequency
&& fielddataMinSegmentSize == that.fielddataMinSegmentSize; && fielddataMinSegmentSize == that.fielddataMinSegmentSize;
@ -375,7 +395,7 @@ public class TextFieldMapper extends FieldMapper {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), fielddata, return Objects.hash(super.hashCode(), fielddata, prefixFieldType,
fielddataMinFrequency, fielddataMaxFrequency, fielddataMinSegmentSize); fielddataMinFrequency, fielddataMaxFrequency, fielddataMinSegmentSize);
} }
@ -420,6 +440,10 @@ public class TextFieldMapper extends FieldMapper {
this.prefixFieldType = prefixFieldType; this.prefixFieldType = prefixFieldType;
} }
public PrefixFieldType getPrefixFieldType() {
return this.prefixFieldType;
}
@Override @Override
public String typeName() { public String typeName() {
return CONTENT_TYPE; return CONTENT_TYPE;

View File

@ -607,7 +607,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix").endObject() .startObject("index_prefixes").endObject()
.field("index_options", "offsets") .field("index_options", "offsets")
.endObject().endObject().endObject().endObject()); .endObject().endObject().endObject().endObject());
@ -623,7 +623,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix").endObject() .startObject("index_prefixes").endObject()
.field("index_options", "positions") .field("index_options", "positions")
.endObject().endObject().endObject().endObject()); .endObject().endObject().endObject().endObject());
@ -640,7 +640,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix").endObject() .startObject("index_prefixes").endObject()
.field("term_vector", "with_positions_offsets") .field("term_vector", "with_positions_offsets")
.endObject().endObject().endObject().endObject()); .endObject().endObject().endObject().endObject());
@ -657,7 +657,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix").endObject() .startObject("index_prefixes").endObject()
.field("term_vector", "with_positions") .field("term_vector", "with_positions")
.endObject().endObject().endObject().endObject()); .endObject().endObject().endObject().endObject());
@ -682,7 +682,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix") .startObject("index_prefixes")
.field("min_chars", 1) .field("min_chars", 1)
.field("max_chars", 10) .field("max_chars", 10)
.endObject() .endObject()
@ -716,7 +716,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix").endObject() .startObject("index_prefixes").endObject()
.endObject().endObject() .endObject().endObject()
.endObject().endObject()); .endObject().endObject());
CompressedXContent json = new CompressedXContent(mapping); CompressedXContent json = new CompressedXContent(mapping);
@ -741,7 +741,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix") .startObject("index_prefixes")
.field("min_chars", 1) .field("min_chars", 1)
.field("max_chars", 10) .field("max_chars", 10)
.endObject() .endObject()
@ -760,7 +760,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix") .startObject("index_prefixes")
.field("min_chars", 1) .field("min_chars", 1)
.field("max_chars", 10) .field("max_chars", 10)
.endObject() .endObject()
@ -783,7 +783,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix") .startObject("index_prefixes")
.field("min_chars", 11) .field("min_chars", 11)
.field("max_chars", 10) .field("max_chars", 10)
.endObject() .endObject()
@ -800,7 +800,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix") .startObject("index_prefixes")
.field("min_chars", 0) .field("min_chars", 0)
.field("max_chars", 10) .field("max_chars", 10)
.endObject() .endObject()
@ -817,7 +817,7 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.startObject("index_prefix") .startObject("index_prefixes")
.field("min_chars", 1) .field("min_chars", 1)
.field("max_chars", 25) .field("max_chars", 25)
.endObject() .endObject()
@ -834,13 +834,13 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("analyzer", "english") .field("analyzer", "english")
.field("index_prefix", (String) null) .field("index_prefixes", (String) null)
.endObject().endObject() .endObject().endObject()
.endObject().endObject()); .endObject().endObject());
MapperParsingException e = expectThrows(MapperParsingException.class, MapperParsingException e = expectThrows(MapperParsingException.class,
() -> parser.parse("type", new CompressedXContent(badConfigMapping)) () -> parser.parse("type", new CompressedXContent(badConfigMapping))
); );
assertThat(e.getMessage(), containsString("[index_prefix] must not have a [null] value")); assertThat(e.getMessage(), containsString("[index_prefixes] must not have a [null] value"));
} }
{ {
@ -848,13 +848,13 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field") .startObject("properties").startObject("field")
.field("type", "text") .field("type", "text")
.field("index", "false") .field("index", "false")
.startObject("index_prefix").endObject() .startObject("index_prefixes").endObject()
.endObject().endObject() .endObject().endObject()
.endObject().endObject()); .endObject().endObject());
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> parser.parse("type", new CompressedXContent(badConfigMapping)) () -> parser.parse("type", new CompressedXContent(badConfigMapping))
); );
assertThat(e.getMessage(), containsString("Cannot set index_prefix on unindexed field [field]")); assertThat(e.getMessage(), containsString("Cannot set index_prefixes on unindexed field [field]"));
} }
} }
} }

View File

@ -71,6 +71,19 @@ public class TextFieldTypeTests extends FieldTypeTestCase {
tft.setFielddataMinSegmentSize(1000); tft.setFielddataMinSegmentSize(1000);
} }
}); });
addModifier(new Modifier("index_prefixes", true) {
@Override
public void modify(MappedFieldType ft) {
TextFieldMapper.TextFieldType tft = (TextFieldMapper.TextFieldType)ft;
TextFieldMapper.PrefixFieldType pft = tft.getPrefixFieldType();
if (pft == null) {
tft.setPrefixFieldType(new TextFieldMapper.PrefixFieldType(ft.name(), 3, 3));
}
else {
tft.setPrefixFieldType(null);
}
}
});
} }
public void testTermQuery() { public void testTermQuery() {