add DruidPrettyPrinter

This commit is contained in:
Zoltan Haindrich 2024-07-24 17:14:30 +00:00
parent e60a200d95
commit 7cfbfdc3ee
16 changed files with 250 additions and 88 deletions

View File

@ -86,7 +86,7 @@ public class MSQDruidMeta extends DruidMeta
}
try {
String str = objectMapper
.writerWithDefaultPrettyPrinter()
.writer(new DruidPrettyPrinter())
.writeValueAsString(payload.getStages());
str = str.replaceAll(taskId, "<taskId>");
DruidHook.dispatch(DruidHook.MSQ_PLAN, str);

View File

@ -40,39 +40,23 @@ order by 1;
"type" : "inputNumber",
"inputNumber" : 0
},
"intervals" : {
"type" : "intervals",
"intervals" : [ "-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z" ]
},
"intervals" : {"type" : "intervals","intervals" : [ "-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z" ]},
"filter" : {
"type" : "inType",
"column" : "cityName",
"matchValueType" : "STRING",
"sortedValues" : [ "Aarhus", "New York" ]
},
"granularity" : {
"type" : "all"
},
"dimensions" : [ {
"type" : "default",
"dimension" : "cityName",
"outputName" : "d0",
"outputType" : "STRING"
} ],
"granularity" : {"type" : "all"},
"dimensions" : [ {"type" : "default","dimension" : "cityName","outputName" : "d0","outputType" : "STRING"} ],
"aggregations" : [ {
"type" : "filtered",
"aggregator" : {
"type" : "count",
"name" : "a0"
},
"aggregator" : {"type" : "count","name" : "a0"},
"filter" : {
"type" : "and",
"fields" : [ {
"type" : "not",
"field" : {
"type" : "null",
"column" : "channel"
}
"field" : {"type" : "null","column" : "channel"}
}, {
"type" : "range",
"column" : "delta",
@ -82,33 +66,19 @@ order by 1;
} ]
},
"name" : "a0"
}, {
"type" : "count",
"name" : "a1"
} ],
"limitSpec" : {
"type" : "NoopLimitSpec"
},
}, {"type" : "count","name" : "a1"} ],
"limitSpec" : {"type" : "NoopLimitSpec"},
"context" : {
"__user" : null,
"finalize" : true,
"maxParseExceptions" : 0,
"plannerStrategy" : "DECOUPLED",
"sqlQueryId" : "dd89814f-71a0-4968-ae18-7fb16b354a42",
"sqlQueryId" : "1a672bac-af09-4c2b-b7fb-3dec3bf248f5",
"sqlStringifyArrays" : false
}
}
},
"signature" : [ {
"name" : "d0",
"type" : "STRING"
}, {
"name" : "a0",
"type" : "LONG"
}, {
"name" : "a1",
"type" : "LONG"
} ],
"signature" : [ {"name" : "d0","type" : "STRING"}, {"name" : "a0","type" : "LONG"}, {"name" : "a1","type" : "LONG"} ],
"shuffleSpec" : {
"type" : "maxCount",
"clusterBy" : {
@ -127,8 +97,8 @@ order by 1;
"partitionCount" : 1,
"shuffle" : "globalSort",
"output" : "localStorage",
"startTime" : "2024-07-19T11:35:14.021Z",
"duration" : 727,
"startTime" : "2024-07-24T17:13:03.981Z",
"duration" : 692,
"sort" : true
}, {
"stageNumber" : 1,
@ -146,39 +116,23 @@ order by 1;
"type" : "inputNumber",
"inputNumber" : 0
},
"intervals" : {
"type" : "intervals",
"intervals" : [ "-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z" ]
},
"intervals" : {"type" : "intervals","intervals" : [ "-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z" ]},
"filter" : {
"type" : "inType",
"column" : "cityName",
"matchValueType" : "STRING",
"sortedValues" : [ "Aarhus", "New York" ]
},
"granularity" : {
"type" : "all"
},
"dimensions" : [ {
"type" : "default",
"dimension" : "cityName",
"outputName" : "d0",
"outputType" : "STRING"
} ],
"granularity" : {"type" : "all"},
"dimensions" : [ {"type" : "default","dimension" : "cityName","outputName" : "d0","outputType" : "STRING"} ],
"aggregations" : [ {
"type" : "filtered",
"aggregator" : {
"type" : "count",
"name" : "a0"
},
"aggregator" : {"type" : "count","name" : "a0"},
"filter" : {
"type" : "and",
"fields" : [ {
"type" : "not",
"field" : {
"type" : "null",
"column" : "channel"
}
"field" : {"type" : "null","column" : "channel"}
}, {
"type" : "range",
"column" : "delta",
@ -188,43 +142,31 @@ order by 1;
} ]
},
"name" : "a0"
}, {
"type" : "count",
"name" : "a1"
} ],
"limitSpec" : {
"type" : "NoopLimitSpec"
},
}, {"type" : "count","name" : "a1"} ],
"limitSpec" : {"type" : "NoopLimitSpec"},
"context" : {
"__user" : null,
"finalize" : true,
"maxParseExceptions" : 0,
"plannerStrategy" : "DECOUPLED",
"sqlQueryId" : "dd89814f-71a0-4968-ae18-7fb16b354a42",
"sqlQueryId" : "1a672bac-af09-4c2b-b7fb-3dec3bf248f5",
"sqlStringifyArrays" : false
}
}
},
"signature" : [ {
"name" : "d0",
"type" : "STRING"
}, {
"name" : "a0",
"type" : "LONG"
}, {
"name" : "a1",
"type" : "LONG"
} ],
"signature" : [ {"name" : "d0","type" : "STRING"}, {"name" : "a0","type" : "LONG"}, {"name" : "a1","type" : "LONG"} ],
"maxWorkerCount" : 1
},
"phase" : "FINISHED",
"workerCount" : 1,
"partitionCount" : 1,
"output" : "localStorage",
"startTime" : "2024-07-19T11:35:14.748Z",
"startTime" : "2024-07-24T17:13:04.672Z",
"duration" : 2
} ]tid:query-dd89814f-71a0-4968-ae18-7fb16b354a42
} ]
!msqPlan
# 227
LogicalSort(sort0=[$0], dir0=[ASC])
LogicalAggregate(group=[{0}], cnt=[COUNT($1)], aall=[COUNT()])
LogicalProject(cityName=[$2], $f1=[CASE(>($17, 0), $1, null:VARCHAR)])

View File

@ -21,6 +21,7 @@ package org.apache.druid.java.util.common.granularity;
import com.google.common.collect.ImmutableList;
import org.apache.druid.java.util.common.DateTimes;
import org.apache.druid.sql.avatica.DruidPrettyPrinter.Inline;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.format.DateTimeFormatter;
@ -28,6 +29,7 @@ import org.joda.time.format.DateTimeFormatter;
/**
* AllGranularty buckets everything into a single bucket
*/
@Inline
public class AllGranularity extends Granularity
{
/**

View File

@ -20,6 +20,7 @@
package org.apache.druid.java.util.common.granularity;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.primitives.Longs;
import org.apache.druid.java.util.common.Cacheable;
import org.apache.druid.java.util.common.DateTimes;
@ -155,6 +156,7 @@ public abstract class Granularity implements Cacheable
*/
public abstract boolean isAligned(Interval interval);
@JsonIgnore
public DateTimeZone getTimeZone()
{
return DateTimeZone.UTC;

View File

@ -26,6 +26,7 @@ import com.google.common.base.Preconditions;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.query.planning.DataSourceAnalysis;
import org.apache.druid.segment.SegmentReference;
import org.apache.druid.sql.avatica.DruidPrettyPrinter.Inline;
import java.util.Collections;
import java.util.List;
@ -35,6 +36,7 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
@JsonTypeName("table")
@Inline
public class TableDataSource implements DataSource
{
private final String name;

View File

@ -27,6 +27,7 @@ import org.apache.druid.segment.ColumnInspector;
import org.apache.druid.segment.ColumnSelectorFactory;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.vector.VectorColumnSelectorFactory;
import org.apache.druid.sql.avatica.DruidPrettyPrinter.Inline;
import javax.annotation.Nullable;
import java.util.Comparator;
@ -34,6 +35,7 @@ import java.util.List;
/**
*/
@Inline
public class CountAggregatorFactory extends AggregatorFactory
{
private final String name;

View File

@ -27,6 +27,7 @@ import org.apache.druid.segment.DimensionSelector;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.vector.MultiValueDimensionVectorSelector;
import org.apache.druid.segment.vector.SingleValueDimensionVectorSelector;
import org.apache.druid.sql.avatica.DruidPrettyPrinter.Inline;
import javax.annotation.Nullable;
import java.util.Objects;
@ -34,6 +35,7 @@ import java.util.Objects;
/**
*
*/
@Inline
public class DefaultDimensionSpec implements DimensionSpec
{
public static DefaultDimensionSpec of(String dimensionName)

View File

@ -25,7 +25,6 @@ import com.google.common.collect.RangeSet;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.java.util.common.Cacheable;
import org.apache.druid.query.extraction.ExtractionFn;
import javax.annotation.Nullable;
import java.util.Set;

View File

@ -43,12 +43,14 @@ import org.apache.druid.segment.index.BitmapColumnIndex;
import org.apache.druid.segment.index.semantic.DruidPredicateIndexes;
import org.apache.druid.segment.index.semantic.NullValueIndex;
import org.apache.druid.segment.vector.VectorColumnSelectorFactory;
import org.apache.druid.sql.avatica.DruidPrettyPrinter.Inline;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@Inline
public class NullFilter extends AbstractOptimizableDimFilter implements Filter
{
public static NullFilter forColumn(String column)

View File

@ -25,12 +25,14 @@ import com.google.common.base.Functions;
import org.apache.druid.java.util.common.guava.Sequence;
import org.apache.druid.query.groupby.GroupByQuery;
import org.apache.druid.query.groupby.ResultRow;
import org.apache.druid.sql.avatica.DruidPrettyPrinter.Inline;
import java.util.Set;
/**
*
*/
@Inline
public final class NoopLimitSpec implements LimitSpec
{
private static final byte CACHE_KEY = 0x0;

View File

@ -25,6 +25,7 @@ import org.apache.druid.java.util.common.JodaUtils;
import org.apache.druid.query.Query;
import org.apache.druid.query.QueryRunner;
import org.apache.druid.query.QuerySegmentWalker;
import org.apache.druid.sql.avatica.DruidPrettyPrinter.Inline;
import org.joda.time.Interval;
import java.util.List;
@ -32,6 +33,7 @@ import java.util.Objects;
/**
*/
@Inline
public class MultipleIntervalSegmentSpec implements QuerySegmentSpec
{
private final List<Interval> intervals;

View File

@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.sql.avatica.DruidPrettyPrinter;
import javax.annotation.Nullable;
@ -32,6 +33,7 @@ import javax.annotation.Nullable;
* Package-private since it is not intended to be used outside that narrow use case. In other cases where passing
* around information about column types is important, use {@link ColumnType} instead.
*/
@DruidPrettyPrinter.Inline
public /*FIXME*/ class ColumnSignature
{
private final String name;

View File

@ -0,0 +1,112 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.sql.avatica;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Druid specific pretty printer which makes it more readable.
*/
public class DruidPrettyPrinter extends DefaultPrettyPrinter
{
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public static @interface Inline
{
}
private static final long serialVersionUID = 1L;
private boolean currentIndent = true;
@Override
public DefaultPrettyPrinter createInstance()
{
return new DruidPrettyPrinter();
}
public DruidPrettyPrinter()
{
_objectIndenter = new DruidIndenter(this::shouldIndent);
}
public boolean shouldIndent(JsonStreamContext ctx)
{
return currentIndent ;
}
@Override
public void writeStartObject(JsonGenerator g) throws IOException
{
currentIndent = shouldIndentObject(g.getOutputContext());
super.writeStartObject(g);
}
@Override
public void writeEndObject(JsonGenerator g, int nrOfEntries) throws IOException
{
super.writeEndObject(g, nrOfEntries);
currentIndent = true;
}
public boolean shouldIndentObject(JsonStreamContext ctx)
{
Object value = ctx.getCurrentValue();
Object annotation = value.getClass().getAnnotation(Inline.class);
if (annotation != null) {
return false;
}
return true;
}
static class DruidIndenter implements Indenter
{
private static final Indenter DEFAULT_INDENTER = DefaultIndenter.SYSTEM_LINEFEED_INSTANCE;
private java.util.function.Predicate<JsonStreamContext> predicate;
public DruidIndenter(java.util.function.Predicate<JsonStreamContext> predicate)
{
this.predicate = predicate;
}
@Override
public void writeIndentation(JsonGenerator g, int level) throws IOException
{
if (predicate.test(g.getOutputContext()) || level < -11) {
DEFAULT_INDENTER.writeIndentation(g, level);
}
}
@Override
public boolean isInline()
{
return false;
}
}
}

View File

@ -0,0 +1,92 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.sql.avatica;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import org.apache.druid.jackson.DefaultObjectMapper;
import org.apache.druid.query.groupby.orderby.LimitSpec;
import org.apache.druid.query.groupby.orderby.NoopLimitSpec;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.RowSignature;
import org.junit.Test;
import java.util.List;
public class DruidPrettyPrinterTest
{
static class TwoInlined
{
@JsonProperty
final LimitSpec limitSpec = NoopLimitSpec.INSTANCE;
@JsonProperty
final LimitSpec limitSpec2 = NoopLimitSpec.INSTANCE;
}
@Test
public void prettyPrintTwoInlined() throws Exception
{
ObjectMapper om = new DefaultObjectMapper();
ObjectWriter w = om.writer(new DruidPrettyPrinter());
String s = w.writeValueAsString(new TwoInlined());
System.out.println(s);
}
static class SampleClass
{
@JsonProperty
final RowSignature rowSignature;
@JsonProperty
final LimitSpec limitSpec;
@JsonProperty
final LimitSpec limitSpec2;
public SampleClass(RowSignature rs, LimitSpec ls)
{
this.rowSignature = rs;
this.limitSpec = ls;
this.limitSpec2 = ls;
}
}
@Test
public void prettyPrint1() throws Exception
{
ObjectMapper om = new DefaultObjectMapper();
ObjectWriter w = om.writer(new DruidPrettyPrinter());
final RowSignature.Builder builder = RowSignature.builder()
.add("s", ColumnType.STRING)
.add("d", ColumnType.DOUBLE)
.add("d1", ColumnType.LONG);
List<org.apache.druid.segment.column.ColumnSignature> cs = builder.build().asColumnSignatures();
String s = w.writeValueAsString(new SampleClass(builder.build(), NoopLimitSpec.INSTANCE));
System.out.println(s);
}
}

View File

@ -77,8 +77,8 @@ public class A11
{
Object v = g.getCurrentValue();
return v instanceof ColumnSignature;
// return false;
// return v instanceof ColumnSignature;
return false;
// return v instanceof RowSignature;
// return g.getCurrentValue() instanceof List;

View File

@ -51,10 +51,9 @@ public class A12
private DefaultPrettyPrinter.Indenter getDelegate()
{
if (isInside) {
return new DefaultPrettyPrinter.NopIndenter();
return DefaultPrettyPrinter.NopIndenter.instance;
} else {
return DefaultIndenter.SYSTEM_LINEFEED_INSTANCE;
}
}