private static PlanNodeStatsEstimate createZeroStats(PlanNodeStatsEstimate stats) { PlanNodeStatsEstimate.Builder result = PlanNodeStatsEstimate.builder(); result.setOutputRowCount(0); stats.getSymbolsWithKnownStatistics().forEach(symbol -> result.addSymbolStatistics(symbol, SymbolStatsEstimate.zero())); return result.build(); }
@Override protected PlanNodeStatsEstimate visitBooleanLiteral(BooleanLiteral node, Void context) { if (node.getValue()) { return input; } PlanNodeStatsEstimate.Builder result = PlanNodeStatsEstimate.builder(); result.setOutputRowCount(0.0); input.getSymbolsWithKnownStatistics().forEach(symbol -> result.addSymbolStatistics(symbol, SymbolStatsEstimate.zero())); return result.build(); }
private SymbolStatsEstimate buildSymbolStatistics(List<Object> values, Session session, Type type) { List<Object> nonNullValues = values.stream() .filter(Objects::nonNull) .collect(toImmutableList()); if (nonNullValues.isEmpty()) { return SymbolStatsEstimate.zero(); } double[] valuesAsDoubles = nonNullValues.stream() .map(value -> toStatsRepresentation(metadata, session, type, value)) .filter(OptionalDouble::isPresent) .mapToDouble(OptionalDouble::getAsDouble) .toArray(); double lowValue = DoubleStream.of(valuesAsDoubles).min().orElse(Double.NEGATIVE_INFINITY); double highValue = DoubleStream.of(valuesAsDoubles).max().orElse(Double.POSITIVE_INFINITY); double valuesCount = values.size(); double nonNullValuesCount = nonNullValues.size(); long distinctValuesCount = nonNullValues.stream().distinct().count(); return SymbolStatsEstimate.builder() .setNullsFraction((valuesCount - nonNullValuesCount) / valuesCount) .setLowValue(lowValue) .setHighValue(highValue) .setDistinctValuesCount(distinctValuesCount) .build(); } }
private PlanNodeStatsEstimate normalize(PlanNodeStatsEstimate stats, Optional<Collection<Symbol>> outputSymbols, TypeProvider types) { if (stats.isOutputRowCountUnknown()) { return PlanNodeStatsEstimate.unknown(); } PlanNodeStatsEstimate.Builder normalized = PlanNodeStatsEstimate.buildFrom(stats); Predicate<Symbol> symbolFilter = outputSymbols .map(ImmutableSet::copyOf) .map(set -> (Predicate<Symbol>) set::contains) .orElse(symbol -> true); for (Symbol symbol : stats.getSymbolsWithKnownStatistics()) { if (!symbolFilter.test(symbol)) { normalized.removeSymbolStatistics(symbol); continue; } SymbolStatsEstimate symbolStats = stats.getSymbolStatistics(symbol); SymbolStatsEstimate normalizedSymbolStats = stats.getOutputRowCount() == 0 ? SymbolStatsEstimate.zero() : normalizeSymbolStats(symbol, symbolStats, stats, types); if (normalizedSymbolStats.isUnknown()) { normalized.removeSymbolStatistics(symbol); continue; } if (!Objects.equals(normalizedSymbolStats, symbolStats)) { normalized.addSymbolStatistics(symbol, normalizedSymbolStats); } } return normalized.build(); }
private static PlanNodeStatsEstimate addStats(PlanNodeStatsEstimate left, PlanNodeStatsEstimate right, RangeAdditionStrategy strategy) { if (left.isOutputRowCountUnknown() || right.isOutputRowCountUnknown()) { return PlanNodeStatsEstimate.unknown(); } PlanNodeStatsEstimate.Builder statsBuilder = PlanNodeStatsEstimate.builder(); double newRowCount = left.getOutputRowCount() + right.getOutputRowCount(); concat(left.getSymbolsWithKnownStatistics().stream(), right.getSymbolsWithKnownStatistics().stream()) .distinct() .forEach(symbol -> { SymbolStatsEstimate symbolStats = SymbolStatsEstimate.zero(); if (newRowCount > 0) { symbolStats = addColumnStats( left.getSymbolStatistics(symbol), left.getOutputRowCount(), right.getSymbolStatistics(symbol), right.getOutputRowCount(), newRowCount, strategy); } statsBuilder.addSymbolStatistics(symbol, symbolStats); }); return statsBuilder.setOutputRowCount(newRowCount).build(); }
return SymbolStatsEstimate.zero();
@Test public void testStatsForEmptyValues() { tester().assertStatsFor(pb -> pb .values(ImmutableList.of(pb.symbol("a", BIGINT)), ImmutableList.of())) .check(outputStats -> outputStats.equalTo( PlanNodeStatsEstimate.builder() .setOutputRowCount(0) .addSymbolStatistics(new Symbol("a"), SymbolStatsEstimate.zero()) .build())); } }
@Test public void testStatsForValuesNodeWithJustNulls() { PlanNodeStatsEstimate nullAStats = PlanNodeStatsEstimate.builder() .setOutputRowCount(1) .addSymbolStatistics(new Symbol("a"), SymbolStatsEstimate.zero()) .build(); tester().assertStatsFor(pb -> pb .values(ImmutableList.of(pb.symbol("a", BIGINT)), ImmutableList.of( ImmutableList.of(expression("3 + null"))))) .check(outputStats -> outputStats.equalTo(nullAStats)); tester().assertStatsFor(pb -> pb .values(ImmutableList.of(pb.symbol("a", BIGINT)), ImmutableList.of( ImmutableList.of(expression("null"))))) .check(outputStats -> outputStats.equalTo(nullAStats)); tester().assertStatsFor(pb -> pb .values(ImmutableList.of(pb.symbol("a", UNKNOWN)), ImmutableList.of( ImmutableList.of(expression("null"))))) .check(outputStats -> outputStats.equalTo(nullAStats)); }
@Test public void testArithmeticBinaryWithAllNullsSymbol() SymbolStatsEstimate allNullStats = SymbolStatsEstimate.zero(); PlanNodeStatsEstimate relationStats = PlanNodeStatsEstimate.builder() .addSymbolStatistics(new Symbol("x"), SymbolStatsEstimate.builder()