Fail queries on not indexed fields.

While returning no hits on fields that are not mapped may be fine, it is not
for fields that are mapped but not indexed (`index:false`). We should fail the
query in that case rather than returning no hits.
This commit is contained in:
Adrien Grand 2016-04-27 16:07:58 +02:00
parent 1df4efccd5
commit b77893b1d1
11 changed files with 221 additions and 0 deletions

View File

@ -343,6 +343,7 @@ public abstract class MappedFieldType extends FieldType {
* boosted by {@link #boost()}.
* @throws IllegalArgumentException if {@code value} cannot be converted to the expected data type */
public Query termQuery(Object value, @Nullable QueryShardContext context) {
failIfNotIndexed();
TermQuery query = new TermQuery(new Term(name(), indexedValueForSearch(value)));
if (boost == 1f ||
(context != null && context.indexVersionCreated().before(Version.V_5_0_0_alpha1))) {
@ -352,6 +353,7 @@ public abstract class MappedFieldType extends FieldType {
}
public Query termsQuery(List values, @Nullable QueryShardContext context) {
failIfNotIndexed();
BytesRef[] bytesRefs = new BytesRef[values.size()];
for (int i = 0; i < bytesRefs.length; i++) {
bytesRefs[i] = indexedValueForSearch(values.get(i));
@ -360,6 +362,7 @@ public abstract class MappedFieldType extends FieldType {
}
public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper) {
failIfNotIndexed();
return new TermRangeQuery(name(),
lowerTerm == null ? null : indexedValueForSearch(lowerTerm),
upperTerm == null ? null : indexedValueForSearch(upperTerm),
@ -367,11 +370,13 @@ public abstract class MappedFieldType extends FieldType {
}
public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
failIfNotIndexed();
return new FuzzyQuery(new Term(name(), indexedValueForSearch(value)),
fuzziness.asDistance(BytesRefs.toString(value)), prefixLength, maxExpansions, transpositions);
}
public Query prefixQuery(String value, @Nullable MultiTermQuery.RewriteMethod method, @Nullable QueryShardContext context) {
failIfNotIndexed();
PrefixQuery query = new PrefixQuery(new Term(name(), indexedValueForSearch(value)));
if (method != null) {
query.setRewriteMethod(method);
@ -448,6 +453,13 @@ public abstract class MappedFieldType extends FieldType {
}
}
protected final void failIfNotIndexed() {
if (indexOptions() == IndexOptions.NONE && pointDimensionCount() == 0) {
// we throw an IAE rather than an ISE so that it translates to a 4xx code rather than 5xx code on the http layer
throw new IllegalArgumentException("Cannot search on field [" + name() + "] since it is not indexed.");
}
}
public boolean eagerGlobalOrdinals() {
return eagerGlobalOrdinals;
}

View File

@ -319,6 +319,7 @@ public class DateFieldMapper extends FieldMapper implements AllFieldMapper.Inclu
@Override
public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
failIfNotIndexed();
long baseLo = parseToMilliseconds(value, false, null, dateMathParser);
long baseHi = parseToMilliseconds(value, true, null, dateMathParser);
long delta;
@ -333,16 +334,19 @@ public class DateFieldMapper extends FieldMapper implements AllFieldMapper.Inclu
@Override
public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper) {
failIfNotIndexed();
return rangeQuery(lowerTerm, upperTerm, includeLower, includeUpper, null, null);
}
public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper,
@Nullable DateTimeZone timeZone, @Nullable DateMathParser forcedDateParser) {
failIfNotIndexed();
return new LateParsingQuery(lowerTerm, upperTerm, includeLower, includeUpper, timeZone, forcedDateParser);
}
Query innerRangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper,
@Nullable DateTimeZone timeZone, @Nullable DateMathParser forcedDateParser) {
failIfNotIndexed();
DateMathParser parser = forcedDateParser == null
? dateMathParser
: forcedDateParser;

View File

@ -177,6 +177,7 @@ public final class KeywordFieldMapper extends FieldMapper implements AllFieldMap
@Override
public Query regexpQuery(String value, int flags, int maxDeterminizedStates,
@Nullable MultiTermQuery.RewriteMethod method, @Nullable QueryShardContext context) {
failIfNotIndexed();
RegexpQuery query = new RegexpQuery(new Term(name(), indexedValueForSearch(value)), flags, maxDeterminizedStates);
if (method != null) {
query.setRewriteMethod(method);

View File

@ -735,6 +735,7 @@ public class NumberFieldMapper extends FieldMapper implements AllFieldMapper.Inc
@Override
public Query termQuery(Object value, QueryShardContext context) {
failIfNotIndexed();
Query query = type.termQuery(name(), value);
if (boost() != 1f) {
query = new BoostQuery(query, boost());
@ -744,6 +745,7 @@ public class NumberFieldMapper extends FieldMapper implements AllFieldMapper.Inc
@Override
public Query termsQuery(List values, QueryShardContext context) {
failIfNotIndexed();
Query query = type.termsQuery(name(), values);
if (boost() != 1f) {
query = new BoostQuery(query, boost());
@ -753,6 +755,7 @@ public class NumberFieldMapper extends FieldMapper implements AllFieldMapper.Inc
@Override
public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper) {
failIfNotIndexed();
Query query = type.rangeQuery(name(), lowerTerm, upperTerm, includeLower, includeUpper);
if (boost() != 1f) {
query = new BoostQuery(query, boost());
@ -763,6 +766,7 @@ public class NumberFieldMapper extends FieldMapper implements AllFieldMapper.Inc
@Override
public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength,
int maxExpansions, boolean transpositions) {
failIfNotIndexed();
return type.fuzzyQuery(name(), value, fuzziness);
}

View File

@ -304,6 +304,7 @@ public class TextFieldMapper extends FieldMapper implements AllFieldMapper.Inclu
@Override
public Query regexpQuery(String value, int flags, int maxDeterminizedStates,
@Nullable MultiTermQuery.RewriteMethod method, @Nullable QueryShardContext context) {
failIfNotIndexed();
RegexpQuery query = new RegexpQuery(new Term(name(), indexedValueForSearch(value)), flags, maxDeterminizedStates);
if (method != null) {
query.setRewriteMethod(method);

View File

@ -164,6 +164,7 @@ public class IpFieldMapper extends FieldMapper implements AllFieldMapper.Include
@Override
public Query termQuery(Object value, @Nullable QueryShardContext context) {
failIfNotIndexed();
if (value instanceof InetAddress) {
return InetAddressPoint.newExactQuery(name(), (InetAddress) value);
} else {
@ -188,6 +189,7 @@ public class IpFieldMapper extends FieldMapper implements AllFieldMapper.Include
@Override
public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper) {
failIfNotIndexed();
InetAddress lower;
if (lowerTerm == null) {
lower = XInetAddressPoint.MIN_VALUE;
@ -219,6 +221,7 @@ public class IpFieldMapper extends FieldMapper implements AllFieldMapper.Include
@Override
public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
failIfNotIndexed();
InetAddress base = parse(value);
int mask = fuzziness.asInt();
return XInetAddressPoint.newPrefixQuery(name(), base, mask);

View File

@ -18,6 +18,9 @@
*/
package org.elasticsearch.index.mapper.core;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.index.mapper.FieldTypeTestCase;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.junit.Before;
@ -47,4 +50,17 @@ public class BooleanFieldTypeTests extends FieldTypeTestCase {
expectThrows(IllegalArgumentException.class, () -> ft.valueForSearch("true"));
expectThrows(IllegalArgumentException.class, () -> ft.valueForSearch("G"));
}
public void testTermQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new TermQuery(new Term("field", "T")), ft.termQuery("true", null));
assertEquals(new TermQuery(new Term("field", "F")), ft.termQuery("false", null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.termQuery("true", null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
}

View File

@ -23,10 +23,13 @@ import java.util.Locale;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.MultiReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.elasticsearch.common.joda.DateMathParser;
@ -144,4 +147,35 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
long instant = LegacyDateFieldMapper.Defaults.DATE_TIME_FORMATTER.parser().parseDateTime(date).getMillis();
assertEquals(date, ft.valueForSearch(instant));
}
public void testTermQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
String date = "2015-10-12T14:10:55";
long instant = LegacyDateFieldMapper.Defaults.DATE_TIME_FORMATTER.parser().parseDateTime(date).getMillis();
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(LongPoint.newExactQuery("field", instant), ft.termQuery(date, null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.termQuery(date, null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testRangeQuery() throws IOException {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
String date1 = "2015-10-12T14:10:55";
String date2 = "2016-04-28T11:33:52";
long instant1 = LegacyDateFieldMapper.Defaults.DATE_TIME_FORMATTER.parser().parseDateTime(date1).getMillis();
long instant2 = LegacyDateFieldMapper.Defaults.DATE_TIME_FORMATTER.parser().parseDateTime(date2).getMillis();
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(LongPoint.newRangeQuery("field", instant1, instant2),
ft.rangeQuery(date1, date2, true, true).rewrite(new MultiReader()));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.rangeQuery(date1, date2, true, true));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
}

View File

@ -20,12 +20,20 @@ package org.elasticsearch.index.mapper.core;
import com.carrotsearch.randomizedtesting.generators.RandomStrings;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.Term;
import org.apache.lucene.queries.TermsQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.mapper.FieldTypeTestCase;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MappedFieldType.Relation;
import org.elasticsearch.index.mapper.core.KeywordFieldMapper.KeywordFieldType;
import java.io.IOException;
import java.util.Arrays;
public class KeywordFieldTypeTests extends FieldTypeTestCase {
@Override
@ -41,4 +49,55 @@ public class KeywordFieldTypeTests extends FieldTypeTestCase {
RandomStrings.randomAsciiOfLengthBetween(random(), 0, 5),
randomBoolean(), randomBoolean(), null, null));
}
public void testTermQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new TermQuery(new Term("field", "foo")), ft.termQuery("foo", null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.termQuery("bar", null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testTermsQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new TermsQuery(new Term("field", "foo"), new Term("field", "bar")),
ft.termsQuery(Arrays.asList("foo", "bar"), null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.termsQuery(Arrays.asList("foo", "bar"), null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testRegexpQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new RegexpQuery(new Term("field","foo.*")),
ft.regexpQuery("foo.*", 0, 10, null, null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.regexpQuery("foo.*", 0, 10, null, null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testFuzzyQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new FuzzyQuery(new Term("field","foo"), 2, 1, 50, true),
ft.fuzzyQuery("foo", Fuzziness.fromEdits(2), 1, 50, true));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.fuzzyQuery("foo", Fuzziness.fromEdits(2), 1, 50, true));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
}

View File

@ -21,6 +21,8 @@ package org.elasticsearch.index.mapper.core;
import com.carrotsearch.randomizedtesting.generators.RandomPicks;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.IndexOptions;
import org.elasticsearch.index.mapper.FieldTypeTestCase;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MappedFieldType.Relation;
@ -49,4 +51,28 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
assertEquals(Relation.INTERSECTS, ft.isFieldWithinQuery(null, randomDouble(), randomDouble(),
randomBoolean(), randomBoolean(), null, null));
}
public void testTermQuery() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.LONG);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(LongPoint.newExactQuery("field", 42), ft.termQuery("42", null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.termQuery("42", null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testRangeQuery() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.LONG);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(LongPoint.newRangeQuery("field", 1, 3), ft.rangeQuery("1", "3", true, true));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.rangeQuery("1", "3", true, true));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
}

View File

@ -18,6 +18,16 @@
*/
package org.elasticsearch.index.mapper.core;
import java.util.Arrays;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.Term;
import org.apache.lucene.queries.TermsQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.TermQuery;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.mapper.FieldTypeTestCase;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.junit.Before;
@ -59,4 +69,55 @@ public class TextFieldTypeTests extends FieldTypeTestCase {
}
});
}
public void testTermQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new TermQuery(new Term("field", "foo")), ft.termQuery("foo", null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.termQuery("bar", null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testTermsQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new TermsQuery(new Term("field", "foo"), new Term("field", "bar")),
ft.termsQuery(Arrays.asList("foo", "bar"), null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.termsQuery(Arrays.asList("foo", "bar"), null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testRegexpQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new RegexpQuery(new Term("field","foo.*")),
ft.regexpQuery("foo.*", 0, 10, null, null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.regexpQuery("foo.*", 0, 10, null, null));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testFuzzyQuery() {
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(new FuzzyQuery(new Term("field","foo"), 2, 1, 50, true),
ft.fuzzyQuery("foo", Fuzziness.fromEdits(2), 1, 50, true));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.fuzzyQuery("foo", Fuzziness.fromEdits(2), 1, 50, true));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
}