Skip to content

Commit 261c8af

Browse files
committed
Distinguish between simple matches with and without the terms index (#63945)
We currently use TextSearchInfo to let query parsers know when a field will support match queries. Some field types (numeric, constant, range) can produce simple match queries that don't use the terms index, and it is useful to distinguish between these fields on the one hand and keyword/text-type fields on the other. In particular, the SignificantTextAggregation only works on fields that have indexed terms, but there is currently no efficient way to see this at search time and so the factory falls back on checking to see if an index analyzer has been defined, with the result that some nonsensical field types are permitted. This commit adds a new static TextSearchInfo implementation called SIMPLE_MATCH_WITHOUT_TERMS that can be returned by field types with no corresponding terms index. It changes significant text to check for this rather than for the presence of an index analyzer. This is a breaking change, in that the significant text agg will now throw an error up-front if you try and apply it to a numeric field, whereas before you would get an empty result.
1 parent c28206f commit 261c8af

File tree

15 files changed

+44
-33
lines changed

15 files changed

+44
-33
lines changed

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public static final class ScaledFloatFieldType extends SimpleMappedFieldType {
138138

139139
public ScaledFloatFieldType(String name, boolean indexed, boolean stored, boolean hasDocValues,
140140
Map<String, String> meta, double scalingFactor, Double nullValue) {
141-
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
141+
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
142142
this.scalingFactor = scalingFactor;
143143
this.nullValue = nullValue;
144144
}

server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/bucket/SignificantTermsSignificanceScoreIT.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -541,11 +541,11 @@ public void testReduceFromSeveralShards() throws IOException, ExecutionException
541541
* Ensure requests using nondeterministic scripts do not get cached.
542542
*/
543543
public void testScriptCaching() throws Exception {
544-
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
544+
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "s", "type=long", "t", "type=text")
545545
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
546546
.get());
547-
indexRandom(true, client().prepareIndex("cache_test_idx", "type", "1").setSource("s", 1),
548-
client().prepareIndex("cache_test_idx", "type", "2").setSource("s", 2));
547+
indexRandom(true, client().prepareIndex("cache_test_idx", "type", "1").setSource("s", 1, "t", "foo"),
548+
client().prepareIndex("cache_test_idx", "type", "2").setSource("s", 2, "t", "bar"));
549549

550550
// Make sure we are starting with a clear cache
551551
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
@@ -561,7 +561,7 @@ public void testScriptCaching() throws Exception {
561561
SearchResponse r;
562562
if (useSigText) {
563563
r = client().prepareSearch("cache_test_idx").setSize(0)
564-
.addAggregation(significantText("foo", "s").significanceHeuristic(scriptHeuristic)).get();
564+
.addAggregation(significantText("foo", "t").significanceHeuristic(scriptHeuristic)).get();
565565
} else {
566566
r = client().prepareSearch("cache_test_idx").setSize(0)
567567
.addAggregation(significantTerms("foo").field("s").significanceHeuristic(scriptHeuristic)).get();
@@ -578,7 +578,7 @@ public void testScriptCaching() throws Exception {
578578
useSigText = randomBoolean();
579579
if (useSigText) {
580580
r = client().prepareSearch("cache_test_idx").setSize(0)
581-
.addAggregation(significantText("foo", "s").significanceHeuristic(scriptHeuristic)).get();
581+
.addAggregation(significantText("foo", "t").significanceHeuristic(scriptHeuristic)).get();
582582
} else {
583583
r = client().prepareSearch("cache_test_idx").setSize(0)
584584
.addAggregation(significantTerms("foo").field("s").significanceHeuristic(scriptHeuristic)).get();
@@ -592,7 +592,7 @@ public void testScriptCaching() throws Exception {
592592

593593
// Ensure that non-scripted requests are cached as normal
594594
if (useSigText) {
595-
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(significantText("foo", "s")).get();
595+
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(significantText("foo", "t")).get();
596596
} else {
597597
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(significantTerms("foo").field("s")).get();
598598
}

server/src/main/java/org/elasticsearch/index/mapper/ConstantFieldType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
public abstract class ConstantFieldType extends MappedFieldType {
4343

4444
public ConstantFieldType(String name, Map<String, String> meta) {
45-
super(name, true, false, true, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
45+
super(name, true, false, true, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
4646
}
4747

4848
@Override

server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ public static final class DateFieldType extends MappedFieldType {
278278
public DateFieldType(String name, boolean isSearchable, boolean isStored, boolean hasDocValues,
279279
DateFormatter dateTimeFormatter, Resolution resolution, String nullValue,
280280
Map<String, String> meta) {
281-
super(name, isSearchable, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
281+
super(name, isSearchable, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
282282
this.dateTimeFormatter = dateTimeFormatter;
283283
this.dateMathParser = dateTimeFormatter.toDateMathParser();
284284
this.resolution = resolution;

server/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public static final class IpFieldType extends SimpleMappedFieldType {
129129

130130
public IpFieldType(String name, boolean indexed, boolean stored, boolean hasDocValues,
131131
InetAddress nullValue, Map<String, String> meta) {
132-
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
132+
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
133133
this.nullValue = nullValue;
134134
}
135135

server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,9 +417,11 @@ public Map<String, String> meta() {
417417
* Returns information on how any text in this field is indexed
418418
*
419419
* Fields that do not support any text-based queries should return
420-
* {@link TextSearchInfo#NONE}. Some fields (eg numeric) may support
420+
* {@link TextSearchInfo#NONE}. Some fields (eg keyword) may support
421421
* only simple match queries, and can return
422-
* {@link TextSearchInfo#SIMPLE_MATCH_ONLY}
422+
* {@link TextSearchInfo#SIMPLE_MATCH_ONLY}; other fields may support
423+
* simple match queries without using the terms index, and can return
424+
* {@link TextSearchInfo#SIMPLE_MATCH_WITHOUT_TERMS}
423425
*/
424426
public TextSearchInfo getTextSearchInfo() {
425427
return textSearchInfo;

server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ public static class NumberFieldType extends SimpleMappedFieldType {
897897

898898
public NumberFieldType(String name, NumberType type, boolean isSearchable, boolean isStored,
899899
boolean hasDocValues, boolean coerce, Number nullValue, Map<String, String> meta) {
900-
super(name, isSearchable, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
900+
super(name, isSearchable, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
901901
this.type = Objects.requireNonNull(type);
902902
this.coerce = coerce;
903903
this.nullValue = nullValue;

server/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ public static final class RangeFieldType extends MappedFieldType {
163163

164164
public RangeFieldType(String name, RangeType type, boolean indexed, boolean stored,
165165
boolean hasDocValues, boolean coerce, Map<String, String> meta) {
166-
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
166+
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
167167
assert type != RangeType.DATE;
168168
this.rangeType = Objects.requireNonNull(type);
169169
dateTimeFormatter = null;
@@ -178,7 +178,7 @@ public RangeFieldType(String name, RangeType type) {
178178

179179
public RangeFieldType(String name, boolean indexed, boolean stored, boolean hasDocValues, DateFormatter formatter,
180180
boolean coerce, Map<String, String> meta) {
181-
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
181+
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
182182
this.rangeType = RangeType.DATE;
183183
this.dateTimeFormatter = Objects.requireNonNull(formatter);
184184
this.dateMathParser = dateTimeFormatter.toDateMathParser();

server/src/main/java/org/elasticsearch/index/mapper/SeqNoFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ static final class SeqNoFieldType extends SimpleMappedFieldType {
9797
private static final SeqNoFieldType INSTANCE = new SeqNoFieldType();
9898

9999
private SeqNoFieldType() {
100-
super(NAME, true, false, true, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
100+
super(NAME, true, false, true, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, Collections.emptyMap());
101101
}
102102

103103
@Override

server/src/main/java/org/elasticsearch/index/mapper/TextSearchInfo.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ public class TextSearchInfo {
5454
public static final TextSearchInfo WHITESPACE_MATCH_ONLY
5555
= new TextSearchInfo(SIMPLE_MATCH_ONLY_FIELD_TYPE, null, Lucene.WHITESPACE_ANALYZER, Lucene.WHITESPACE_ANALYZER);
5656

57+
/**
58+
* Defines indexing information for fields that support simple match text queries
59+
* without using the terms index
60+
*/
61+
public static final TextSearchInfo SIMPLE_MATCH_WITHOUT_TERMS
62+
= new TextSearchInfo(SIMPLE_MATCH_ONLY_FIELD_TYPE, null, Lucene.KEYWORD_ANALYZER, Lucene.KEYWORD_ANALYZER);
63+
5764
private static final NamedAnalyzer FORBIDDEN_ANALYZER = new NamedAnalyzer("", AnalyzerScope.GLOBAL,
5865
new Analyzer() {
5966
@Override

0 commit comments

Comments
 (0)