Skip to content

Commit d553b8b

Browse files
authored
Implement parseBytesRef for TimeSeriesRoutingHashFieldType (elastic#113373) (elastic#113439)
This implements the `parseBytesRef` method for the `_ts_routing_hash` field so we can parse the values generated by the companion `format` method. We parse the values when fetching them from the source when the field is used as a `sort` paired with `search_after`. Before this change a sort by and search_after `_ts_routing_hash` would yield an `UnsupportedOperationException` (cherry picked from commit 4e5e870) Signed-off-by: Andrei Dan <[email protected]>
1 parent 8c81222 commit d553b8b

File tree

5 files changed

+77
-1
lines changed

5 files changed

+77
-1
lines changed

docs/changelog/113373.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 113373
2+
summary: Implement `parseBytesRef` for `TimeSeriesRoutingHashFieldType`
3+
area: TSDB
4+
type: bug
5+
issues:
6+
- 112399

rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/tsdb/25_id_generation.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ setup:
6565

6666
---
6767
generates a consistent id:
68+
- requires:
69+
cluster_features: "tsdb.ts_routing_hash_doc_value_parse_byte_ref"
70+
reason: _tsid routing hash doc value parsing has been fixed
6871
- do:
6972
bulk:
7073
refresh: true
@@ -152,6 +155,50 @@ generates a consistent id:
152155
- match: { hits.hits.8._source.@timestamp: 2021-04-28T18:52:04.467Z }
153156
- match: { hits.hits.8._source.k8s.pod.uid: 947e4ced-1786-4e53-9e0c-5c447e959507 }
154157

158+
- do:
159+
search:
160+
index: id_generation_test
161+
body:
162+
query:
163+
match_all: {}
164+
sort: ["@timestamp", "_ts_routing_hash"]
165+
_source: true
166+
search_after: [ "2021-04-28T18:50:03.142Z", "cn4exQ" ]
167+
docvalue_fields: [_ts_routing_hash]
168+
169+
- match: {hits.total.value: 9}
170+
171+
- match: { hits.hits.0._id: cZZNs7B9sSWsyrL5AAABeRnRGTM }
172+
- match: { hits.hits.0._source.@timestamp: 2021-04-28T18:50:04.467Z }
173+
- match: { hits.hits.0._source.k8s.pod.uid: 947e4ced-1786-4e53-9e0c-5c447e959507 }
174+
175+
- match: { hits.hits.1._id: cn4excfoxSs_KdA5AAABeRnRYiY }
176+
- match: { hits.hits.1._source.@timestamp: 2021-04-28T18:50:23.142Z }
177+
- match: { hits.hits.1._source.k8s.pod.uid: df3145b3-0563-4d3b-a0f7-897eb2876ea9 }
178+
179+
- match: { hits.hits.2._id: cZZNs7B9sSWsyrL5AAABeRnRZ1M }
180+
- match: { hits.hits.2._source.@timestamp: 2021-04-28T18:50:24.467Z }
181+
- match: { hits.hits.2._source.k8s.pod.uid: 947e4ced-1786-4e53-9e0c-5c447e959507 }
182+
183+
- match: { hits.hits.3._id: cZZNs7B9sSWsyrL5AAABeRnRtXM }
184+
- match: { hits.hits.3._source.@timestamp: 2021-04-28T18:50:44.467Z }
185+
- match: { hits.hits.3._source.k8s.pod.uid: 947e4ced-1786-4e53-9e0c-5c447e959507 }
186+
187+
- match: { hits.hits.4._id: cn4excfoxSs_KdA5AAABeRnR11Y }
188+
- match: { hits.hits.4._source.@timestamp: 2021-04-28T18:50:53.142Z }
189+
- match: { hits.hits.4._source.k8s.pod.uid: df3145b3-0563-4d3b-a0f7-897eb2876ea9 }
190+
191+
- match: { hits.hits.5._id: cn4excfoxSs_KdA5AAABeRnR_mY }
192+
- match: { hits.hits.5._source.@timestamp: 2021-04-28T18:51:03.142Z }
193+
- match: { hits.hits.5._source.k8s.pod.uid: df3145b3-0563-4d3b-a0f7-897eb2876ea9 }
194+
195+
- match: { hits.hits.6._id: cZZNs7B9sSWsyrL5AAABeRnSA5M }
196+
- match: { hits.hits.6._source.@timestamp: 2021-04-28T18:51:04.467Z }
197+
- match: { hits.hits.6._source.k8s.pod.uid: 947e4ced-1786-4e53-9e0c-5c447e959507 }
198+
199+
- match: { hits.hits.7._id: cZZNs7B9sSWsyrL5AAABeRnS7fM }
200+
- match: { hits.hits.7._source.@timestamp: 2021-04-28T18:52:04.467Z }
201+
- match: { hits.hits.7._source.k8s.pod.uid: 947e4ced-1786-4e53-9e0c-5c447e959507 }
155202
---
156203
index a new document on top of an old one:
157204
- do:

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ public Set<NodeFeature> getFeatures() {
4343
SourceFieldMapper.SYNTHETIC_SOURCE_COPY_TO_FIX,
4444
FlattenedFieldMapper.IGNORE_ABOVE_SUPPORT,
4545
IndexSettings.IGNORE_ABOVE_INDEX_LEVEL_SETTING,
46-
SourceFieldMapper.SYNTHETIC_SOURCE_COPY_TO_INSIDE_OBJECTS_FIX
46+
SourceFieldMapper.SYNTHETIC_SOURCE_COPY_TO_INSIDE_OBJECTS_FIX,
47+
TimeSeriesRoutingHashFieldMapper.TS_ROUTING_HASH_FIELD_PARSES_BYTES_REF
4748
);
4849
}
4950
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.apache.lucene.util.BytesRef;
1515
import org.elasticsearch.common.io.stream.StreamOutput;
1616
import org.elasticsearch.common.util.ByteUtils;
17+
import org.elasticsearch.features.NodeFeature;
1718
import org.elasticsearch.index.IndexMode;
1819
import org.elasticsearch.index.IndexVersions;
1920
import org.elasticsearch.index.fielddata.FieldData;
@@ -45,6 +46,7 @@ public class TimeSeriesRoutingHashFieldMapper extends MetadataFieldMapper {
4546
public static final TimeSeriesRoutingHashFieldMapper INSTANCE = new TimeSeriesRoutingHashFieldMapper();
4647

4748
public static final TypeParser PARSER = new FixedTypeParser(c -> c.getIndexSettings().getMode().timeSeriesRoutingHashFieldMapper());
49+
static final NodeFeature TS_ROUTING_HASH_FIELD_PARSES_BYTES_REF = new NodeFeature("tsdb.ts_routing_hash_doc_value_parse_byte_ref");
4850

4951
static final class TimeSeriesRoutingHashFieldType extends MappedFieldType {
5052

@@ -64,6 +66,13 @@ public Object format(BytesRef value) {
6466
return Uid.decodeId(value.bytes, value.offset, value.length);
6567
}
6668

69+
@Override
70+
public BytesRef parseBytesRef(Object value) {
71+
if (value instanceof BytesRef valueAsBytesRef) {
72+
return valueAsBytesRef;
73+
}
74+
return Uid.encodeId(value.toString());
75+
}
6776
};
6877

6978
private TimeSeriesRoutingHashFieldType() {

server/src/test/java/org/elasticsearch/search/DocValueFormatTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.elasticsearch.common.time.DateFormatter;
2121
import org.elasticsearch.index.mapper.DateFieldMapper.Resolution;
2222
import org.elasticsearch.index.mapper.TimeSeriesIdFieldMapper.TimeSeriesIdBuilder;
23+
import org.elasticsearch.index.mapper.TimeSeriesRoutingHashFieldMapper;
2324
import org.elasticsearch.test.ESTestCase;
2425

2526
import java.io.IOException;
@@ -33,6 +34,8 @@
3334
import static org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileUtils.longEncode;
3435
import static org.hamcrest.Matchers.containsString;
3536
import static org.hamcrest.Matchers.equalTo;
37+
import static org.hamcrest.Matchers.instanceOf;
38+
import static org.hamcrest.Matchers.is;
3639

3740
public class DocValueFormatTests extends ESTestCase {
3841

@@ -388,4 +391,14 @@ public void testParseTsid() throws IOException {
388391
Object tsidBase64 = Base64.getUrlEncoder().withoutPadding().encodeToString(expectedBytes);
389392
assertEquals(tsidFormat, tsidBase64);
390393
}
394+
395+
public void testFormatAndParseTsRoutingHash() throws IOException {
396+
BytesRef tsRoutingHashInput = new BytesRef("cn4exQ");
397+
DocValueFormat docValueFormat = TimeSeriesRoutingHashFieldMapper.INSTANCE.fieldType().docValueFormat(null, ZoneOffset.UTC);
398+
Object formattedValue = docValueFormat.format(tsRoutingHashInput);
399+
// the format method takes BytesRef as input and outputs a String
400+
assertThat(formattedValue, instanceOf(String.class));
401+
// the parse method will output the BytesRef input
402+
assertThat(docValueFormat.parseBytesRef(formattedValue), is(tsRoutingHashInput));
403+
}
391404
}

0 commit comments

Comments
 (0)