Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
20dc681
ES|QL: Make _tsid available in metadata
leontyevdv Sep 22, 2025
27b4a4c
[CI] Auto commit changes from spotless
Sep 22, 2025
43610a7
ES|QL: Make _tsid available in metadata
leontyevdv Sep 22, 2025
3a003e1
Merge remote-tracking branch 'origin/feature/esql-add-tsid-into-metad…
leontyevdv Sep 22, 2025
8954568
[CI] Auto commit changes from spotless
Sep 22, 2025
f2e7404
ES|QL: Make _tsid available in metadata
leontyevdv Sep 22, 2025
abcdbd0
Merge remote-tracking branch 'origin/feature/esql-add-tsid-into-metad…
leontyevdv Sep 22, 2025
98434a6
ES|QL: Make _tsid available in metadata
leontyevdv Sep 23, 2025
09338d7
[CI] Update transport version definitions
Sep 23, 2025
31b3823
Merge branch 'main' into feature/esql-add-tsid-into-metadata-list
leontyevdv Sep 23, 2025
ec17c13
ES|QL: Make _tsid available in metadata
leontyevdv Sep 23, 2025
7c497df
Merge branch 'main' into feature/esql-add-tsid-into-metadata-list
leontyevdv Sep 23, 2025
35da14a
ES|QL: Make _tsid available in metadata
leontyevdv Sep 23, 2025
f14c65d
Update docs/changelog/135204.yaml
leontyevdv Sep 23, 2025
80d6197
[CI] Update transport version definitions
Sep 23, 2025
a492b47
ES|QL: Make _tsid available in metadata
leontyevdv Sep 23, 2025
7c9b453
Merge remote-tracking branch 'origin/feature/esql-add-tsid-into-metad…
leontyevdv Sep 23, 2025
d283f77
Merge branch 'main' into feature/esql-add-tsid-into-metadata-list
leontyevdv Sep 25, 2025
d1fcc5e
Merge branch 'main' into feature/esql-add-tsid-into-metadata-list
leontyevdv Sep 26, 2025
3e1f1dd
ES|QL: Make _tsid available in metadata
leontyevdv Sep 26, 2025
f289285
ES|QL: Make _tsid available in metadata
leontyevdv Sep 26, 2025
0687445
Merge branch 'main' into feature/esql-add-tsid-into-metadata-list
leontyevdv Sep 26, 2025
62a63e6
ES|QL: Make _tsid available in metadata
leontyevdv Sep 26, 2025
5b6cc34
ES|QL: Make _tsid available in metadata
leontyevdv Sep 26, 2025
0d9ff88
Merge branch 'main' into feature/esql-add-tsid-into-metadata-list
leontyevdv Sep 26, 2025
1324a9f
Merge branch 'main' into feature/esql-add-tsid-into-metadata-list
leontyevdv Sep 29, 2025
3f23565
Merge branch 'main' into feature/esql-add-tsid-into-metadata-list
leontyevdv Sep 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/changelog/135204.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 135204
summary: Make `_tsid` available in metadata
area: "ES|QL, TSDB, ES|QL"
type: enhancement
issues:
- 133205

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

| field | result |
| --- | --- |
| _tsid | boolean |
| boolean | boolean |
| cartesian_point | boolean |
| cartesian_shape | boolean |
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ public Query termQuery(Object value, SearchExecutionContext context) {
throw new IllegalArgumentException("[" + NAME + "] is not searchable");
}

@Override
public Object valueForDisplay(Object value) {
if (value == null) {
return null;
}
BytesRef binaryValue = (BytesRef) value;
return TimeSeriesIdFieldMapper.encodeTsid(binaryValue);
}

@Override
public BlockLoader blockLoader(BlockLoaderContext blContext) {
return new BlockDocValuesReader.BytesRefsFromOrdsBlockLoader(name());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -768,4 +768,23 @@ public void testParseWithDynamicMappingInvalidRoutingHash() {
});
assertThat(failure.getMessage(), equalTo("[5:1] failed to parse: Illegal base64 character 20"));
}

public void testValueForDisplay() throws Exception {
DocumentMapper docMapper = createDocumentMapper("a", mapping(b -> {
b.startObject("a").field("type", "keyword").field("time_series_dimension", true).endObject();
b.startObject("b").field("type", "long").field("time_series_dimension", true).endObject();
}));

ParsedDocument doc = parseDocument(docMapper, b -> b.field("a", "value").field("b", 100));
BytesRef tsidBytes = doc.rootDoc().getBinaryValue("_tsid");
assertThat(tsidBytes, not(nullValue()));

TimeSeriesIdFieldMapper.TimeSeriesIdFieldType fieldType = TimeSeriesIdFieldMapper.FIELD_TYPE;
Object displayValue = fieldType.valueForDisplay(tsidBytes);
Object encodedValue = TimeSeriesIdFieldMapper.encodeTsid(tsidBytes);

assertThat(displayValue, equalTo(encodedValue));
assertThat(displayValue.getClass(), is(String.class));
assertThat(fieldType.valueForDisplay(null), nullValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ public class MetadataAttribute extends TypedAttribute {
Map.entry(IgnoredFieldMapper.NAME, new MetadataAttributeConfiguration(DataType.KEYWORD, true)),
Map.entry(SourceFieldMapper.NAME, new MetadataAttributeConfiguration(DataType.SOURCE, false)),
Map.entry(IndexModeFieldMapper.NAME, new MetadataAttributeConfiguration(DataType.KEYWORD, true)),
Map.entry(SCORE, new MetadataAttributeConfiguration(DataType.DOUBLE, false))
Map.entry(SCORE, new MetadataAttributeConfiguration(DataType.DOUBLE, false)),
Map.entry(TSID_FIELD, new MetadataAttributeConfiguration(DataType.TSID_DATA_TYPE, false))
);

private record MetadataAttributeConfiguration(DataType dataType, boolean searchable) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ public enum DataType {
}

private static final Collection<DataType> TYPES = Arrays.stream(values())
.filter(d -> d != DOC_DATA_TYPE && d != TSID_DATA_TYPE)
.filter(d -> d != DOC_DATA_TYPE)
.sorted(Comparator.comparing(DataType::typeName))
.toList();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.elasticsearch.geometry.utils.Geohash;
import org.elasticsearch.h3.H3;
import org.elasticsearch.index.IndexMode;
import org.elasticsearch.index.mapper.RoutingPathFields;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.search.SearchService;
import org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileUtils;
Expand Down Expand Up @@ -887,8 +888,9 @@ public static Literal randomLiteral(DataType type) {
throw new UncheckedIOException(e);
}
}
case TSID_DATA_TYPE -> randomTsId().toBytesRef();
case DENSE_VECTOR -> Arrays.asList(randomArray(10, 10, i -> new Float[10], ESTestCase::randomFloat));
case UNSUPPORTED, OBJECT, DOC_DATA_TYPE, TSID_DATA_TYPE, PARTIAL_AGG -> throw new IllegalArgumentException(
case UNSUPPORTED, OBJECT, DOC_DATA_TYPE, PARTIAL_AGG -> throw new IllegalArgumentException(
"can't make random values for [" + type.typeName() + "]"
);
}, type);
Expand All @@ -904,6 +906,22 @@ static Version randomVersion() {
};
}

static BytesReference randomTsId() {
RoutingPathFields routingPathFields = new RoutingPathFields(null);

int numDimensions = randomIntBetween(1, 4);
for (int i = 0; i < numDimensions; i++) {
String fieldName = "dim" + i;
if (randomBoolean()) {
routingPathFields.addString(fieldName, randomAlphaOfLength(randomIntBetween(3, 10)));
} else {
routingPathFields.addLong(fieldName, randomLongBetween(1, 1000));
}
}

return routingPathFields.buildHash();
}

public static WildcardLike wildcardLike(Expression left, String exp) {
return new WildcardLike(EMPTY, left, new WildcardPattern(exp), false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,3 +518,37 @@ true | two | 2024-05-10T00:18:00.000Z
false | two | 2024-05-10T00:20:00.000Z
false | two | 2024-05-10T00:22:00.000Z
;

tsidMetadataAttributeCount
required_capability: metrics_command
required_capability: metadata_tsid_field

TS k8s METADATA _tsid
| STATS cnt = count_distinct(_tsid)
;

cnt:long
9
;

tsidMetadataAttributeAggregation
required_capability: metrics_command
required_capability: metadata_tsid_field

TS k8s METADATA _tsid
| STATS cnt = COUNT(_tsid) BY cluster, pod
| SORT cluster
;
ignoreOrder:true

cnt:long | cluster:keyword | pod:keyword
1 | staging | one
1 | staging | two
1 | staging | three
1 | qa | one
1 | qa | two
1 | qa | three
1 | prod | one
1 | prod | two
1 | prod | three
;
Original file line number Diff line number Diff line change
Expand Up @@ -686,4 +686,21 @@ public void testNullMetricsAreSkipped() {
assertEquals("Did not filter nulls on counter type", 50, resp.documentsFound());
}
}

public void testTSIDMetadataAttribute() {
List<ColumnInfoImpl> columns = List.of(
new ColumnInfoImpl("_tsid", DataType.TSID_DATA_TYPE, null),
new ColumnInfoImpl("cluster", DataType.KEYWORD, null)
);

try (EsqlQueryResponse resp = run(" TS hosts METADATA _tsid | KEEP _tsid, cluster | LIMIT 1")) {
assertThat(resp.columns(), equalTo(columns));

List<List<Object>> values = EsqlTestUtils.getValuesList(resp);
assertThat(values, hasSize(1));
assertThat(values.getFirst().get(0), Matchers.notNullValue());
assertThat(values.getFirst().get(1), Matchers.notNullValue());
}
}

}
Loading