Skip to content
8 changes: 5 additions & 3 deletions docs/querying/segmentmetadataquery.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@ The format of the result is:
} ]
```

Dimension columns will have type `STRING`, `FLOAT`, `DOUBLE`, or `LONG`.
Metric columns will have type `FLOAT`, `DOUBLE`, or `LONG`, or the name of the underlying complex type such as `hyperUnique` in case of COMPLEX metric.
Timestamp column will have type `LONG`.
All columns contain a `typeSignature` that Druid uses to represent the column type information internally. The `typeSignature` is typically the same value used to identify the JSON type information at query or ingest time. One of: `STRING`, `FLOAT`, `DOUBLE`, `LONG`, or `COMPLEX<typeName>`, e.g. `COMPLEX<hyperUnique>`.

Columns also have a legacy `type` name. For some column types, the value may match the `typeSignature` (`STRING`, `FLOAT`, `DOUBLE`, or `LONG`). For `COMPLEX` columns, the `type` only contains the name of the underlying complex type such as `hyperUnique`.

New applications should use `typeSignature`, not `type`.

If the `errorMessage` field is non-null, you should not trust the other fields in the response. Their contents are
undefined.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"id": "merged",
"columns": {
"location": {
"typeSignature": "STRING",
"type": "STRING",
"size": 0,
"hasMultipleValues": false,
Expand All @@ -25,6 +26,7 @@
"errorMessage": null
},
"user_id_sketch": {
"typeSignature": "COMPLEX<thetaSketch>",
"type": "thetaSketch",
"size": 0,
"hasMultipleValues": false,
Expand All @@ -35,6 +37,7 @@
"errorMessage": null
},
"other_metric": {
"typeSignature": "COMPLEX<thetaSketch>",
"type": "thetaSketch",
"size": 0,
"hasMultipleValues": false,
Expand All @@ -45,6 +48,7 @@
"errorMessage": null
},
"__time": {
"typeSignature": "LONG",
"type": "LONG",
"size": 0,
"hasMultipleValues": false,
Expand All @@ -55,6 +59,7 @@
"errorMessage": null
},
"product": {
"typeSignature": "STRING",
"type": "STRING",
"size": 0,
"hasMultipleValues": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@
"intervals":["2013-01-01T00:00:00.000Z/2013-01-02T00:00:00.000Z"],
"columns":{
"has_links":{
"typeSignature": "STRING",
"type":"STRING",
"hasMultipleValues":false,
"size":0,
Expand All @@ -618,6 +619,7 @@
"intervals":["2013-01-02T00:00:00.000Z/2013-01-03T00:00:00.000Z"],
"columns":{
"has_links":{
"typeSignature": "STRING",
"type":"STRING",
"hasMultipleValues":false,
"size":0,
Expand All @@ -640,6 +642,7 @@
"intervals":["2013-01-03T00:00:00.000Z/2013-01-04T00:00:00.000Z"],
"columns":{
"has_links":{
"typeSignature": "STRING",
"type":"STRING",
"hasMultipleValues":false,
"size":0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,7 @@
"intervals":["2012-12-29T00:00:00.000Z/2013-01-10T08:00:00.000Z"],
"columns":{
"country_name":{
"typeSignature": "STRING",
"type":"STRING",
"hasMultipleValues":false,
"size":0,
Expand All @@ -1412,6 +1413,7 @@
"hasNulls":true
},
"language":{
"typeSignature": "STRING",
"type":"STRING",
"hasMultipleValues":false,
"size":0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
import org.apache.druid.segment.column.ColumnHolder;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.ColumnTypeFactory;
import org.apache.druid.segment.column.ComplexColumn;
import org.apache.druid.segment.column.DictionaryEncodedColumn;
import org.apache.druid.segment.column.TypeSignature;
Expand Down Expand Up @@ -194,7 +195,8 @@ private ColumnAnalysis analyzeNumericColumn(
}

return new ColumnAnalysis(
capabilities.asTypeString(),
capabilities.toColumnType(),
capabilities.getType().name(),
capabilities.hasMultipleValues().isTrue(),
capabilities.hasNulls().isMaybeTrue(), // if we don't know for sure, then we should plan to check for nulls
size,
Expand Down Expand Up @@ -250,7 +252,8 @@ private ColumnAnalysis analyzeStringColumn(
}

return new ColumnAnalysis(
capabilities.asTypeString(),
capabilities.toColumnType(),
capabilities.getType().name(),
capabilities.hasMultipleValues().isTrue(),
capabilities.hasNulls().isMaybeTrue(), // if we don't know for sure, then we should plan to check for nulls
size,
Expand Down Expand Up @@ -328,7 +331,8 @@ public Long accumulate(Long accumulated, Cursor cursor)
}

return new ColumnAnalysis(
capabilities.asTypeString(),
capabilities.toColumnType(),
capabilities.getType().name(),
capabilities.hasMultipleValues().isTrue(),
capabilities.hasNulls().isMaybeTrue(), // if we don't know for sure, then we should plan to check for nulls
size,
Expand All @@ -347,8 +351,6 @@ private ColumnAnalysis analyzeComplexColumn(
final TypeSignature<ValueType> typeSignature = capabilities == null ? ColumnType.UNKNOWN_COMPLEX : capabilities;
final String typeName = typeSignature.getComplexTypeName();

// serialize using asTypeString (which is also used for JSON so can easily round-trip complex type info back into ColumnType)
final String serdeTypeName = typeSignature.asTypeString();
try (final ComplexColumn complexColumn = columnHolder != null ? (ComplexColumn) columnHolder.getColumn() : null) {
final boolean hasMultipleValues = capabilities != null && capabilities.hasMultipleValues().isTrue();
final boolean hasNulls = capabilities != null && capabilities.hasNulls().isMaybeTrue();
Expand All @@ -363,7 +365,8 @@ private ColumnAnalysis analyzeComplexColumn(
final Function<Object, Long> inputSizeFn = serde.inputSizeFn();
if (inputSizeFn == null) {
return new ColumnAnalysis(
serdeTypeName,
ColumnTypeFactory.ofType(typeSignature),
typeName,
hasMultipleValues,
hasNulls,
0,
Expand All @@ -381,7 +384,8 @@ private ColumnAnalysis analyzeComplexColumn(
}

return new ColumnAnalysis(
serdeTypeName,
ColumnTypeFactory.ofType(typeSignature),
typeName,
hasMultipleValues,
hasNulls,
size,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
Expand Down Expand Up @@ -58,8 +57,6 @@
import org.joda.time.DateTime;
import org.joda.time.Interval;

import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
Expand All @@ -75,16 +72,10 @@ public class SegmentMetadataQueryQueryToolChest extends QueryToolChest<SegmentAn
private static final TypeReference<SegmentAnalysis> TYPE_REFERENCE = new TypeReference<SegmentAnalysis>()
{
};
private static final byte[] SEGMENT_METADATA_CACHE_PREFIX = new byte[]{0x4};
private static final byte SEGMENT_METADATA_CACHE_PREFIX = 0x4;
private static final byte SEGMENT_METADATA_QUERY = 0x16;
private static final Function<SegmentAnalysis, SegmentAnalysis> MERGE_TRANSFORM_FN = new Function<SegmentAnalysis, SegmentAnalysis>()
{
@Override
public SegmentAnalysis apply(SegmentAnalysis analysis)
{
return finalizeAnalysis(analysis);
}
};
private static final Function<SegmentAnalysis, SegmentAnalysis> MERGE_TRANSFORM_FN =
SegmentMetadataQueryQueryToolChest::finalizeAnalysis;

private final SegmentMetadataQueryConfig config;
private final GenericQueryMetricsFactory queryMetricsFactory;
Expand Down Expand Up @@ -195,13 +186,9 @@ public boolean isCacheable(SegmentMetadataQuery query, boolean willMergeRunners)
public byte[] computeCacheKey(SegmentMetadataQuery query)
{
SegmentMetadataQuery updatedQuery = query.withFinalizedAnalysisTypes(config);
byte[] includerBytes = updatedQuery.getToInclude().getCacheKey();
byte[] analysisTypesBytes = updatedQuery.getAnalysisTypesCacheKey();
return ByteBuffer.allocate(1 + includerBytes.length + analysisTypesBytes.length)
.put(SEGMENT_METADATA_CACHE_PREFIX)
.put(includerBytes)
.put(analysisTypesBytes)
.array();
return new CacheKeyBuilder(SEGMENT_METADATA_CACHE_PREFIX).appendCacheable(updatedQuery.getToInclude())
.appendCacheables(updatedQuery.getAnalysisTypes())
.build();
}

@Override
Expand All @@ -223,27 +210,13 @@ public TypeReference<SegmentAnalysis> getCacheObjectClazz()
@Override
public Function<SegmentAnalysis, SegmentAnalysis> prepareForCache(boolean isResultLevelCache)
{
return new Function<SegmentAnalysis, SegmentAnalysis>()
{
@Override
public SegmentAnalysis apply(@Nullable SegmentAnalysis input)
{
return input;
}
};
return input -> input;
}

@Override
public Function<SegmentAnalysis, SegmentAnalysis> pullFromCache(boolean isResultLevelCache)
{
return new Function<SegmentAnalysis, SegmentAnalysis>()
{
@Override
public SegmentAnalysis apply(@Nullable SegmentAnalysis input)
{
return input;
}
};
return input -> input;
}
};
}
Expand All @@ -266,14 +239,7 @@ public <T extends LogicalSegment> List<T> filterSegments(SegmentMetadataQuery qu
return Lists.newArrayList(
Iterables.filter(
segments,
new Predicate<T>()
{
@Override
public boolean apply(T input)
{
return (input.getInterval().overlaps(targetInterval));
}
}
input -> (input.getInterval().overlaps(targetInterval))
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.segment.column.ColumnType;

import java.util.Objects;

Expand All @@ -33,10 +35,11 @@ public class ColumnAnalysis

public static ColumnAnalysis error(String reason)
{
return new ColumnAnalysis("STRING", false, false, -1, null, null, null, ERROR_PREFIX + reason);
return new ColumnAnalysis(ColumnType.STRING, "STRING", false, false, -1, null, null, null, ERROR_PREFIX + reason);
}

private final String type;
private final ColumnType typeSignature;
private final boolean hasMultipleValues;
private final boolean hasNulls;
private final long size;
Expand All @@ -47,6 +50,7 @@ public static ColumnAnalysis error(String reason)

@JsonCreator
public ColumnAnalysis(
@JsonProperty("typeSignature") ColumnType typeSignature,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this change cause a problem during upgrade? E.g. an historical is on older version while broker is on newer version so the broker gets old json from the historical when running segment metadata queries?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the supported upgrade order is brokers last, but it would just be null, which shouldn't be a problem i think

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/apache/druid/pull/11895/files#diff-5aa1494dc5a13e82654e42ce8cdb3cb628c95233f8828312b3ede40dac1b8544R156 - shall this be modified to pick the one if the other is null instead of throwing an error. I am throwing darts in the dark here so please ignore if this is not really a problem :)

Copy link
Copy Markdown
Member Author

@clintropolis clintropolis Nov 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, if we supported updating the broker before data servers then we might want to consider that, but we don't (so that new query types, filters, aggregators, etc cannot be issued before data servers can understand them)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes. you are right. thanks for clarifying.

@JsonProperty("type") String type,
@JsonProperty("hasMultipleValues") boolean hasMultipleValues,
@JsonProperty("hasNulls") boolean hasNulls,
Expand All @@ -57,6 +61,7 @@ public ColumnAnalysis(
@JsonProperty("errorMessage") String errorMessage
)
{
this.typeSignature = typeSignature;
this.type = type;
this.hasMultipleValues = hasMultipleValues;
this.hasNulls = hasNulls;
Expand All @@ -68,6 +73,13 @@ public ColumnAnalysis(
}

@JsonProperty
public ColumnType getTypeSignature()
{
return typeSignature;
}

@JsonProperty
@Deprecated
public String getType()
{
return type;
Expand Down Expand Up @@ -135,8 +147,20 @@ public ColumnAnalysis fold(ColumnAnalysis rhs)
return rhs;
}

if (!type.equals(rhs.getType())) {
return ColumnAnalysis.error("cannot_merge_diff_types");
if (!Objects.equals(type, rhs.getType())) {
return ColumnAnalysis.error(
StringUtils.format("cannot_merge_diff_types: [%s] and [%s]", type, rhs.getType())
);
}

if (!Objects.equals(typeSignature, rhs.getTypeSignature())) {
return ColumnAnalysis.error(
StringUtils.format(
"cannot_merge_diff_types: [%s] and [%s]",
typeSignature.asTypeString(),
rhs.getTypeSignature().asTypeString()
)
);
}

Integer cardinality = getCardinality();
Expand All @@ -153,6 +177,7 @@ public ColumnAnalysis fold(ColumnAnalysis rhs)
Comparable newMax = choose(maxValue, rhs.maxValue, true);

return new ColumnAnalysis(
typeSignature,
type,
multipleValues,
hasNulls || rhs.hasNulls,
Expand Down Expand Up @@ -180,7 +205,8 @@ private <T extends Comparable> T choose(T obj1, T obj2, boolean max)
public String toString()
{
return "ColumnAnalysis{" +
"type='" + type + '\'' +
"typeSignature='" + typeSignature + '\'' +
", type=" + type +
", hasMultipleValues=" + hasMultipleValues +
", hasNulls=" + hasNulls +
", size=" + size +
Expand All @@ -204,6 +230,7 @@ public boolean equals(Object o)
return hasMultipleValues == that.hasMultipleValues &&
hasNulls == that.hasNulls &&
size == that.size &&
Objects.equals(typeSignature, that.typeSignature) &&
Objects.equals(type, that.type) &&
Objects.equals(cardinality, that.cardinality) &&
Objects.equals(minValue, that.minValue) &&
Expand All @@ -214,6 +241,16 @@ public boolean equals(Object o)
@Override
public int hashCode()
{
return Objects.hash(type, hasMultipleValues, hasNulls, size, cardinality, minValue, maxValue, errorMessage);
return Objects.hash(
typeSignature,
type,
hasMultipleValues,
hasNulls,
size,
cardinality,
minValue,
maxValue,
errorMessage
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.apache.druid.java.util.common.Cacheable;

/**
*/
Expand All @@ -30,8 +31,7 @@
@JsonSubTypes.Type(name = "all", value = AllColumnIncluderator.class),
@JsonSubTypes.Type(name = "list", value = ListColumnIncluderator.class)
})
public interface ColumnIncluderator
public interface ColumnIncluderator extends Cacheable
{
boolean include(String columnName);
byte[] getCacheKey();
}
Loading