Skip to content

Commit

Permalink
Support custom Druid queries. (#57)
Browse files Browse the repository at this point in the history
--`QueryType` has been turned into an interface backed by an enum.

--The `DruidResponseParser` and `DruidQueryBuilder` are now injectable.
  • Loading branch information
archolewa authored Oct 6, 2016
1 parent 76f81bf commit bae3fb3
Show file tree
Hide file tree
Showing 20 changed files with 194 additions and 117 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ Current

### Changed:

- [Fili now supports custom Druid query types](https://github.com/yahoo/fili/pull/57)
* `QueryType` has been turned into an interface, backed by an enum `DefaultQueryType`.
- The default implementations of `DruidResponseParser` `DruidQueryBuilder`, `WeightEvaluationQuery` and
`TestDruidWebService` only support `DefaultQueryType`.
* `DruidResponseParser` is now injectable by overriding `AbstractBinderFactory::buildDruidResponseParser` method.
* `DruidQueryBuilder` is now injectable by overriding `AbstractBinderFactory::buildDruidQueryBuilder` method.

- [Updated commons-collections4 dependency from 4.0 to 4.1 to address a security vulnerability in the library.](https://github.com/yahoo/fili/pull/52)
* For details see: https://commons.apache.org/proper/commons-collections/security-reports.html#Apache_Commons_Collections_Security_Vulnerabilities
* It should be noted that Fili does not make use of any the serialization/deserialization capabilities of any classes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,9 @@ protected void configure() {
bind(getGranularityParser()).to(GranularityParser.class);

// Bind the request building action classes for druid
bind(DruidQueryBuilder.class).to(DruidQueryBuilder.class);
bind(buildDruidQueryBuilder()).to(DruidQueryBuilder.class);
bind(TemplateDruidQueryMerger.class).to(TemplateDruidQueryMerger.class);
bind(DruidResponseParser.class).to(DruidResponseParser.class);
bind(buildDruidResponseParser()).to(DruidResponseParser.class);
bind(buildDruidFilterBuilder()).to(DruidFilterBuilder.class);

//Initialize the field converter
Expand Down Expand Up @@ -321,6 +321,24 @@ protected void configure() {
};
}

/**
* Initializes the factory that builds druid queries.
*
* @return An isntance of the {@link DruidQueryBuilder}
*/
protected Class<DruidQueryBuilder> buildDruidQueryBuilder() {
return DruidQueryBuilder.class;
}

/**
* Initializes the class that parses responses from Druid.
*
* @return An instance of the {@link DruidResponseParser}
*/
protected Class<DruidResponseParser> buildDruidResponseParser() {
return DruidResponseParser.class;
}

/**
* Returns a clock for generating instants for timestamps.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.yahoo.bard.webservice.data.dimension.DimensionRow;
import com.yahoo.bard.webservice.data.metric.MetricColumn;
import com.yahoo.bard.webservice.druid.model.QueryType;
import com.yahoo.bard.webservice.druid.model.DefaultQueryType;
import com.yahoo.bard.webservice.table.ZonedSchema;

import com.fasterxml.jackson.databind.JsonNode;
Expand Down Expand Up @@ -38,20 +39,27 @@ public class DruidResponseParser {
*
* @param jsonResult Druid results in json
* @param schema Schema for results
* @param queryType the type of query
* @param queryType the type of query, note that this implementation only supports instances of
* {@link DefaultQueryType}
*
* @return the set of results
*/
public ResultSet parse(JsonNode jsonResult, ZonedSchema schema, QueryType queryType) {

LOG.trace("Parsing druid query {} by json result: {} using schema: {}", queryType, jsonResult, schema);

if (!(queryType instanceof DefaultQueryType)) {
// Throw an exception for unsupported query types
unsupportedQueryType(queryType);
}
DefaultQueryType defaultQueryType = (DefaultQueryType) queryType;

/* Get dimension and metric columns */
Set<DimensionColumn> dimensionColumns = schema.getColumns(DimensionColumn.class);
Set<MetricColumn> metricColumns = schema.getColumns(MetricColumn.class);

List<Result> results;
switch (queryType) {
List<Result> results = null;
switch (defaultQueryType) {
case GROUP_BY:
results = makeGroupByResults(jsonResult, dimensionColumns, metricColumns, schema.getDateTimeZone());
break;
Expand All @@ -65,15 +73,25 @@ public ResultSet parse(JsonNode jsonResult, ZonedSchema schema, QueryType queryT
results = makeLookbackResults(jsonResult, dimensionColumns, metricColumns, schema.getDateTimeZone());
break;
default:
String msg = RESULT_SET_ERROR.logFormat(queryType);
LOG.error(msg);
throw new UnsupportedOperationException(msg);
// Throw an exception for unsupported query types
unsupportedQueryType(queryType);
}

LOG.trace("Parsed druid query {} results: {}", queryType, results);
return new ResultSet(results, schema);
}

/**
* Log an error message and throw an exception for an unsupported query type.
*
* @param queryType The query type that is not supported
*/
private void unsupportedQueryType(QueryType queryType) {
String msg = RESULT_SET_ERROR.logFormat(queryType);
LOG.error(msg);
throw new UnsupportedOperationException(msg);
}

/**
* Create a list of results from a JsonNode of a groupBy response.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms.
package com.yahoo.bard.webservice.druid.model;

import com.yahoo.bard.webservice.util.EnumUtils;

/**
* Druid queries that Fili supports out o the box.
*/
public enum DefaultQueryType implements QueryType {
GROUP_BY,
TOP_N,
TIMESERIES,
TIME_BOUNDARY,
SEGMENT_METADATA,
SEARCH,
LOOKBACK;

final String jsonName;

/**
* Constructor.
*/
DefaultQueryType() {
this.jsonName = EnumUtils.enumJsonName(this);
}

@Override
public String toJson() {
return jsonName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,18 @@
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms.
package com.yahoo.bard.webservice.druid.model;

import com.yahoo.bard.webservice.util.EnumUtils;

import com.fasterxml.jackson.annotation.JsonValue;

/**
* Druid Queries the application knows about.
* Types of queries supported by this application.
*/
public enum QueryType {
GROUP_BY,
TOP_N,
TIMESERIES,
TIME_BOUNDARY,
SEGMENT_METADATA,
SEARCH,
LOOKBACK;

final String jsonName;

/**
* Constructor.
*/
QueryType() {
this.jsonName = EnumUtils.enumJsonName(this);
}
public interface QueryType {

/**
* Get the JSON version of this.
* Get the JSON serialization of the query type.
*
* @return the json representation of this enum
* @return the json representation of this type
*/
@JsonValue
public String toJson() {
return jsonName;
}
String toJson();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package com.yahoo.bard.webservice.druid.model.query;

import com.yahoo.bard.webservice.data.dimension.Dimension;
import com.yahoo.bard.webservice.druid.model.QueryType;
import com.yahoo.bard.webservice.druid.model.DefaultQueryType;
import com.yahoo.bard.webservice.druid.model.datasource.DataSource;
import com.yahoo.bard.webservice.druid.model.filter.Filter;
import com.yahoo.bard.webservice.druid.model.orderby.SearchSortDirection;
Expand Down Expand Up @@ -56,7 +56,7 @@ protected DruidSearchQuery(
QueryContext context,
boolean doFork
) {
super(QueryType.SEARCH, dataSource, granularity, filter, intervals, context, doFork);
super(DefaultQueryType.SEARCH, dataSource, granularity, filter, intervals, context, doFork);
this.searchDimensions = searchDimensions;
this.query = query;
this.sort = sort;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package com.yahoo.bard.webservice.druid.model.query;

import com.yahoo.bard.webservice.data.dimension.Dimension;
import com.yahoo.bard.webservice.druid.model.QueryType;
import com.yahoo.bard.webservice.druid.model.DefaultQueryType;
import com.yahoo.bard.webservice.druid.model.aggregation.Aggregation;
import com.yahoo.bard.webservice.druid.model.datasource.DataSource;
import com.yahoo.bard.webservice.druid.model.datasource.QueryDataSource;
Expand Down Expand Up @@ -63,7 +63,7 @@ protected GroupByQuery(
boolean doFork
) {
super(
QueryType.GROUP_BY,
DefaultQueryType.GROUP_BY,
dataSource,
granularity,
dimensions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package com.yahoo.bard.webservice.druid.model.query;

import com.yahoo.bard.webservice.data.dimension.Dimension;
import com.yahoo.bard.webservice.druid.model.QueryType;
import com.yahoo.bard.webservice.druid.model.DefaultQueryType;
import com.yahoo.bard.webservice.druid.model.aggregation.Aggregation;
import com.yahoo.bard.webservice.druid.model.datasource.DataSource;
import com.yahoo.bard.webservice.druid.model.datasource.QueryDataSource;
Expand Down Expand Up @@ -79,7 +79,7 @@ private LookbackQuery(
LimitSpec limitSpec
) {
super(
QueryType.LOOKBACK,
DefaultQueryType.LOOKBACK,
dataSource,
granularity,
Collections.<Dimension>emptySet(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms.
package com.yahoo.bard.webservice.druid.model.query;

import com.yahoo.bard.webservice.druid.model.QueryType;
import com.yahoo.bard.webservice.druid.model.DefaultQueryType;
import com.yahoo.bard.webservice.druid.model.datasource.DataSource;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
Expand Down Expand Up @@ -36,7 +36,7 @@ protected SegmentMetadataQuery(
QueryContext context,
boolean doFork
) {
super(QueryType.SEGMENT_METADATA, dataSource, context, doFork);
super(DefaultQueryType.SEGMENT_METADATA, dataSource, context, doFork);
this.intervals = Collections.unmodifiableCollection(intervals);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms.
package com.yahoo.bard.webservice.druid.model.query;

import com.yahoo.bard.webservice.druid.model.QueryType;
import com.yahoo.bard.webservice.druid.model.DefaultQueryType;
import com.yahoo.bard.webservice.druid.model.datasource.DataSource;

/**
Expand All @@ -20,7 +20,7 @@ public class TimeBoundaryQuery extends AbstractDruidQuery<TimeBoundaryQuery>
* context.
*/
protected TimeBoundaryQuery(DataSource dataSource, QueryContext context, boolean doFork) {
super(QueryType.TIME_BOUNDARY, dataSource, context, doFork);
super(DefaultQueryType.TIME_BOUNDARY, dataSource, context, doFork);
}

/**
Expand All @@ -29,7 +29,7 @@ protected TimeBoundaryQuery(DataSource dataSource, QueryContext context, boolean
* @param dataSource The datasource
*/
public TimeBoundaryQuery(DataSource dataSource) {
super(QueryType.TIME_BOUNDARY, dataSource, null, false);
super(DefaultQueryType.TIME_BOUNDARY, dataSource, null, false);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package com.yahoo.bard.webservice.druid.model.query;

import com.yahoo.bard.webservice.data.dimension.Dimension;
import com.yahoo.bard.webservice.druid.model.QueryType;
import com.yahoo.bard.webservice.druid.model.DefaultQueryType;
import com.yahoo.bard.webservice.druid.model.aggregation.Aggregation;
import com.yahoo.bard.webservice.druid.model.datasource.DataSource;
import com.yahoo.bard.webservice.druid.model.filter.Filter;
Expand Down Expand Up @@ -45,7 +45,7 @@ public TimeSeriesQuery(
boolean doFork
) {
super(
QueryType.TIMESERIES,
DefaultQueryType.TIMESERIES,
dataSource,
granularity,
Collections.<Dimension>emptySet(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package com.yahoo.bard.webservice.druid.model.query;

import com.yahoo.bard.webservice.data.dimension.Dimension;
import com.yahoo.bard.webservice.druid.model.QueryType;
import com.yahoo.bard.webservice.druid.model.DefaultQueryType;
import com.yahoo.bard.webservice.druid.model.aggregation.Aggregation;
import com.yahoo.bard.webservice.druid.model.datasource.DataSource;
import com.yahoo.bard.webservice.druid.model.filter.Filter;
Expand Down Expand Up @@ -58,7 +58,7 @@ protected TopNQuery(
boolean doFork
) {
super(
QueryType.TOP_N,
DefaultQueryType.TOP_N,
dataSource,
granularity,
Collections.singletonList(dimension),
Expand Down
Loading

0 comments on commit bae3fb3

Please sign in to comment.