Skip to content

Commit 7e13c56

Browse files
Enable collapse on unsigned_long field (#63495) (#63810)
Collapse was not working on unsigned_long field, as collapsing was enabled only on KeywordFieldType and NumberFieldType. This introduces a new method `collapseType` to MappedFieldType, that is checked to decide if collapsing should be enabled. Relates to #60050
1 parent 356109f commit 7e13c56

File tree

8 files changed

+120
-15
lines changed

8 files changed

+120
-15
lines changed

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

+5
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@ protected BytesRef indexedValueForSearch(Object value) {
294294
}
295295
return getTextSearchInfo().getSearchAnalyzer().normalize(name(), value.toString());
296296
}
297+
298+
@Override
299+
public CollapseType collapseType() {
300+
return CollapseType.KEYWORD;
301+
}
297302
}
298303

299304
private final boolean indexed;

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

+15
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,15 @@ public void setIndexAnalyzer(NamedAnalyzer analyzer) {
141141
this.indexAnalyzer = analyzer;
142142
}
143143

144+
/**
145+
* Returns the collapse type of the field
146+
* CollapseType.NONE means the field can'be used for collapsing.
147+
* @return collapse type of the field
148+
*/
149+
public CollapseType collapseType() {
150+
return CollapseType.NONE;
151+
}
152+
144153
/** Given a value that comes from the stored fields API, convert it to the
145154
* expected type. For instance a date field would store dates as longs and
146155
* format it back to a string in this method. */
@@ -415,4 +424,10 @@ public Map<String, String> meta() {
415424
public TextSearchInfo getTextSearchInfo() {
416425
return textSearchInfo;
417426
}
427+
428+
public enum CollapseType {
429+
NONE, // this field is not collapsable
430+
KEYWORD,
431+
NUMERIC
432+
}
418433
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,11 @@ public DocValueFormat docValueFormat(String format, ZoneId timeZone) {
10071007
public Number parsePoint(byte[] value) {
10081008
return type.parsePoint(value);
10091009
}
1010+
1011+
@Override
1012+
public CollapseType collapseType() {
1013+
return CollapseType.NUMERIC;
1014+
}
10101015
}
10111016

10121017
private final NumberType type;

server/src/main/java/org/elasticsearch/search/collapse/CollapseBuilder.java

+4-7
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,10 @@
2929
import org.elasticsearch.common.xcontent.ToXContentObject;
3030
import org.elasticsearch.common.xcontent.XContentBuilder;
3131
import org.elasticsearch.common.xcontent.XContentParser;
32-
import org.elasticsearch.index.mapper.KeywordFieldMapper;
3332
import org.elasticsearch.index.mapper.MappedFieldType;
34-
import org.elasticsearch.index.mapper.NumberFieldMapper;
3533
import org.elasticsearch.index.query.InnerHitBuilder;
3634
import org.elasticsearch.index.query.QueryShardContext;
35+
import org.elasticsearch.index.mapper.MappedFieldType.CollapseType;
3736

3837
import java.io.IOException;
3938
import java.util.ArrayList;
@@ -203,12 +202,10 @@ public CollapseContext build(QueryShardContext queryShardContext) {
203202
if (fieldType == null) {
204203
throw new IllegalArgumentException("no mapping found for `" + field + "` in order to collapse on");
205204
}
206-
if (fieldType instanceof KeywordFieldMapper.KeywordFieldType == false &&
207-
fieldType instanceof NumberFieldMapper.NumberFieldType == false) {
208-
throw new IllegalArgumentException("unknown type for collapse field `" + field +
209-
"`, only keywords and numbers are accepted");
205+
if (fieldType.collapseType() == CollapseType.NONE) {
206+
throw new IllegalArgumentException("collapse is not supported for the field [" + fieldType.name() +
207+
"] of the type [" + fieldType.typeName() + "]");
210208
}
211-
212209
if (fieldType.hasDocValues() == false) {
213210
throw new IllegalArgumentException("cannot collapse on field `" + field + "` without `doc_values`");
214211
}

server/src/main/java/org/elasticsearch/search/collapse/CollapseContext.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@
2020

2121
import org.apache.lucene.search.Sort;
2222
import org.apache.lucene.search.grouping.CollapsingTopDocsCollector;
23-
import org.elasticsearch.index.mapper.KeywordFieldMapper;
2423
import org.elasticsearch.index.mapper.MappedFieldType;
25-
import org.elasticsearch.index.mapper.NumberFieldMapper;
2624
import org.elasticsearch.index.query.InnerHitBuilder;
25+
import org.elasticsearch.index.mapper.MappedFieldType.CollapseType;
2726

2827
import java.util.List;
2928

@@ -61,13 +60,12 @@ public List<InnerHitBuilder> getInnerHit() {
6160
}
6261

6362
public CollapsingTopDocsCollector<?> createTopDocs(Sort sort, int topN) {
64-
if (fieldType instanceof KeywordFieldMapper.KeywordFieldType) {
63+
if (fieldType.collapseType() == CollapseType.KEYWORD) {
6564
return CollapsingTopDocsCollector.createKeyword(fieldName, fieldType, sort, topN);
66-
} else if (fieldType instanceof NumberFieldMapper.NumberFieldType) {
65+
} else if (fieldType.collapseType() == CollapseType.NUMERIC) {
6766
return CollapsingTopDocsCollector.createNumeric(fieldName, fieldType, sort, topN);
6867
} else {
69-
throw new IllegalStateException("unknown type for collapse field " + fieldName +
70-
", only keywords and numbers are accepted");
68+
throw new IllegalStateException("collapse is not supported on this field type");
7169
}
7270
}
7371
}

server/src/test/java/org/elasticsearch/search/collapse/CollapseBuilderTests.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ public void testBuildWithExceptions() {
205205
MappedFieldType fieldType = new MappedFieldType("field", true, false, true, TextSearchInfo.NONE, Collections.emptyMap()) {
206206
@Override
207207
public String typeName() {
208-
return null;
208+
return "some_type";
209209
}
210210

211211
@Override
@@ -225,7 +225,7 @@ public Query existsQuery(QueryShardContext context) {
225225
when(shardContext.getFieldType("field")).thenReturn(fieldType);
226226
CollapseBuilder builder = new CollapseBuilder("field");
227227
IllegalArgumentException exc = expectThrows(IllegalArgumentException.class, () -> builder.build(shardContext));
228-
assertEquals(exc.getMessage(), "unknown type for collapse field `field`, only keywords and numbers are accepted");
228+
assertEquals(exc.getMessage(), "collapse is not supported for the field [field] of the type [some_type]");
229229
}
230230
}
231231

x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java

+5
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ public Function<byte[], Number> pointReaderIfPossible() {
277277
return null;
278278
}
279279

280+
@Override
281+
public CollapseType collapseType() {
282+
return CollapseType.NUMERIC;
283+
}
284+
280285
/**
281286
* Parses value to unsigned long for Term Query
282287
* @param value to to parse
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
setup:
2+
3+
- skip:
4+
version: " - 7.99.99"
5+
reason: "collapse on unsigned_long was added in 8.0"
6+
7+
- do:
8+
indices.create:
9+
index: test1
10+
body:
11+
settings:
12+
index.number_of_shards: 3
13+
mappings:
14+
properties:
15+
ul:
16+
type: unsigned_long
17+
k:
18+
type: keyword
19+
20+
- do:
21+
bulk:
22+
index: test1
23+
refresh: true
24+
body: |
25+
{ "index": {"_id" : "1"} }
26+
{ "ul": 0, "k": "01" }
27+
{ "index": {"_id" : "2"} }
28+
{ "ul": 0, "k": "02" }
29+
{ "index": {"_id" : "3"} }
30+
{ "ul": 9223372036854775807, "k": "03" }
31+
{ "index": {"_id" : "4"} }
32+
{ "ul": 9223372036854775807, "k": "04" }
33+
{ "index": {"_id" : "5"} }
34+
{ "ul": 9223372036854775808, "k": "05" }
35+
{ "index": {"_id" : "6"} }
36+
{ "ul": 9223372036854775808, "k": "06" }
37+
{ "index": {"_id" : "7"} }
38+
{ "ul": 18446744073709551614, "k": "07" }
39+
{ "index": {"_id" : "8"} }
40+
{ "ul": 18446744073709551615, "k": "08" }
41+
{ "index": {"_id" : "9"} }
42+
{ "ul": 18446744073709551615, "k": "09" }
43+
{ "index": {"_id" : "10"} }
44+
{ "ul": 18446744073709551615, "k": "10" }
45+
46+
---
47+
"Collapse":
48+
- do:
49+
search:
50+
index: test1
51+
body:
52+
collapse:
53+
field: ul
54+
inner_hits:
55+
name: my_inner_hits
56+
_source : false
57+
size: 3
58+
sort: [ "k" ]
59+
60+
- match: { hits.total.value: 10 }
61+
62+
- match: { hits.hits.0._id: "1" }
63+
- match: { hits.hits.0.fields.ul: [0] }
64+
- match: { hits.hits.0.inner_hits.my_inner_hits.hits.total.value: 2 }
65+
66+
- match: { hits.hits.1._id: "3" }
67+
- match: { hits.hits.1.fields.ul: [9223372036854775807] }
68+
- match: { hits.hits.1.inner_hits.my_inner_hits.hits.total.value: 2 }
69+
70+
- match: { hits.hits.2._id: "5" }
71+
- match: { hits.hits.2.fields.ul: [9223372036854775808] }
72+
- match: { hits.hits.2.inner_hits.my_inner_hits.hits.total.value: 2 }
73+
74+
- match: { hits.hits.3._id: "7" }
75+
- match: { hits.hits.3.fields.ul: [18446744073709551614] }
76+
- match: { hits.hits.3.inner_hits.my_inner_hits.hits.total.value: 1 }
77+
78+
- match: { hits.hits.4._id: "8" }
79+
- match: { hits.hits.4.fields.ul: [18446744073709551615] }
80+
- match: { hits.hits.4.inner_hits.my_inner_hits.hits.total.value: 3 }

0 commit comments

Comments
 (0)