@Override protected MetricDictionary factory(MetricDictionary scope) { return new MetricDictionary(scope); } }
/** * Checks that the dependent metrics are in the dictionary, and throws an exception if any are not. * * @param dependentMetrics List of dependent metrics needed to check */ protected void assertDependentMetricsExist(List<String> dependentMetrics) { for (String dependentMetric : dependentMetrics) { if (!metrics.containsKey(dependentMetric)) { String message = String.format( MISSING_DEP_FORMAT, dependentMetric ); LOG.error(message); throw new IllegalArgumentException(message); } } }
/** * Buid a stream of metric columns by filtering the table group's collection of ApiMetricNames. * Metric names are resolved and then filtered considering the table granularity and the metric referenced. * * @param apiMetricNames The names of the apiMetrics being bound and filtered * @param granularity The grain used to filter those metric names * @param metricDictionary The dictionary to resolve the logical metric instances from * * @return A stream of metric columns, filtered for compatibility with the grain. */ private static Stream<LogicalMetricColumn> buildMetricColumns( Collection<ApiMetricName> apiMetricNames, Granularity granularity, MetricDictionary metricDictionary ) { return apiMetricNames.stream() .filter(name -> name.isValidFor(granularity, metricDictionary.get(name.asName()))) .map(ApiMetricName::asName) .map(metricDictionary::get) .map(LogicalMetricColumn::new); } }
/** * Generates the set of all available metrics. * * @param metricName string corresponding to the metric name specified in the URL * @param metricDictionary metric dictionary that contains the map of valid metric names to metric objects. * * @return Set of metric objects. * @throws BadApiRequestException if an invalid metric is requested or the metric dictionary is empty. */ protected LinkedHashSet<LogicalMetric> generateMetrics(String metricName, MetricDictionary metricDictionary) throws BadApiRequestException { LinkedHashSet<LogicalMetric> generated = metricDictionary.values().stream() .filter(logicalMetric -> metricName == null || metricName.equals(logicalMetric.getName())) .collect(Collectors.toCollection(LinkedHashSet::new)); if (generated.isEmpty()) { String msg; if (metricDictionary.isEmpty()) { msg = EMPTY_DICTIONARY.logFormat("Metric"); } else { msg = METRICS_UNDEFINED.logFormat(metricName); } LOG.error(msg); throw new BadApiRequestException(msg); } LOG.trace("Generated set of metrics: {}", generated); return generated; }
@Override public void loadMetricDictionary(MetricDictionary metricDictionary, DimensionDictionary dimensionDictionary) { buildMetricMakers(metricDictionary); // Metrics that directly aggregate druid fields List<MetricInstance> metrics = Arrays.asList( new MetricInstance((ApiMetricName) A_HEIGHT, longSumMaker, HEIGHT), new MetricInstance(A_WIDTH, longSumMaker, WIDTH), new MetricInstance(A_DEPTH, longSumMaker, DEPTH), new MetricInstance(A_LIMBS, longSumMaker, LIMBS), new MetricInstance(A_USERS, sketchMaker, USERS), new MetricInstance(A_OTHER_USERS, sketchMaker, USERS), new MetricInstance(A_ROW_NUM, rowNumMaker, new FieldName[] {}), new MetricInstance(A_AREA, productMaker, A_HEIGHT, A_WIDTH), new MetricInstance(A_VOLUME, productMaker, A_HEIGHT, A_WIDTH, A_DEPTH), new MetricInstance(A_DAY_AVG_USERS, simpleDailyAverageMaker, A_USERS), new MetricInstance(A_DAY_AVG_OTHER_USERS, simpleDailyAverageMaker, A_OTHER_USERS), new MetricInstance(A_DAY_AVG_LIMBS, simpleDailyAverageMaker, A_LIMBS) ); metrics.stream().map(MetricInstance::make).forEach(metricDictionary::add); metricDictionary.getScope("shapes").add( new MetricInstance(new LogicalMetricInfo(A_SCOPED_WIDTH.asName()), longSumMaker, WIDTH.asName()).make() ); //Allows us to add some non-numeric LogicalMetrics without having to write a Maker for them. Makers should //be written if using complex metrics in production code. NonNumericMetrics.getLogicalMetrics().forEach(metricDictionary::add); } }
bardConfigResources.getMetricDictionary().getScope(Collections.singletonList(tableName)) ); validateMetrics(this.logicalMetrics, this.table);
@Override public String toString() { return String.format("Dimension dictionary: %s \n\n" + "Metric dictionary: %s \n\n" + "Logical Table dictionary: %s \n\n" + "Physical Table dictionary: %s", dimension, metric.keySet(), logical, physical); } }
/** * Add a logical metric to the dictionary. * * @param logicalMetric Logical metric to add * * @return True if the Logical Metric did not exist in the dictionary before, false if it did */ public boolean add(LogicalMetric logicalMetric) { return this.put(logicalMetric.getName(), logicalMetric) == null; }
@Override public void loadMetricDictionary(MetricDictionary metricDictionary, DimensionDictionary dimensionDictionary) { buildMetricMakers(metricDictionary); // Metrics that directly aggregate druid fields List<MetricInstance> metrics = Arrays.asList( new MetricInstance((ApiMetricName) A_HEIGHT, longSumMaker, HEIGHT), new MetricInstance(A_WIDTH, longSumMaker, WIDTH), new MetricInstance(A_DEPTH, longSumMaker, DEPTH), new MetricInstance(A_LIMBS, longSumMaker, LIMBS), new MetricInstance(A_USERS, sketchMaker, USERS), new MetricInstance(A_OTHER_USERS, sketchMaker, USERS), new MetricInstance(A_ROW_NUM, rowNumMaker, new FieldName[] {}), new MetricInstance(A_AREA, productMaker, A_HEIGHT, A_WIDTH), new MetricInstance(A_VOLUME, productMaker, A_HEIGHT, A_WIDTH, A_DEPTH), new MetricInstance(A_DAY_AVG_USERS, simpleDailyAverageMaker, A_USERS), new MetricInstance(A_DAY_AVG_OTHER_USERS, simpleDailyAverageMaker, A_OTHER_USERS), new MetricInstance(A_DAY_AVG_LIMBS, simpleDailyAverageMaker, A_LIMBS) ); metrics.stream().map(MetricInstance::make).forEach(metricDictionary::add); metricDictionary.getScope("shapes").add( new MetricInstance(new LogicalMetricInfo(A_SCOPED_WIDTH.asName()), longSumMaker, WIDTH.asName()).make() ); //Allows us to add some non-numeric LogicalMetrics without having to write a Maker for them. Makers should //be written if using complex metrics in production code. NonNumericMetrics.getLogicalMetrics().forEach(metricDictionary::add); } }
page, bardConfigResources.getDimensionDictionary(), bardConfigResources.getMetricDictionary().getScope(Collections.singletonList(tableName)), bardConfigResources.getLogicalTableDictionary(), bardConfigResources.getSystemTimeZone(), page, bardConfigResources.getDimensionDictionary(), bardConfigResources.getMetricDictionary().getScope(Collections.singletonList(tableName)), bardConfigResources.getLogicalTableDictionary(), bardConfigResources.getSystemTimeZone(),
List<String> invalidMetricNames = new ArrayList<>(); for (String metricName : apiMetricQuery.split(",")) { LogicalMetric logicalMetric = metricDictionary.get(metricName); if (logicalMetric == null) { invalidMetricNames.add(metricName);
/** * Constructor. */ public ResourceDictionaries() { physical = new PhysicalTableDictionary(); logical = new LogicalTableDictionary(); metric = new MetricDictionary(); dimension = new DimensionDictionary(); }
/** * Prepare a post aggregation for a field expecting a numeric value. * <p> * The post-agg is created per the following heuristics: * <dl> * <dt>If it's an aggregator * <dd>wrap it in a field accessor * <dt>If it's a sketch * <dd>wrap it in a sketch estimate * <dt>If it's already a numeric post aggregator * <dd>simply return it * </dl> * * @param fieldName The name for the aggregation or post aggregation column being gotten * * @return A post aggregator representing a number field value * * @deprecated use the static version {@link #getNumericField(MetricField)} by preference */ @Deprecated protected PostAggregation getNumericField(String fieldName) { return getNumericField(metrics.get(fieldName).getMetricField()); }
/** * Prepare a post aggregation for a field expecting a sketch value. * <p> * The post-agg is created per the following heuristics: * <dl> * <dt>If it's an aggregator * <dd>wrap it in a field accessor * <dt>If it's a sketch estimate * <dd>unwrap the sketch estimate * <dt>If it's already a sketch post aggregator * <dd>simply return it * <dt>Otherwise</dt> * <dd>This is an illegal field</dd> * </dl> * * @param fieldName The name for the aggregation or post aggregation column being gotten * * @return A post aggregator representing a number field value * * @deprecated use the static version {@link MetricMaker#getSketchField(MetricField)} by preference */ @Deprecated protected PostAggregation getSketchField(String fieldName) { // Get the field return getSketchField(metrics.get(fieldName).getMetricField()); }
LogicalMetric logicalMetric = metricDictionary.get(metricName);
sortMetricName = entry.getKey(); LogicalMetric logicalMetric = metricDictionary.get(sortMetricName);
@Override protected LogicalMetric makeInner(LogicalMetricInfo logicalMetricInfo, List<String> dependentMetrics) { LogicalMetric sourceMetric = metricDictionary.get(dependentMetrics.get(0)); Aggregation sourceAggregation = assertDependentIsAggregationMetric(sourceMetric); FilteredAggregation filteredAggregation = new FilteredAggregation( logicalMetricInfo.getName(), sourceAggregation, filter ); return new LogicalMetric( new TemplateDruidQuery( ImmutableSet.of(filteredAggregation), Collections.emptySet(), sourceMetric.getTemplateDruidQuery().getInnerQuery().orElse(null) ), sourceMetric.getCalculation(), logicalMetricInfo ); }
@Override protected LogicalMetric makeInner(LogicalMetricInfo logicalMetricInfo, List<String> dependentMetrics) { // Get the Metric that is being averaged over LogicalMetric dependentMetric = metrics.get(dependentMetrics.get(0)); // Get the field being subtotalled in the inner query MetricField sourceMetric = convertToSketchEstimateIfNeeded(dependentMetric.getMetricField()); // Build the TemplateDruidQuery for the metric TemplateDruidQuery innerQuery = buildInnerQuery(sourceMetric, dependentMetric.getTemplateDruidQuery()); TemplateDruidQuery outerQuery = buildOuterQuery(logicalMetricInfo.getName(), sourceMetric, innerQuery); return new LogicalMetric(outerQuery, NO_OP_MAPPER, logicalMetricInfo); }
LogicalMetric logicalMetric = metricDictionary.get(metricName);