Skip to content

Commit 4191c72

Browse files
authored
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 266f52d commit 4191c72

File tree

15 files changed

+40
-30
lines changed

15 files changed

+40
-30
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
@@ -136,7 +136,7 @@ public static final class ScaledFloatFieldType extends SimpleMappedFieldType {
136136

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

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
@@ -540,11 +540,11 @@ public void testReduceFromSeveralShards() throws IOException, ExecutionException
540540
* Ensure requests using nondeterministic scripts do not get cached.
541541
*/
542542
public void testScriptCaching() throws Exception {
543-
assertAcked(prepareCreate("cache_test_idx").setMapping("d", "type=long")
543+
assertAcked(prepareCreate("cache_test_idx").setMapping("s", "type=long", "t", "type=text")
544544
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
545545
.get());
546-
indexRandom(true, client().prepareIndex("cache_test_idx").setId("1").setSource("s", 1),
547-
client().prepareIndex("cache_test_idx").setId("2").setSource("s", 2));
546+
indexRandom(true, client().prepareIndex("cache_test_idx").setId("1").setSource("s", 1, "t", "foo"),
547+
client().prepareIndex("cache_test_idx").setId("2").setSource("s", 2, "t", "bar"));
548548

549549
// Make sure we are starting with a clear cache
550550
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
@@ -560,7 +560,7 @@ public void testScriptCaching() throws Exception {
560560
SearchResponse r;
561561
if (useSigText) {
562562
r = client().prepareSearch("cache_test_idx").setSize(0)
563-
.addAggregation(significantText("foo", "s").significanceHeuristic(scriptHeuristic)).get();
563+
.addAggregation(significantText("foo", "t").significanceHeuristic(scriptHeuristic)).get();
564564
} else {
565565
r = client().prepareSearch("cache_test_idx").setSize(0)
566566
.addAggregation(significantTerms("foo").field("s").significanceHeuristic(scriptHeuristic)).get();
@@ -577,7 +577,7 @@ public void testScriptCaching() throws Exception {
577577
useSigText = randomBoolean();
578578
if (useSigText) {
579579
r = client().prepareSearch("cache_test_idx").setSize(0)
580-
.addAggregation(significantText("foo", "s").significanceHeuristic(scriptHeuristic)).get();
580+
.addAggregation(significantText("foo", "t").significanceHeuristic(scriptHeuristic)).get();
581581
} else {
582582
r = client().prepareSearch("cache_test_idx").setSize(0)
583583
.addAggregation(significantTerms("foo").field("s").significanceHeuristic(scriptHeuristic)).get();
@@ -591,7 +591,7 @@ public void testScriptCaching() throws Exception {
591591

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

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
@@ -273,7 +273,7 @@ public static final class DateFieldType extends MappedFieldType {
273273
public DateFieldType(String name, boolean isSearchable, boolean isStored, boolean hasDocValues,
274274
DateFormatter dateTimeFormatter, Resolution resolution, String nullValue,
275275
Map<String, String> meta) {
276-
super(name, isSearchable, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
276+
super(name, isSearchable, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
277277
this.dateTimeFormatter = dateTimeFormatter;
278278
this.dateMathParser = dateTimeFormatter.toDateMathParser();
279279
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
@@ -133,7 +133,7 @@ public static final class IpFieldType extends SimpleMappedFieldType {
133133

134134
public IpFieldType(String name, boolean indexed, boolean stored, boolean hasDocValues,
135135
InetAddress nullValue, Map<String, String> meta) {
136-
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
136+
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
137137
this.nullValue = nullValue;
138138
}
139139

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,11 @@ public Map<String, String> meta() {
406406
* Returns information on how any text in this field is indexed
407407
*
408408
* Fields that do not support any text-based queries should return
409-
* {@link TextSearchInfo#NONE}. Some fields (eg numeric) may support
409+
* {@link TextSearchInfo#NONE}. Some fields (eg keyword) may support
410410
* only simple match queries, and can return
411-
* {@link TextSearchInfo#SIMPLE_MATCH_ONLY}
411+
* {@link TextSearchInfo#SIMPLE_MATCH_ONLY}; other fields may support
412+
* simple match queries without using the terms index, and can return
413+
* {@link TextSearchInfo#SIMPLE_MATCH_WITHOUT_TERMS}
412414
*/
413415
public TextSearchInfo getTextSearchInfo() {
414416
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
@@ -894,7 +894,7 @@ public static class NumberFieldType extends SimpleMappedFieldType {
894894

895895
public NumberFieldType(String name, NumberType type, boolean isSearchable, boolean isStored,
896896
boolean hasDocValues, boolean coerce, Number nullValue, Map<String, String> meta) {
897-
super(name, isSearchable, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
897+
super(name, isSearchable, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
898898
this.type = Objects.requireNonNull(type);
899899
this.coerce = coerce;
900900
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
@@ -153,7 +153,7 @@ public static final class RangeFieldType extends MappedFieldType {
153153

154154
public RangeFieldType(String name, RangeType type, boolean indexed, boolean stored,
155155
boolean hasDocValues, boolean coerce, Map<String, String> meta) {
156-
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
156+
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
157157
assert type != RangeType.DATE;
158158
this.rangeType = Objects.requireNonNull(type);
159159
dateTimeFormatter = null;
@@ -168,7 +168,7 @@ public RangeFieldType(String name, RangeType type) {
168168

169169
public RangeFieldType(String name, boolean indexed, boolean stored, boolean hasDocValues, DateFormatter formatter,
170170
boolean coerce, Map<String, String> meta) {
171-
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
171+
super(name, indexed, stored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
172172
this.rangeType = RangeType.DATE;
173173
this.dateTimeFormatter = Objects.requireNonNull(formatter);
174174
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
@@ -96,7 +96,7 @@ static final class SeqNoFieldType extends SimpleMappedFieldType {
9696
private static final SeqNoFieldType INSTANCE = new SeqNoFieldType();
9797

9898
private SeqNoFieldType() {
99-
super(NAME, true, false, true, TextSearchInfo.SIMPLE_MATCH_ONLY, Collections.emptyMap());
99+
super(NAME, true, false, true, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, Collections.emptyMap());
100100
}
101101

102102
@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)