Ensure that _exists queries on keyword fields use norms when they're available. (#33006)
This commit is contained in:
parent
767c69593c
commit
67b5a83a9a
|
@ -28,6 +28,7 @@ import org.apache.lucene.index.IndexOptions;
|
||||||
import org.apache.lucene.index.IndexableField;
|
import org.apache.lucene.index.IndexableField;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.DocValuesFieldExistsQuery;
|
import org.apache.lucene.search.DocValuesFieldExistsQuery;
|
||||||
|
import org.apache.lucene.search.NormsFieldExistsQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
@ -166,7 +167,7 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||||
builder.ignoreAbove(XContentMapValues.nodeIntegerValue(propNode, -1));
|
builder.ignoreAbove(XContentMapValues.nodeIntegerValue(propNode, -1));
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
} else if (propName.equals("norms")) {
|
} else if (propName.equals("norms")) {
|
||||||
builder.omitNorms(XContentMapValues.nodeBooleanValue(propNode, "norms") == false);
|
TypeParsers.parseNorms(builder, name, propNode);
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
} else if (propName.equals("eager_global_ordinals")) {
|
} else if (propName.equals("eager_global_ordinals")) {
|
||||||
builder.eagerGlobalOrdinals(XContentMapValues.nodeBooleanValue(propNode, "eager_global_ordinals"));
|
builder.eagerGlobalOrdinals(XContentMapValues.nodeBooleanValue(propNode, "eager_global_ordinals"));
|
||||||
|
@ -256,8 +257,10 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||||
public Query existsQuery(QueryShardContext context) {
|
public Query existsQuery(QueryShardContext context) {
|
||||||
if (hasDocValues()) {
|
if (hasDocValues()) {
|
||||||
return new DocValuesFieldExistsQuery(name());
|
return new DocValuesFieldExistsQuery(name());
|
||||||
} else {
|
} else if (omitNorms()) {
|
||||||
return new TermQuery(new Term(FieldNamesFieldMapper.NAME, name()));
|
return new TermQuery(new Term(FieldNamesFieldMapper.NAME, name()));
|
||||||
|
} else {
|
||||||
|
return new NormsFieldExistsQuery(name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,17 +369,19 @@ public final class KeywordFieldMapper extends FieldMapper {
|
||||||
|
|
||||||
// convert to utf8 only once before feeding postings/dv/stored fields
|
// convert to utf8 only once before feeding postings/dv/stored fields
|
||||||
final BytesRef binaryValue = new BytesRef(value);
|
final BytesRef binaryValue = new BytesRef(value);
|
||||||
if (fieldType().indexOptions() != IndexOptions.NONE || fieldType().stored()) {
|
if (fieldType().indexOptions() != IndexOptions.NONE || fieldType().stored()) {
|
||||||
Field field = new Field(fieldType().name(), binaryValue, fieldType());
|
Field field = new Field(fieldType().name(), binaryValue, fieldType());
|
||||||
fields.add(field);
|
fields.add(field);
|
||||||
|
|
||||||
|
if (fieldType().hasDocValues() == false && fieldType().omitNorms()) {
|
||||||
|
createFieldNamesField(context, fields);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldType().hasDocValues()) {
|
if (fieldType().hasDocValues()) {
|
||||||
fields.add(new SortedSetDocValuesField(fieldType().name(), binaryValue));
|
fields.add(new SortedSetDocValuesField(fieldType().name(), binaryValue));
|
||||||
} else if (fieldType().stored() || fieldType().indexOptions() != IndexOptions.NONE) {
|
|
||||||
createFieldNamesField(context, fields);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String contentType() {
|
protected String contentType() {
|
||||||
return CONTENT_TYPE;
|
return CONTENT_TYPE;
|
||||||
|
|
|
@ -122,8 +122,7 @@ public class TypeParsers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void parseNorms(FieldMapper.Builder builder, String fieldName, Object propNode,
|
public static void parseNorms(FieldMapper.Builder builder, String fieldName, Object propNode) {
|
||||||
Mapper.TypeParser.ParserContext parserContext) {
|
|
||||||
builder.omitNorms(XContentMapValues.nodeBooleanValue(propNode, fieldName + ".norms") == false);
|
builder.omitNorms(XContentMapValues.nodeBooleanValue(propNode, fieldName + ".norms") == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +139,7 @@ public class TypeParsers {
|
||||||
final String propName = entry.getKey();
|
final String propName = entry.getKey();
|
||||||
final Object propNode = entry.getValue();
|
final Object propNode = entry.getValue();
|
||||||
if ("norms".equals(propName)) {
|
if ("norms".equals(propName)) {
|
||||||
parseNorms(builder, name, propNode, parserContext);
|
parseNorms(builder, name, propNode);
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,11 +321,16 @@ public class KeywordFieldMapperTests extends ESSingleNodeTestCase {
|
||||||
|
|
||||||
public void testEnableNorms() throws IOException {
|
public void testEnableNorms() throws IOException {
|
||||||
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
|
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||||
.startObject("properties").startObject("field").field("type", "keyword").field("norms", true).endObject().endObject()
|
.startObject("properties")
|
||||||
.endObject().endObject());
|
.startObject("field")
|
||||||
|
.field("type", "keyword")
|
||||||
|
.field("doc_values", false)
|
||||||
|
.field("norms", true)
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject().endObject());
|
||||||
|
|
||||||
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
|
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
|
||||||
|
|
||||||
assertEquals(mapping, mapper.mappingSource().toString());
|
assertEquals(mapping, mapper.mappingSource().toString());
|
||||||
|
|
||||||
ParsedDocument doc = mapper.parse(SourceToParse.source("test", "type", "1", BytesReference
|
ParsedDocument doc = mapper.parse(SourceToParse.source("test", "type", "1", BytesReference
|
||||||
|
@ -336,8 +341,11 @@ public class KeywordFieldMapperTests extends ESSingleNodeTestCase {
|
||||||
XContentType.JSON));
|
XContentType.JSON));
|
||||||
|
|
||||||
IndexableField[] fields = doc.rootDoc().getFields("field");
|
IndexableField[] fields = doc.rootDoc().getFields("field");
|
||||||
assertEquals(2, fields.length);
|
assertEquals(1, fields.length);
|
||||||
assertFalse(fields[0].fieldType().omitNorms());
|
assertFalse(fields[0].fieldType().omitNorms());
|
||||||
|
|
||||||
|
IndexableField[] fieldNamesFields = doc.rootDoc().getFields(FieldNamesFieldMapper.NAME);
|
||||||
|
assertEquals(0, fieldNamesFields.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNormalizer() throws IOException {
|
public void testNormalizer() throws IOException {
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package org.elasticsearch.index.mapper;
|
package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
|
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
|
||||||
|
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
import org.apache.lucene.analysis.LowerCaseFilter;
|
import org.apache.lucene.analysis.LowerCaseFilter;
|
||||||
import org.apache.lucene.analysis.TokenFilter;
|
import org.apache.lucene.analysis.TokenFilter;
|
||||||
|
@ -28,9 +27,11 @@ import org.apache.lucene.analysis.Tokenizer;
|
||||||
import org.apache.lucene.analysis.core.WhitespaceTokenizer;
|
import org.apache.lucene.analysis.core.WhitespaceTokenizer;
|
||||||
import org.apache.lucene.index.IndexOptions;
|
import org.apache.lucene.index.IndexOptions;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.TermInSetQuery;
|
import org.apache.lucene.search.DocValuesFieldExistsQuery;
|
||||||
import org.apache.lucene.search.FuzzyQuery;
|
import org.apache.lucene.search.FuzzyQuery;
|
||||||
|
import org.apache.lucene.search.NormsFieldExistsQuery;
|
||||||
import org.apache.lucene.search.RegexpQuery;
|
import org.apache.lucene.search.RegexpQuery;
|
||||||
|
import org.apache.lucene.search.TermInSetQuery;
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.common.lucene.Lucene;
|
import org.elasticsearch.common.lucene.Lucene;
|
||||||
|
@ -132,6 +133,23 @@ public class KeywordFieldTypeTests extends FieldTypeTestCase {
|
||||||
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
|
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testExistsQuery() {
|
||||||
|
MappedFieldType ft = createDefaultFieldType();
|
||||||
|
ft.setName("field");
|
||||||
|
|
||||||
|
ft.setHasDocValues(true);
|
||||||
|
ft.setOmitNorms(true);
|
||||||
|
assertEquals(new DocValuesFieldExistsQuery("field"), ft.existsQuery(null));
|
||||||
|
|
||||||
|
ft.setHasDocValues(false);
|
||||||
|
ft.setOmitNorms(false);
|
||||||
|
assertEquals(new NormsFieldExistsQuery("field"), ft.existsQuery(null));
|
||||||
|
|
||||||
|
ft.setHasDocValues(false);
|
||||||
|
ft.setOmitNorms(true);
|
||||||
|
assertEquals(new TermQuery(new Term(FieldNamesFieldMapper.NAME, "field")), ft.existsQuery(null));
|
||||||
|
}
|
||||||
|
|
||||||
public void testRegexpQuery() {
|
public void testRegexpQuery() {
|
||||||
MappedFieldType ft = createDefaultFieldType();
|
MappedFieldType ft = createDefaultFieldType();
|
||||||
ft.setName("field");
|
ft.setName("field");
|
||||||
|
|
Loading…
Reference in New Issue