From 45e31115495838b3327e0fff1d21bee0adf31132 Mon Sep 17 00:00:00 2001 From: Paul Rogers Date: Wed, 15 Jun 2022 11:31:22 -0700 Subject: [PATCH] Clean up query contexts (#12633) * Clean up query contexts Uses constants in place of literal strings for context keys. Moves some QueryContext methods to QueryContexts for reuse. * Revisions from review comments --- .../org/apache/druid/query/BaseQuery.java | 10 +- .../query/FinalizeResultsQueryRunner.java | 2 +- .../org/apache/druid/query/QueryContext.java | 37 +---- .../org/apache/druid/query/QueryContexts.java | 133 +++++++++++++++--- .../groupby/strategy/GroupByStrategyV1.java | 3 +- .../groupby/strategy/GroupByStrategyV2.java | 2 +- .../apache/druid/query/QueryContextsTest.java | 57 +++++++- .../DataSourceMetadataQueryTest.java | 20 +-- .../query/groupby/GroupByQueryRunnerTest.java | 2 +- .../timeboundary/TimeBoundaryQueryTest.java | 28 ++-- .../client/CachingClusteredClientTest.java | 5 +- 11 files changed, 209 insertions(+), 90 deletions(-) diff --git a/processing/src/main/java/org/apache/druid/query/BaseQuery.java b/processing/src/main/java/org/apache/druid/query/BaseQuery.java index 5c9ca69ab80..794dfc204bf 100644 --- a/processing/src/main/java/org/apache/druid/query/BaseQuery.java +++ b/processing/src/main/java/org/apache/druid/query/BaseQuery.java @@ -35,10 +35,10 @@ import org.joda.time.Duration; import org.joda.time.Interval; import javax.annotation.Nullable; + import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.TreeMap; /** * @@ -210,13 +210,7 @@ public abstract class BaseQuery implements Query final Map overrides ) { - Map overridden = new TreeMap<>(); - if (context != null) { - overridden.putAll(context); - } - overridden.putAll(overrides); - - return overridden; + return QueryContexts.override(context, overrides); } /** diff --git a/processing/src/main/java/org/apache/druid/query/FinalizeResultsQueryRunner.java b/processing/src/main/java/org/apache/druid/query/FinalizeResultsQueryRunner.java index d63dcdd88de..e73b9cc4619 100644 --- a/processing/src/main/java/org/apache/druid/query/FinalizeResultsQueryRunner.java +++ b/processing/src/main/java/org/apache/druid/query/FinalizeResultsQueryRunner.java @@ -64,7 +64,7 @@ public class FinalizeResultsQueryRunner implements QueryRunner final MetricManipulationFn metricManipulationFn; if (shouldFinalize) { - queryToRun = query.withOverriddenContext(ImmutableMap.of("finalize", false)); + queryToRun = query.withOverriddenContext(ImmutableMap.of(QueryContexts.FINALIZE_KEY, false)); metricManipulationFn = MetricManipulatorFns.finalizing(); } else { queryToRun = query; diff --git a/processing/src/main/java/org/apache/druid/query/QueryContext.java b/processing/src/main/java/org/apache/druid/query/QueryContext.java index 38257e70a35..20b607f784d 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContext.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContext.java @@ -19,10 +19,8 @@ package org.apache.druid.query; -import org.apache.druid.java.util.common.IAE; -import org.apache.druid.java.util.common.Numbers; - import javax.annotation.Nullable; + import java.util.Collections; import java.util.Map; import java.util.Objects; @@ -162,16 +160,7 @@ public class QueryContext final boolean defaultValue ) { - final Object value = get(parameter); - if (value == null) { - return defaultValue; - } else if (value instanceof String) { - return Boolean.parseBoolean((String) value); - } else if (value instanceof Boolean) { - return (Boolean) value; - } else { - throw new IAE("Expected parameter[%s] to be boolean", parameter); - } + return QueryContexts.getAsBoolean(parameter, get(parameter), defaultValue); } public int getAsInt( @@ -179,30 +168,12 @@ public class QueryContext final int defaultValue ) { - final Object value = get(parameter); - if (value == null) { - return defaultValue; - } else if (value instanceof String) { - return Numbers.parseInt(value); - } else if (value instanceof Number) { - return ((Number) value).intValue(); - } else { - throw new IAE("Expected parameter[%s] to be integer", parameter); - } + return QueryContexts.getAsInt(parameter, get(parameter), defaultValue); } public long getAsLong(final String parameter, final long defaultValue) { - final Object value = get(parameter); - if (value == null) { - return defaultValue; - } else if (value instanceof String) { - return Numbers.parseLong(value); - } else if (value instanceof Number) { - return ((Number) value).longValue(); - } else { - throw new IAE("Expected parameter[%s] to be long", parameter); - } + return QueryContexts.getAsLong(parameter, get(parameter), defaultValue); } public Map getMergedParams() diff --git a/processing/src/main/java/org/apache/druid/query/QueryContexts.java b/processing/src/main/java/org/apache/druid/query/QueryContexts.java index 73bf04fcae2..d8bf22ebc7f 100644 --- a/processing/src/main/java/org/apache/druid/query/QueryContexts.java +++ b/processing/src/main/java/org/apache/druid/query/QueryContexts.java @@ -31,6 +31,7 @@ import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.segment.QueryableIndexStorageAdapter; import java.util.Map; +import java.util.TreeMap; import java.util.concurrent.TimeUnit; @PublicApi @@ -71,6 +72,12 @@ public class QueryContexts public static final String BROKER_SERVICE_NAME = "brokerService"; public static final String IN_SUB_QUERY_THRESHOLD_KEY = "inSubQueryThreshold"; public static final String TIME_BOUNDARY_PLANNING_KEY = "enableTimeBoundaryPlanning"; + public static final String POPULATE_CACHE_KEY = "populateCache"; + public static final String POPULATE_RESULT_LEVEL_CACHE_KEY = "populateResultLevelCache"; + public static final String USE_RESULT_LEVEL_CACHE_KEY = "useResultLevelCache"; + public static final String SERIALIZE_DATE_TIME_AS_LONG_KEY = "serializeDateTimeAsLong"; + public static final String SERIALIZE_DATE_TIME_AS_LONG_INNER_KEY = "serializeDateTimeAsLongInner"; + public static final String UNCOVERED_INTERVALS_LIMIT_KEY = "uncoveredIntervalsLimit"; public static final boolean DEFAULT_BY_SEGMENT = false; public static final boolean DEFAULT_POPULATE_CACHE = true; @@ -158,7 +165,7 @@ public class QueryContexts public static boolean isPopulateCache(Query query, boolean defaultValue) { - return parseBoolean(query, "populateCache", defaultValue); + return parseBoolean(query, POPULATE_CACHE_KEY, defaultValue); } public static boolean isUseCache(Query query) @@ -178,7 +185,7 @@ public class QueryContexts public static boolean isPopulateResultLevelCache(Query query, boolean defaultValue) { - return parseBoolean(query, "populateResultLevelCache", defaultValue); + return parseBoolean(query, POPULATE_RESULT_LEVEL_CACHE_KEY, defaultValue); } public static boolean isUseResultLevelCache(Query query) @@ -188,22 +195,22 @@ public class QueryContexts public static boolean isUseResultLevelCache(Query query, boolean defaultValue) { - return parseBoolean(query, "useResultLevelCache", defaultValue); + return parseBoolean(query, USE_RESULT_LEVEL_CACHE_KEY, defaultValue); } - public static boolean isFinalize(Query query, boolean defaultValue) + { return parseBoolean(query, FINALIZE_KEY, defaultValue); } public static boolean isSerializeDateTimeAsLong(Query query, boolean defaultValue) { - return parseBoolean(query, "serializeDateTimeAsLong", defaultValue); + return parseBoolean(query, SERIALIZE_DATE_TIME_AS_LONG_KEY, defaultValue); } public static boolean isSerializeDateTimeAsLongInner(Query query, boolean defaultValue) { - return parseBoolean(query, "serializeDateTimeAsLongInner", defaultValue); + return parseBoolean(query, SERIALIZE_DATE_TIME_AS_LONG_INNER_KEY, defaultValue); } public static Vectorize getVectorize(Query query) @@ -248,7 +255,7 @@ public class QueryContexts public static int getUncoveredIntervalsLimit(Query query, int defaultValue) { - return parseInt(query, "uncoveredIntervalsLimit", defaultValue); + return parseInt(query, UNCOVERED_INTERVALS_LIMIT_KEY, defaultValue); } public static int getPriority(Query query) @@ -450,32 +457,124 @@ public class QueryContexts static long parseLong(Query query, String key, long defaultValue) { - final Object val = query.getContextValue(key); - return val == null ? defaultValue : Numbers.parseLong(val); + return getAsLong(key, query.getContextValue(key), defaultValue); + } + + @SuppressWarnings("unused") + static long parseLong(Map context, String key, long defaultValue) + { + return getAsLong(key, context.get(key), defaultValue); } static int parseInt(Query query, String key, int defaultValue) { - final Object val = query.getContextValue(key); - return val == null ? defaultValue : Numbers.parseInt(val); + return getAsInt(key, query.getContextValue(key), defaultValue); } static int parseInt(Map context, String key, int defaultValue) { - final Object val = context.get(key); - return val == null ? defaultValue : Numbers.parseInt(val); + return getAsInt(key, context.get(key), defaultValue); } static boolean parseBoolean(Query query, String key, boolean defaultValue) { - final Object val = query.getContextValue(key); - return val == null ? defaultValue : Numbers.parseBoolean(val); + return getAsBoolean(key, query.getContextValue(key), defaultValue); } static boolean parseBoolean(Map context, String key, boolean defaultValue) { - final Object val = context.get(key); - return val == null ? defaultValue : Numbers.parseBoolean(val); + return getAsBoolean(key, context.get(key), defaultValue); + } + + public static String getAsString( + final String parameter, + final Object value, + final String defaultValue + ) + { + if (value == null) { + return defaultValue; + } else if (value instanceof String) { + return (String) value; + } else { + throw new IAE("Expected parameter [%s] to be String", parameter); + } + } + + /** + * Get the value of a parameter as a {@code boolean}. The parameter is expected + * to be {@code null}, a string or a {@code Boolean} object. + */ + public static boolean getAsBoolean( + final String parameter, + final Object value, + final boolean defaultValue + ) + { + if (value == null) { + return defaultValue; + } else if (value instanceof String) { + return Boolean.parseBoolean((String) value); + } else if (value instanceof Boolean) { + return (Boolean) value; + } else { + throw new IAE("Expected parameter [%s] to be a boolean", parameter); + } + } + + /** + * Get the value of a parameter as an {@code int}. The parameter is expected + * to be {@code null}, a string or a {@code Number} object. + */ + public static int getAsInt( + final String parameter, + final Object value, + final int defaultValue + ) + { + if (value == null) { + return defaultValue; + } else if (value instanceof String) { + return Numbers.parseInt(value); + } else if (value instanceof Number) { + return ((Number) value).intValue(); + } else { + throw new IAE("Expected parameter [%s] to be an integer", parameter); + } + } + + /** + * Get the value of a parameter as an {@code long}. The parameter is expected + * to be {@code null}, a string or a {@code Number} object. + */ + public static long getAsLong( + final String parameter, + final Object value, + final long defaultValue) + { + if (value == null) { + return defaultValue; + } else if (value instanceof String) { + return Numbers.parseLong(value); + } else if (value instanceof Number) { + return ((Number) value).longValue(); + } else { + throw new IAE("Expected parameter [%s] to be a long", parameter); + } + } + + public static Map override( + final Map context, + final Map overrides + ) + { + Map overridden = new TreeMap<>(); + if (context != null) { + overridden.putAll(context); + } + overridden.putAll(overrides); + + return overridden; } private QueryContexts() diff --git a/processing/src/main/java/org/apache/druid/query/groupby/strategy/GroupByStrategyV1.java b/processing/src/main/java/org/apache/druid/query/groupby/strategy/GroupByStrategyV1.java index aeb3d2b8005..bc475514f61 100644 --- a/processing/src/main/java/org/apache/druid/query/groupby/strategy/GroupByStrategyV1.java +++ b/processing/src/main/java/org/apache/druid/query/groupby/strategy/GroupByStrategyV1.java @@ -30,6 +30,7 @@ import org.apache.druid.java.util.common.IAE; import org.apache.druid.java.util.common.guava.Sequence; import org.apache.druid.java.util.common.guava.Sequences; import org.apache.druid.query.GroupByMergedQueryRunner; +import org.apache.druid.query.QueryContexts; import org.apache.druid.query.QueryPlus; import org.apache.druid.query.QueryProcessingPool; import org.apache.druid.query.QueryRunner; @@ -115,7 +116,7 @@ public class GroupByStrategyV1 implements GroupByStrategy .overrideContext( ImmutableMap.builder() .put(GroupByQueryConfig.CTX_KEY_STRATEGY, GroupByStrategySelector.STRATEGY_V1) - .put("finalize", false) + .put(QueryContexts.FINALIZE_KEY, false) // Always request array result rows when passing the query down. .put(GroupByQueryConfig.CTX_KEY_ARRAY_RESULT_ROWS, true) diff --git a/processing/src/main/java/org/apache/druid/query/groupby/strategy/GroupByStrategyV2.java b/processing/src/main/java/org/apache/druid/query/groupby/strategy/GroupByStrategyV2.java index abb5cdf65da..c4ee7613f7d 100644 --- a/processing/src/main/java/org/apache/druid/query/groupby/strategy/GroupByStrategyV2.java +++ b/processing/src/main/java/org/apache/druid/query/groupby/strategy/GroupByStrategyV2.java @@ -214,7 +214,7 @@ public class GroupByStrategyV2 implements GroupByStrategy // Set up downstream context. final ImmutableMap.Builder context = ImmutableMap.builder(); - context.put("finalize", false); + context.put(QueryContexts.FINALIZE_KEY, false); context.put(GroupByQueryConfig.CTX_KEY_STRATEGY, GroupByStrategySelector.STRATEGY_V2); context.put(CTX_KEY_OUTERMOST, false); diff --git a/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java b/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java index c9f0c8b482a..f5ab7afb264 100644 --- a/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java +++ b/processing/src/test/java/org/apache/druid/query/QueryContextsTest.java @@ -44,7 +44,7 @@ public class QueryContextsTest new TableDataSource("test"), new MultipleIntervalSegmentSpec(ImmutableList.of(Intervals.of("0/100"))), false, - new HashMap() + new HashMap<>() ); Assert.assertEquals(300_000, QueryContexts.getDefaultTimeout(query)); } @@ -56,7 +56,7 @@ public class QueryContextsTest new TableDataSource("test"), new MultipleIntervalSegmentSpec(ImmutableList.of(Intervals.of("0/100"))), false, - new HashMap() + new HashMap<>() ); Assert.assertEquals(300_000, QueryContexts.getTimeout(query)); @@ -206,4 +206,57 @@ public class QueryContextsTest Assert.assertTrue(QueryContexts.isDebug(query)); Assert.assertTrue(QueryContexts.isDebug(query.getContext())); } + + @Test + public void testGetAs() + { + Assert.assertNull(QueryContexts.getAsString("foo", null, null)); + Assert.assertEquals("default", QueryContexts.getAsString("foo", null, "default")); + Assert.assertEquals("value", QueryContexts.getAsString("foo", "value", "default")); + try { + QueryContexts.getAsString("foo", 10, null); + Assert.fail(); + } + catch (IAE e) { + // Expected + } + + Assert.assertFalse(QueryContexts.getAsBoolean("foo", null, false)); + Assert.assertTrue(QueryContexts.getAsBoolean("foo", null, true)); + Assert.assertTrue(QueryContexts.getAsBoolean("foo", "true", false)); + Assert.assertTrue(QueryContexts.getAsBoolean("foo", true, false)); + try { + QueryContexts.getAsBoolean("foo", 10, false); + Assert.fail(); + } + catch (IAE e) { + // Expected + } + + Assert.assertEquals(10, QueryContexts.getAsInt("foo", null, 10)); + Assert.assertEquals(20, QueryContexts.getAsInt("foo", "20", 10)); + Assert.assertEquals(20, QueryContexts.getAsInt("foo", 20, 10)); + Assert.assertEquals(20, QueryContexts.getAsInt("foo", 20L, 10)); + Assert.assertEquals(20, QueryContexts.getAsInt("foo", 20D, 10)); + try { + QueryContexts.getAsInt("foo", true, 20); + Assert.fail(); + } + catch (IAE e) { + // Expected + } + + Assert.assertEquals(10L, QueryContexts.getAsLong("foo", null, 10)); + Assert.assertEquals(20L, QueryContexts.getAsLong("foo", "20", 10)); + Assert.assertEquals(20L, QueryContexts.getAsLong("foo", 20, 10)); + Assert.assertEquals(20L, QueryContexts.getAsLong("foo", 20L, 10)); + Assert.assertEquals(20L, QueryContexts.getAsLong("foo", 20D, 10)); + try { + QueryContexts.getAsLong("foo", true, 20); + Assert.fail(); + } + catch (IAE e) { + // Expected + } + } } diff --git a/processing/src/test/java/org/apache/druid/query/datasourcemetadata/DataSourceMetadataQueryTest.java b/processing/src/test/java/org/apache/druid/query/datasourcemetadata/DataSourceMetadataQueryTest.java index d4caf89e757..97958818c9d 100644 --- a/processing/src/test/java/org/apache/druid/query/datasourcemetadata/DataSourceMetadataQueryTest.java +++ b/processing/src/test/java/org/apache/druid/query/datasourcemetadata/DataSourceMetadataQueryTest.java @@ -79,13 +79,13 @@ public class DataSourceMetadataQueryTest .intervals("2013/2014") .context( ImmutableMap.of( - "priority", + QueryContexts.PRIORITY_KEY, 1, - "useCache", + QueryContexts.USE_CACHE_KEY, true, - "populateCache", + QueryContexts.POPULATE_CACHE_KEY, "true", - "finalize", + QueryContexts.FINALIZE_KEY, true ) ).build(); @@ -103,12 +103,12 @@ public class DataSourceMetadataQueryTest ); Assert.assertEquals((Integer) 1, serdeQuery.getContextValue(QueryContexts.PRIORITY_KEY)); - Assert.assertEquals(true, serdeQuery.getContextValue("useCache")); - Assert.assertEquals("true", serdeQuery.getContextValue("populateCache")); - Assert.assertEquals(true, serdeQuery.getContextValue("finalize")); - Assert.assertEquals(true, serdeQuery.getContextBoolean("useCache", false)); - Assert.assertEquals(true, serdeQuery.getContextBoolean("populateCache", false)); - Assert.assertEquals(true, serdeQuery.getContextBoolean("finalize", false)); + Assert.assertEquals(true, serdeQuery.getContextValue(QueryContexts.USE_CACHE_KEY)); + Assert.assertEquals("true", serdeQuery.getContextValue(QueryContexts.POPULATE_CACHE_KEY)); + Assert.assertEquals(true, serdeQuery.getContextValue(QueryContexts.FINALIZE_KEY)); + Assert.assertEquals(true, serdeQuery.getContextBoolean(QueryContexts.USE_CACHE_KEY, false)); + Assert.assertEquals(true, serdeQuery.getContextBoolean(QueryContexts.POPULATE_CACHE_KEY, false)); + Assert.assertEquals(true, serdeQuery.getContextBoolean(QueryContexts.FINALIZE_KEY, false)); } @Test diff --git a/processing/src/test/java/org/apache/druid/query/groupby/GroupByQueryRunnerTest.java b/processing/src/test/java/org/apache/druid/query/groupby/GroupByQueryRunnerTest.java index 5426f483020..4a3a0b5cf4d 100644 --- a/processing/src/test/java/org/apache/druid/query/groupby/GroupByQueryRunnerTest.java +++ b/processing/src/test/java/org/apache/druid/query/groupby/GroupByQueryRunnerTest.java @@ -7524,7 +7524,7 @@ public class GroupByQueryRunnerTest extends InitializedNullHandlingTest new LongLastAggregatorFactory("innerlast", "index", null) ) .setGranularity(QueryRunnerTestHelper.DAY_GRAN) - .overrideContext(ImmutableMap.of("finalize", true)) + .overrideContext(ImmutableMap.of(QueryContexts.FINALIZE_KEY, true)) .build(); GroupByQuery query = makeQueryBuilder() diff --git a/processing/src/test/java/org/apache/druid/query/timeboundary/TimeBoundaryQueryTest.java b/processing/src/test/java/org/apache/druid/query/timeboundary/TimeBoundaryQueryTest.java index 925eed2af77..868e83392db 100644 --- a/processing/src/test/java/org/apache/druid/query/timeboundary/TimeBoundaryQueryTest.java +++ b/processing/src/test/java/org/apache/druid/query/timeboundary/TimeBoundaryQueryTest.java @@ -55,13 +55,13 @@ public class TimeBoundaryQueryTest .intervals("2013/2014") .context( ImmutableMap.of( - "priority", + QueryContexts.PRIORITY_KEY, 1, - "useCache", + QueryContexts.USE_CACHE_KEY, true, - "populateCache", + QueryContexts.POPULATE_CACHE_KEY, true, - "finalize", + QueryContexts.FINALIZE_KEY, true ) ).build(); @@ -80,9 +80,9 @@ public class TimeBoundaryQueryTest Assert.assertEquals(new Integer(1), serdeQuery.getContextValue(QueryContexts.PRIORITY_KEY)); - Assert.assertEquals(true, serdeQuery.getContextValue("useCache")); - Assert.assertEquals(true, serdeQuery.getContextValue("populateCache")); - Assert.assertEquals(true, serdeQuery.getContextValue("finalize")); + Assert.assertEquals(true, serdeQuery.getContextValue(QueryContexts.USE_CACHE_KEY)); + Assert.assertEquals(true, serdeQuery.getContextValue(QueryContexts.POPULATE_CACHE_KEY)); + Assert.assertEquals(true, serdeQuery.getContextValue(QueryContexts.FINALIZE_KEY)); } @Test @@ -93,13 +93,13 @@ public class TimeBoundaryQueryTest .intervals("2013/2014") .context( ImmutableMap.of( - "priority", + QueryContexts.PRIORITY_KEY, "1", - "useCache", + QueryContexts.USE_CACHE_KEY, "true", - "populateCache", + QueryContexts.POPULATE_CACHE_KEY, "true", - "finalize", + QueryContexts.FINALIZE_KEY, "true" ) ).build(); @@ -118,8 +118,8 @@ public class TimeBoundaryQueryTest Assert.assertEquals("1", serdeQuery.getContextValue(QueryContexts.PRIORITY_KEY)); - Assert.assertEquals("true", serdeQuery.getContextValue("useCache")); - Assert.assertEquals("true", serdeQuery.getContextValue("populateCache")); - Assert.assertEquals("true", serdeQuery.getContextValue("finalize")); + Assert.assertEquals("true", serdeQuery.getContextValue(QueryContexts.USE_CACHE_KEY)); + Assert.assertEquals("true", serdeQuery.getContextValue(QueryContexts.POPULATE_CACHE_KEY)); + Assert.assertEquals("true", serdeQuery.getContextValue(QueryContexts.FINALIZE_KEY)); } } diff --git a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java index e9e295f6e18..ac9afb8958d 100644 --- a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java +++ b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java @@ -96,6 +96,7 @@ import org.apache.druid.query.filter.InDimFilter; import org.apache.druid.query.filter.OrDimFilter; import org.apache.druid.query.filter.SelectorDimFilter; import org.apache.druid.query.groupby.GroupByQuery; +import org.apache.druid.query.groupby.GroupByQueryConfig; import org.apache.druid.query.groupby.ResultRow; import org.apache.druid.query.groupby.strategy.GroupByStrategySelector; import org.apache.druid.query.ordering.StringComparators; @@ -179,10 +180,10 @@ import java.util.stream.IntStream; public class CachingClusteredClientTest { private static final ImmutableMap CONTEXT = ImmutableMap.of( - "finalize", false, + QueryContexts.FINALIZE_KEY, false, // GroupBy v2 won't cache on the broker, so test with v1. - "groupByStrategy", GroupByStrategySelector.STRATEGY_V1 + GroupByQueryConfig.CTX_KEY_STRATEGY, GroupByStrategySelector.STRATEGY_V1 ); private static final MultipleIntervalSegmentSpec SEG_SPEC = new MultipleIntervalSegmentSpec(ImmutableList.of()); private static final String DATA_SOURCE = "test";