CompletionFieldMapper should use index name instead of full name

Fixes #3669
This commit is contained in:
Igor Motov 2013-09-11 14:40:07 -04:00
parent 507b6a6e8c
commit 714aaa40ea
3 changed files with 53 additions and 46 deletions

View File

@ -112,7 +112,7 @@ public class CompletionFieldMapper extends AbstractFieldMapper<String> {
this.preservePositionIncrements = preservePositionIncrements; this.preservePositionIncrements = preservePositionIncrements;
return this; return this;
} }
public Builder maxInputLength(int maxInputLength) { public Builder maxInputLength(int maxInputLength) {
if (maxInputLength <= 0) { if (maxInputLength <= 0) {
throw new ElasticSearchIllegalArgumentException(Fields.MAX_INPUT_LENGTH + " must be > 0 but was [" + maxInputLength + "]"); throw new ElasticSearchIllegalArgumentException(Fields.MAX_INPUT_LENGTH + " must be > 0 but was [" + maxInputLength + "]");
@ -175,7 +175,7 @@ public class CompletionFieldMapper extends AbstractFieldMapper<String> {
private NamedAnalyzer getNamedAnalyzer(ParserContext parserContext, String name) { private NamedAnalyzer getNamedAnalyzer(ParserContext parserContext, String name) {
NamedAnalyzer analyzer = parserContext.analysisService().analyzer(name); NamedAnalyzer analyzer = parserContext.analysisService().analyzer(name);
if (analyzer == null) { if (analyzer == null) {
throw new ElasticSearchIllegalArgumentException("Can't find default or mapped analyzer with name [" + name +"]"); throw new ElasticSearchIllegalArgumentException("Can't find default or mapped analyzer with name [" + name + "]");
} }
return analyzer; return analyzer;
} }
@ -280,21 +280,21 @@ public class CompletionFieldMapper extends AbstractFieldMapper<String> {
final String originalInput = input; final String originalInput = input;
if (input.length() > maxInputLength) { if (input.length() > maxInputLength) {
final int len = correctSubStringLen(input, Math.min(maxInputLength, input.length())); final int len = correctSubStringLen(input, Math.min(maxInputLength, input.length()));
input = input.substring(0, len); input = input.substring(0, len);
} }
for (int i = 0; i < input.length(); i++) { for (int i = 0; i < input.length(); i++) {
if (isReservedChar(input.charAt(i))) { if (isReservedChar(input.charAt(i))) {
throw new ElasticSearchIllegalArgumentException("Illegal input [" + originalInput + "] UTF-16 codepoint [0x" throw new ElasticSearchIllegalArgumentException("Illegal input [" + originalInput + "] UTF-16 codepoint [0x"
+ Integer.toHexString((int) input.charAt(i)).toUpperCase(Locale.ROOT) + Integer.toHexString((int) input.charAt(i)).toUpperCase(Locale.ROOT)
+ "] at position " + i + " is a reserved character"); + "] at position " + i + " is a reserved character");
} }
} }
return new SuggestField(names().fullName(), input, this.fieldType, payload, analyzingSuggestLookupProvider); return new SuggestField(names.indexName(), input, this.fieldType, payload, analyzingSuggestLookupProvider);
} }
public static int correctSubStringLen(String input, int len) { public static int correctSubStringLen(String input, int len) {
if (Character.isHighSurrogate(input.charAt(len-1))) { if (Character.isHighSurrogate(input.charAt(len - 1))) {
assert input.length() >= len+1 && Character.isLowSurrogate(input.charAt(len)); assert input.length() >= len + 1 && Character.isLowSurrogate(input.charAt(len));
return len + 1; return len + 1;
} }
return len; return len;
@ -308,7 +308,7 @@ public class CompletionFieldMapper extends AbstractFieldMapper<String> {
private static final class SuggestField extends Field { private static final class SuggestField extends Field {
private final BytesRef payload; private final BytesRef payload;
private final CompletionTokenStream.ToFiniteStrings toFiniteStrings; private final CompletionTokenStream.ToFiniteStrings toFiniteStrings;
public SuggestField(String name, Reader value, FieldType type, BytesRef payload, CompletionTokenStream.ToFiniteStrings toFiniteStrings) { public SuggestField(String name, Reader value, FieldType type, BytesRef payload, CompletionTokenStream.ToFiniteStrings toFiniteStrings) {
super(name, value, type); super(name, value, type);
this.payload = payload; this.payload = payload;
@ -342,7 +342,7 @@ public class CompletionFieldMapper extends AbstractFieldMapper<String> {
builder.field(Fields.PAYLOADS, this.payloads); builder.field(Fields.PAYLOADS, this.payloads);
builder.field(Fields.PRESERVE_SEPARATORS, this.preserveSeparators); builder.field(Fields.PRESERVE_SEPARATORS, this.preserveSeparators);
builder.field(Fields.PRESERVE_POSITION_INCREMENTS, this.preservePositionIncrements); builder.field(Fields.PRESERVE_POSITION_INCREMENTS, this.preservePositionIncrements);
builder.field(Fields.MAX_INPUT_LENGTH, this.maxInputLength); builder.field(Fields.MAX_INPUT_LENGTH, this.maxInputLength);
return builder.endObject(); return builder.endObject();
} }
@ -379,7 +379,7 @@ public class CompletionFieldMapper extends AbstractFieldMapper<String> {
public boolean isStoringPayloads() { public boolean isStoringPayloads() {
return payloads; return payloads;
} }
@Override @Override
public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappingException { public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappingException {
super.merge(mergeWith, mergeContext); super.merge(mergeWith, mergeContext);
@ -387,19 +387,19 @@ public class CompletionFieldMapper extends AbstractFieldMapper<String> {
if (payloads != fieldMergeWith.payloads) { if (payloads != fieldMergeWith.payloads) {
mergeContext.addConflict("mapper [" + names.fullName() + "] has different payload values"); mergeContext.addConflict("mapper [" + names.fullName() + "] has different payload values");
} }
if (preservePositionIncrements != fieldMergeWith.preservePositionIncrements) { if (preservePositionIncrements != fieldMergeWith.preservePositionIncrements) {
mergeContext.addConflict("mapper [" + names.fullName() + "] has different 'preserve_position_increments' values"); mergeContext.addConflict("mapper [" + names.fullName() + "] has different 'preserve_position_increments' values");
} }
if (preserveSeparators != fieldMergeWith.preserveSeparators) { if (preserveSeparators != fieldMergeWith.preserveSeparators) {
mergeContext.addConflict("mapper [" + names.fullName() + "] has different 'preserve_separators' values"); mergeContext.addConflict("mapper [" + names.fullName() + "] has different 'preserve_separators' values");
} }
if (!mergeContext.mergeFlags().simulate()) { if (!mergeContext.mergeFlags().simulate()) {
this.maxInputLength = fieldMergeWith.maxInputLength; this.maxInputLength = fieldMergeWith.maxInputLength;
} }
} }
private static final char END_LABEL = 0x00; private static final char END_LABEL = 0x00;
// this should be package private but our tests don't allow it. // this should be package private but our tests don't allow it.
public static boolean isReservedChar(char character) { public static boolean isReservedChar(char character) {
/* we also use 0xFF as a SEP_LABEL in the suggester but it's not valid UTF-8 so no need to check. /* we also use 0xFF as a SEP_LABEL in the suggester but it's not valid UTF-8 so no need to check.

View File

@ -31,8 +31,11 @@ import org.apache.lucene.store.IndexOutput;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.IntsRef; import org.apache.lucene.util.IntsRef;
import org.apache.lucene.util.fst.*; import org.apache.lucene.util.fst.ByteSequenceOutputs;
import org.apache.lucene.util.fst.FST;
import org.apache.lucene.util.fst.PairOutputs;
import org.apache.lucene.util.fst.PairOutputs.Pair; import org.apache.lucene.util.fst.PairOutputs.Pair;
import org.apache.lucene.util.fst.PositiveIntOutputs;
import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.index.mapper.FieldMapper; import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.search.suggest.completion.Completion090PostingsFormat.CompletionLookupProvider; import org.elasticsearch.search.suggest.completion.Completion090PostingsFormat.CompletionLookupProvider;
@ -50,10 +53,10 @@ public class AnalyzingCompletionLookupProvider extends CompletionLookupProvider
private static final int MAX_SURFACE_FORMS_PER_ANALYZED_FORM = 256; private static final int MAX_SURFACE_FORMS_PER_ANALYZED_FORM = 256;
private static final int MAX_GRAPH_EXPANSIONS = -1; private static final int MAX_GRAPH_EXPANSIONS = -1;
public static final String CODEC_NAME = "analyzing"; public static final String CODEC_NAME = "analyzing";
public static final int CODEC_VERSION = 1; public static final int CODEC_VERSION = 1;
private boolean preserveSep; private boolean preserveSep;
private boolean preservePositionIncrements; private boolean preservePositionIncrements;
private int maxSurfaceFormsPerAnalyzedForm; private int maxSurfaceFormsPerAnalyzedForm;
@ -84,6 +87,7 @@ public class AnalyzingCompletionLookupProvider extends CompletionLookupProvider
CodecUtil.writeHeader(output, CODEC_NAME, CODEC_VERSION); CodecUtil.writeHeader(output, CODEC_NAME, CODEC_VERSION);
return new FieldsConsumer() { return new FieldsConsumer() {
private Map<FieldInfo, Long> fieldOffsets = new HashMap<FieldInfo, Long>(); private Map<FieldInfo, Long> fieldOffsets = new HashMap<FieldInfo, Long>();
@Override @Override
public void close() throws IOException { public void close() throws IOException {
try { /* try { /*
@ -179,7 +183,7 @@ public class AnalyzingCompletionLookupProvider extends CompletionLookupProvider
analyzingSuggestLookupProvider.parsePayload(payload, spare); analyzingSuggestLookupProvider.parsePayload(payload, spare);
builder.addSurface(spare.surfaceForm, spare.payload, spare.weight); builder.addSurface(spare.surfaceForm, spare.payload, spare.weight);
// multi fields have the same surface form so we sum up here // multi fields have the same surface form so we sum up here
maxAnalyzedPathsForOneInput = Math.max(maxAnalyzedPathsForOneInput, position+1); maxAnalyzedPathsForOneInput = Math.max(maxAnalyzedPathsForOneInput, position + 1);
} }
@Override @Override
@ -189,7 +193,9 @@ public class AnalyzingCompletionLookupProvider extends CompletionLookupProvider
public int getMaxAnalyzedPathsForOneInput() { public int getMaxAnalyzedPathsForOneInput() {
return maxAnalyzedPathsForOneInput; return maxAnalyzedPathsForOneInput;
} }
}; }
;
@Override @Override
@ -225,11 +231,11 @@ public class AnalyzingCompletionLookupProvider extends CompletionLookupProvider
return new LookupFactory() { return new LookupFactory() {
@Override @Override
public Lookup getLookup(FieldMapper<?> mapper, CompletionSuggestionContext suggestionContext) { public Lookup getLookup(FieldMapper<?> mapper, CompletionSuggestionContext suggestionContext) {
AnalyzingSuggestHolder analyzingSuggestHolder = lookupMap.get(mapper.names().fullName()); AnalyzingSuggestHolder analyzingSuggestHolder = lookupMap.get(mapper.names().indexName());
if (analyzingSuggestHolder == null) { if (analyzingSuggestHolder == null) {
return null; return null;
} }
int flags = analyzingSuggestHolder.preserveSep? XAnalyzingSuggester.PRESERVE_SEP : 0; int flags = analyzingSuggestHolder.preserveSep ? XAnalyzingSuggester.PRESERVE_SEP : 0;
XAnalyzingSuggester suggester; XAnalyzingSuggester suggester;
if (suggestionContext.isFuzzy()) { if (suggestionContext.isFuzzy()) {
@ -251,14 +257,14 @@ public class AnalyzingCompletionLookupProvider extends CompletionLookupProvider
} }
@Override @Override
public CompletionStats stats(String ... fields) { public CompletionStats stats(String... fields) {
long sizeInBytes = 0; long sizeInBytes = 0;
TObjectLongHashMap<String> completionFields = null; TObjectLongHashMap<String> completionFields = null;
if (fields != null && fields.length > 0) { if (fields != null && fields.length > 0) {
completionFields = new TObjectLongHashMap<String>(fields.length); completionFields = new TObjectLongHashMap<String>(fields.length);
} }
for (Map.Entry<String, AnalyzingSuggestHolder> entry: lookupMap.entrySet()) { for (Map.Entry<String, AnalyzingSuggestHolder> entry : lookupMap.entrySet()) {
sizeInBytes += entry.getValue().fst.sizeInBytes(); sizeInBytes += entry.getValue().fst.sizeInBytes();
if (fields == null || fields.length == 0) { if (fields == null || fields.length == 0) {
continue; continue;

View File

@ -20,6 +20,7 @@ package org.elasticsearch.search.suggest;
import com.carrotsearch.randomizedtesting.generators.RandomStrings; import com.carrotsearch.randomizedtesting.generators.RandomStrings;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.elasticsearch.AbstractSharedClusterTest;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus; import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse; import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse;
@ -39,7 +40,6 @@ import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder; import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionFuzzyBuilder; import org.elasticsearch.search.suggest.completion.CompletionSuggestionFuzzyBuilder;
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions; import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import org.elasticsearch.AbstractSharedClusterTest;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;
@ -370,6 +370,7 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
.startObject(TYPE).startObject("properties") .startObject(TYPE).startObject("properties")
.startObject(FIELD) .startObject(FIELD)
.field("type", "multi_field") .field("type", "multi_field")
.field("path", "just_name")
.startObject("fields") .startObject("fields")
.startObject(FIELD).field("type", "string").endObject() .startObject(FIELD).field("type", "string").endObject()
.startObject("suggest").field("type", "completion").field("index_analyzer", "simple").field("search_analyzer", "simple").endObject() .startObject("suggest").field("type", "completion").field("index_analyzer", "simple").field("search_analyzer", "simple").endObject()
@ -381,7 +382,7 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
assertThat(putMappingResponse.isAcknowledged(), is(true)); assertThat(putMappingResponse.isAcknowledged(), is(true));
SuggestResponse suggestResponse = client().prepareSuggest(INDEX).addSuggestion( SuggestResponse suggestResponse = client().prepareSuggest(INDEX).addSuggestion(
new CompletionSuggestionBuilder("suggs").field(FIELD + ".suggest").text("f").size(10) new CompletionSuggestionBuilder("suggs").field("suggest").text("f").size(10)
).execute().actionGet(); ).execute().actionGet();
assertSuggestions(suggestResponse, "suggs"); assertSuggestions(suggestResponse, "suggs");
@ -389,7 +390,7 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
waitForRelocation(ClusterHealthStatus.GREEN); waitForRelocation(ClusterHealthStatus.GREEN);
SuggestResponse afterReindexingResponse = client().prepareSuggest(INDEX).addSuggestion( SuggestResponse afterReindexingResponse = client().prepareSuggest(INDEX).addSuggestion(
new CompletionSuggestionBuilder("suggs").field(FIELD + ".suggest").text("f").size(10) new CompletionSuggestionBuilder("suggs").field("suggest").text("f").size(10)
).execute().actionGet(); ).execute().actionGet();
assertSuggestions(afterReindexingResponse, "suggs", "Foo Fighters"); assertSuggestions(afterReindexingResponse, "suggs", "Foo Fighters");
} }
@ -684,7 +685,7 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
client().admin().indices().prepareOptimize(INDEX).execute().actionGet(); client().admin().indices().prepareOptimize(INDEX).execute().actionGet();
} }
} }
@Test // see #3555 @Test // see #3555
public void testPrunedSegments() throws IOException { public void testPrunedSegments() throws IOException {
createIndexAndMappingAndSettings(settingsBuilder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_NUMBER_OF_REPLICAS, 0), "standard", "standard", false, false, false); createIndexAndMappingAndSettings(settingsBuilder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_NUMBER_OF_REPLICAS, 0), "standard", "standard", false, false, false);
@ -696,7 +697,7 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
).get(); ).get();
client().prepareIndex(INDEX, TYPE, "2").setSource(jsonBuilder() client().prepareIndex(INDEX, TYPE, "2").setSource(jsonBuilder()
.startObject() .startObject()
.field("somefield", "somevalue") .field("somefield", "somevalue")
.endObject() .endObject()
).get(); // we have 2 docs in a segment... ).get(); // we have 2 docs in a segment...
OptimizeResponse actionGet = client().admin().indices().prepareOptimize().setFlush(true).setMaxNumSegments(1).setRefresh(true).execute().actionGet(); OptimizeResponse actionGet = client().admin().indices().prepareOptimize().setFlush(true).setMaxNumSegments(1).setRefresh(true).execute().actionGet();
@ -704,7 +705,7 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
// update the first one and then merge.. the target segment will have no value in FIELD // update the first one and then merge.. the target segment will have no value in FIELD
client().prepareIndex(INDEX, TYPE, "1").setSource(jsonBuilder() client().prepareIndex(INDEX, TYPE, "1").setSource(jsonBuilder()
.startObject() .startObject()
.field("somefield", "somevalue") .field("somefield", "somevalue")
.endObject() .endObject()
).get(); ).get();
actionGet = client().admin().indices().prepareOptimize().setFlush(true).setMaxNumSegments(1).setRefresh(true).execute().actionGet(); actionGet = client().admin().indices().prepareOptimize().setFlush(true).setMaxNumSegments(1).setRefresh(true).execute().actionGet();
@ -712,27 +713,27 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
assertSuggestions("b"); assertSuggestions("b");
assertThat(2l, equalTo(client().prepareCount(INDEX).get().getCount())); assertThat(2l, equalTo(client().prepareCount(INDEX).get().getCount()));
for(IndexShardSegments seg : client().admin().indices().prepareSegments().get().getIndices().get(INDEX)) { for (IndexShardSegments seg : client().admin().indices().prepareSegments().get().getIndices().get(INDEX)) {
ShardSegments[] shards = seg.getShards(); ShardSegments[] shards = seg.getShards();
for (ShardSegments shardSegments : shards) { for (ShardSegments shardSegments : shards) {
assertThat(1, equalTo(shardSegments.getSegments().size())); assertThat(1, equalTo(shardSegments.getSegments().size()));
} }
} }
} }
@Test @Test
public void testMaxFieldLength() throws IOException { public void testMaxFieldLength() throws IOException {
client().admin().indices().prepareCreate(INDEX).get(); client().admin().indices().prepareCreate(INDEX).get();
int iters = atLeast(10); int iters = atLeast(10);
for (int i = 0; i < iters; i++) { for (int i = 0; i < iters; i++) {
int len = between(3, 50); int len = between(3, 50);
String str = replaceReservedChars(randomRealisticUnicodeOfCodepointLengthBetween(len+1, atLeast(len + 2)), (char)0x01); String str = replaceReservedChars(randomRealisticUnicodeOfCodepointLengthBetween(len + 1, atLeast(len + 2)), (char) 0x01);
ElasticsearchAssertions.assertAcked(client().admin().indices().preparePutMapping(INDEX).setType(TYPE).setSource(jsonBuilder().startObject() ElasticsearchAssertions.assertAcked(client().admin().indices().preparePutMapping(INDEX).setType(TYPE).setSource(jsonBuilder().startObject()
.startObject(TYPE).startObject("properties") .startObject(TYPE).startObject("properties")
.startObject(FIELD) .startObject(FIELD)
.field("type", "completion") .field("type", "completion")
.field("max_input_len", len) .field("max_input_len", len)
// upgrade mapping each time // upgrade mapping each time
.field("analyzer", "keyword") .field("analyzer", "keyword")
.endObject() .endObject()
.endObject().endObject() .endObject().endObject()
@ -748,14 +749,14 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
assertSuggestions(str.substring(0, prefixLen), "foobar"); assertSuggestions(str.substring(0, prefixLen), "foobar");
if (len + 1 < str.length()) { if (len + 1 < str.length()) {
assertSuggestions(str.substring(0, CompletionFieldMapper.correctSubStringLen(str, assertSuggestions(str.substring(0, CompletionFieldMapper.correctSubStringLen(str,
len + (Character.isHighSurrogate(str.charAt(len-1)) ? 2 : 1)))); len + (Character.isHighSurrogate(str.charAt(len - 1)) ? 2 : 1))));
} }
} }
} }
@Test @Test
// see #3596 // see #3596
public void testVeryLongInput() throws IOException { public void testVeryLongInput() throws IOException {
client().admin().indices().prepareCreate(INDEX).get(); client().admin().indices().prepareCreate(INDEX).get();
ElasticsearchAssertions.assertAcked(client().admin().indices().preparePutMapping(INDEX).setType(TYPE).setSource(jsonBuilder().startObject() ElasticsearchAssertions.assertAcked(client().admin().indices().preparePutMapping(INDEX).setType(TYPE).setSource(jsonBuilder().startObject()
.startObject(TYPE).startObject("properties") .startObject(TYPE).startObject("properties")
@ -766,19 +767,19 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
.endObject())); .endObject()));
ensureYellow(); ensureYellow();
// can cause stack overflow without the default max_input_len // can cause stack overflow without the default max_input_len
String longString = replaceReservedChars(randomRealisticUnicodeOfLength(atLeast(5000)), (char)0x01); String longString = replaceReservedChars(randomRealisticUnicodeOfLength(atLeast(5000)), (char) 0x01);
client().prepareIndex(INDEX, TYPE, "1").setSource(jsonBuilder() client().prepareIndex(INDEX, TYPE, "1").setSource(jsonBuilder()
.startObject().startObject(FIELD) .startObject().startObject(FIELD)
.startArray("input").value(longString).endArray() .startArray("input").value(longString).endArray()
.field("output", "foobar") .field("output", "foobar")
.endObject().endObject() .endObject().endObject()
).setRefresh(true).get(); ).setRefresh(true).get();
} }
// see #3648 // see #3648
@Test(expected = MapperParsingException.class) @Test(expected = MapperParsingException.class)
public void testReservedChars() throws IOException { public void testReservedChars() throws IOException {
client().admin().indices().prepareCreate(INDEX).get(); client().admin().indices().prepareCreate(INDEX).get();
ElasticsearchAssertions.assertAcked(client().admin().indices().preparePutMapping(INDEX).setType(TYPE).setSource(jsonBuilder().startObject() ElasticsearchAssertions.assertAcked(client().admin().indices().preparePutMapping(INDEX).setType(TYPE).setSource(jsonBuilder().startObject()
.startObject(TYPE).startObject("properties") .startObject(TYPE).startObject("properties")
@ -789,16 +790,16 @@ public class CompletionSuggestSearchTests extends AbstractSharedClusterTest {
.endObject())); .endObject()));
ensureYellow(); ensureYellow();
// can cause stack overflow without the default max_input_len // can cause stack overflow without the default max_input_len
String string = "foo" + (char)0x00 + "bar"; String string = "foo" + (char) 0x00 + "bar";
client().prepareIndex(INDEX, TYPE, "1").setSource(jsonBuilder() client().prepareIndex(INDEX, TYPE, "1").setSource(jsonBuilder()
.startObject().startObject(FIELD) .startObject().startObject(FIELD)
.startArray("input").value(string).endArray() .startArray("input").value(string).endArray()
.field("output", "foobar") .field("output", "foobar")
.endObject().endObject() .endObject().endObject()
).setRefresh(true).get(); ).setRefresh(true).get();
} }
private static String replaceReservedChars(String input, char replacement) { private static String replaceReservedChars(String input, char replacement) {
char[] charArray = input.toCharArray(); char[] charArray = input.toCharArray();
for (int i = 0; i < charArray.length; i++) { for (int i = 0; i < charArray.length; i++) {