diff --git a/core/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java b/core/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java index 163c8578bee..1a63a4dfb27 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java @@ -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; } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java index f93fd7b4c7d..81977fe6caf 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java @@ -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; diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/KeywordFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/KeywordFieldMapper.java index 880d61db6ca..bfcea8c6667 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/KeywordFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/KeywordFieldMapper.java @@ -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); diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/NumberFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/NumberFieldMapper.java index 3449e90b08c..2c3a9a5c83e 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/NumberFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/NumberFieldMapper.java @@ -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); } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/TextFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/TextFieldMapper.java index 711c1eb6cbb..3815293835a 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/TextFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/TextFieldMapper.java @@ -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); diff --git a/core/src/main/java/org/elasticsearch/index/mapper/ip/IpFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/ip/IpFieldMapper.java index 922fd9183ea..6cb3cbe46c8 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/ip/IpFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/ip/IpFieldMapper.java @@ -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); diff --git a/core/src/test/java/org/elasticsearch/index/mapper/core/BooleanFieldTypeTests.java b/core/src/test/java/org/elasticsearch/index/mapper/core/BooleanFieldTypeTests.java index a30addc34ac..821daa6a54c 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/core/BooleanFieldTypeTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/core/BooleanFieldTypeTests.java @@ -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()); + } } diff --git a/core/src/test/java/org/elasticsearch/index/mapper/core/DateFieldTypeTests.java b/core/src/test/java/org/elasticsearch/index/mapper/core/DateFieldTypeTests.java index 41fac7ca270..62bfae40a37 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/core/DateFieldTypeTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/core/DateFieldTypeTests.java @@ -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()); + } } diff --git a/core/src/test/java/org/elasticsearch/index/mapper/core/KeywordFieldTypeTests.java b/core/src/test/java/org/elasticsearch/index/mapper/core/KeywordFieldTypeTests.java index 0d8ab6b8049..77360c12fda 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/core/KeywordFieldTypeTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/core/KeywordFieldTypeTests.java @@ -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()); + } } diff --git a/core/src/test/java/org/elasticsearch/index/mapper/core/NumberFieldTypeTests.java b/core/src/test/java/org/elasticsearch/index/mapper/core/NumberFieldTypeTests.java index 4bb73d857ae..25591591e42 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/core/NumberFieldTypeTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/core/NumberFieldTypeTests.java @@ -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()); + } } diff --git a/core/src/test/java/org/elasticsearch/index/mapper/core/TextFieldTypeTests.java b/core/src/test/java/org/elasticsearch/index/mapper/core/TextFieldTypeTests.java index ea65bfc3421..cde814508c5 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/core/TextFieldTypeTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/core/TextFieldTypeTests.java @@ -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()); + } }