def apply_filter(expr, predicates): # This will attempt predicate pushdown in the cases where we can do it # easily and safely, to make both cleaner SQL and fewer referential errors # for users op = expr.op() if isinstance(op, ops.Selection): return _filter_selection(expr, predicates) elif isinstance(op, ops.Aggregation): # Potential fusion opportunity # GH1344: We can't sub in things with correlated subqueries simplified_predicates = [ sub_for(predicate, [(expr, op.table)]) if not has_reduction(predicate) else predicate for predicate in predicates ] if op.table._is_valid(simplified_predicates): result = ops.Aggregation(op.table, op.metrics, by=op.by, having=op.having, predicates=op.predicates + simplified_predicates, sort_keys=op.sort_keys) return ir.TableExpr(result) elif isinstance(op, ops.Join): expr = expr.materialize() result = ops.Selection(expr, [], predicates) return ir.TableExpr(result)
def _lift_Aggregation(self, expr, block=None): if block is None: block = self.block_projection op = expr.op() # as exposed in #544, do not lift the table inside (which may be # filtered or otherwise altered in some way) if blocking if block: lifted_table = op.table else: lifted_table = self.lift(op.table, block=True) unch = lifted_table is op.table lifted_aggs, unch1 = self._lift_arg(op.metrics, block=True) lifted_by, unch2 = self._lift_arg(op.by, block=True) lifted_having, unch3 = self._lift_arg(op.having, block=True) unchanged = unch and unch1 and unch2 and unch3 if not unchanged: lifted_op = ops.Aggregation(lifted_table, lifted_aggs, by=lifted_by, having=lifted_having) result = ir.TableExpr(lifted_op) else: result = expr return result
def aggregate(table, metrics=None, by=None, having=None, **kwds): """ Aggregate a table with a given set of reductions, with grouping expressions, and post-aggregation filters. Parameters ---------- table : table expression metrics : expression or expression list by : optional, default None Grouping expressions having : optional, default None Post-aggregation filters Returns ------- agg_expr : TableExpr """ if metrics is None: metrics = [] for k, v in sorted(kwds.items()): v = table._ensure_expr(v) metrics.append(v.name(k)) op = _ops.Aggregation(table, metrics, by=by, having=having) return TableExpr(op)
def apply_filter(expr, predicates): # This will attempt predicate pushdown in the cases where we can do it # easily and safely, to make both cleaner SQL and fewer referential errors # for users op = expr.op() if isinstance(op, ops.Selection): return _filter_selection(expr, predicates) elif isinstance(op, ops.Aggregation): # Potential fusion opportunity simplified_predicates = [ sub_for(x, [(expr, op.table)]) for x in predicates ] if op.table._is_valid(simplified_predicates): result = ops.Aggregation(op.table, op.agg_exprs, by=op.by, having=op.having, predicates=op.predicates + simplified_predicates, sort_keys=op.sort_keys) return ir.TableExpr(result) elif isinstance(op, ops.Join): expr = expr.materialize() result = ops.Selection(expr, [], predicates) return ir.TableExpr(result)
def apply_filter(expr, predicates): # This will attempt predicate pushdown in the cases where we can do it # easily and safely, to make both cleaner SQL and fewer referential errors # for users op = expr.op() if isinstance(op, ops.Selection): return _filter_selection(expr, predicates) elif isinstance(op, ops.Aggregation): # Potential fusion opportunity # GH1344: We can't sub in things with correlated subqueries simplified_predicates = [ # Originally this line tried substituting op.table in for expr, but # that is too aggressive in the presence of filters that occur # after aggregations. # # See https://github.com/ibis-project/ibis/pull/3341 for details sub_for(predicate, [(op.table, expr)]) if not has_reduction(predicate) else predicate for predicate in predicates ] if op.table._is_valid(simplified_predicates): result = ops.Aggregation( op.table, op.metrics, by=op.by, having=op.having, predicates=op.predicates + simplified_predicates, sort_keys=op.sort_keys, ) return ir.TableExpr(result) result = ops.Selection(expr, [], predicates) return ir.TableExpr(result)
def _lift_Aggregation(self, expr, block=None): if block is None: block = self.block_projection op = expr.op() lifted_table = self.lift(op.table, block=True) unch = lifted_table is op.table lifted_aggs, unch1 = self._lift_arg(op.agg_exprs, block=True) lifted_by, unch2 = self._lift_arg(op.by, block=True) lifted_having, unch3 = self._lift_arg(op.having, block=True) unchanged = unch and unch1 and unch2 and unch3 if not unchanged: lifted_op = ops.Aggregation(lifted_table, lifted_aggs, by=lifted_by, having=lifted_having) result = ir.TableExpr(lifted_op) else: result = expr return result