Context suggester should filter doc values field (#25858)

The context suggester extracts the context field values from the document but it does not filter doc values field coming from Keyword field.
This change filters doc values field when building the context values.

Fixes #25404
This commit is contained in:
Jim Ferenczi 2017-07-24 17:45:01 +02:00 committed by GitHub
parent 2f8f440e80
commit 3a59b6a16c
2 changed files with 55 additions and 3 deletions

View File

@ -19,7 +19,11 @@
package org.elasticsearch.search.suggest.completion.context;
import org.apache.lucene.document.SortedDocValuesField;
import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.SortedSetSortField;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -28,6 +32,7 @@ import org.elasticsearch.common.xcontent.XContentParser.Token;
import org.elasticsearch.index.mapper.KeywordFieldMapper;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.index.mapper.StringFieldType;
import java.io.IOException;
import java.util.ArrayList;
@ -136,10 +141,16 @@ public class CategoryContextMapping extends ContextMapping<CategoryQueryContext>
IndexableField[] fields = document.getFields(fieldName);
values = new HashSet<>(fields.length);
for (IndexableField field : fields) {
if (field.fieldType() instanceof KeywordFieldMapper.KeywordFieldType) {
if (field instanceof SortedDocValuesField ||
field instanceof SortedSetDocValuesField ||
field instanceof StoredField) {
// Ignore doc values and stored fields
} else if (field.fieldType() instanceof KeywordFieldMapper.KeywordFieldType) {
values.add(field.binaryValue().utf8ToString());
} else {
} else if (field.fieldType() instanceof StringFieldType) {
values.add(field.stringValue());
} else {
throw new IllegalArgumentException("Failed to parse context field [" + fieldName + "], only keyword and text fields are accepted");
}
}
}

View File

@ -20,9 +20,14 @@
package org.elasticsearch.search.suggest.completion;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.SortedDocValuesField;
import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.suggest.document.ContextSuggestField;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -32,11 +37,15 @@ import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.mapper.CompletionFieldMapper.CompletionFieldType;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.KeywordFieldMapper;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.mapper.StringFieldType;
import org.elasticsearch.index.mapper.TextFieldMapper;
import org.elasticsearch.search.suggest.completion.context.CategoryContextMapping;
import org.elasticsearch.search.suggest.completion.context.ContextBuilder;
import org.elasticsearch.search.suggest.completion.context.ContextMapping;
@ -46,6 +55,7 @@ import java.util.List;
import java.util.Set;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
public class CategoryContextMappingTests extends ESSingleNodeTestCase {
@ -699,10 +709,41 @@ public class CategoryContextMappingTests extends ESSingleNodeTestCase {
public void testParsingContextFromDocument() throws Exception {
CategoryContextMapping mapping = ContextBuilder.category("cat").field("category").build();
ParseContext.Document document = new ParseContext.Document();
document.add(new StringField("category", "category1", Field.Store.NO));
KeywordFieldMapper.KeywordFieldType keyword = new KeywordFieldMapper.KeywordFieldType();
keyword.setName("category");
document.add(new Field(keyword.name(), new BytesRef("category1"), keyword));
// Ignore doc values
document.add(new SortedSetDocValuesField(keyword.name(), new BytesRef("category1")));
Set<CharSequence> context = mapping.parseContext(document);
assertThat(context.size(), equalTo(1));
assertTrue(context.contains("category1"));
document = new ParseContext.Document();
TextFieldMapper.TextFieldType text = new TextFieldMapper.TextFieldType();
text.setName("category");
document.add(new Field(text.name(), "category1", text));
// Ignore stored field
document.add(new StoredField(text.name(), "category1", text));
context = mapping.parseContext(document);
assertThat(context.size(), equalTo(1));
assertTrue(context.contains("category1"));
document = new ParseContext.Document();
document.add(new SortedSetDocValuesField("category", new BytesRef("category")));
context = mapping.parseContext(document);
assertThat(context.size(), equalTo(0));
document = new ParseContext.Document();
document.add(new SortedDocValuesField("category", new BytesRef("category")));
context = mapping.parseContext(document);
assertThat(context.size(), equalTo(0));
final ParseContext.Document doc = new ParseContext.Document();
doc.add(new IntPoint("category", 36));
IllegalArgumentException exc = expectThrows(IllegalArgumentException.class, () -> mapping.parseContext(doc));
assertThat(exc.getMessage(), containsString("Failed to parse context field [category]"));
}
static void assertContextSuggestFields(IndexableField[] fields, int expected) {