| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.pig.newplan.logical.relational; |
| |
| import java.util.Collection; |
| import java.util.List; |
| |
| import org.apache.pig.impl.logicalLayer.FrontendException; |
| import org.apache.pig.impl.util.MultiMap; |
| import org.apache.pig.newplan.Operator; |
| import org.apache.pig.newplan.OperatorPlan; |
| import org.apache.pig.newplan.PlanVisitor; |
| import org.apache.pig.newplan.logical.expression.LogicalExpressionPlan; |
| |
| /** |
| * CUBE operator implementation for data cube computation. |
| * <p> |
| * Cube operator syntax |
| * |
| * <pre> |
| * {@code alias = CUBE rel BY { CUBE | ROLLUP }(col_ref) [, { CUBE | ROLLUP }(col_ref) ...];} |
| * alias - output alias |
| * CUBE - operator |
| * rel - input relation |
| * BY - operator |
| * CUBE | ROLLUP - cube or rollup operation |
| * col_ref - column references or * or range in the schema referred by rel |
| * </pre> |
| * |
| * </p> |
| * <p> |
| * The cube computation and rollup computation using UDFs |
| * {@link org.apache.pig.builtin.CubeDimensions} and |
| * {@link org.apache.pig.builtin.RollupDimensions} can be represented like below |
| * |
| * <pre> |
| * {@code |
| * events = LOAD '/logs/events' USING EventLoader() AS (lang, event, app_id, event_id, total); |
| * eventcube = CUBE events BY CUBE(lang, event), ROLLUP(app_id, event_id); |
| * result = FOREACH eventcube GENERATE FLATTEN(group) as (lang, event), |
| * COUNT_STAR(cube), SUM(cube.total); |
| * STORE result INTO 'cuberesult'; |
| * } |
| * </pre> |
| * |
| * In the above example, CUBE(lang, event) will generate all combinations of |
| * aggregations {(lang, event), (lang, ), ( , event), ( , )}. |
| * For n dimensions, 2^n combinations of aggregations will be generated. |
| * |
| * Similarly, ROLLUP(app_id, event_id) will generate aggregations from the most |
| * detailed to the most general (grandtotal) level in the hierarchical order |
| * like {(app_id, event_id), (app_id, ), ( , )}. For n dimensions, |
| * n+1 combinations of aggregations will be generated. |
| * |
| * The output of the above example query will have the following combinations of |
| * aggregations {(lang, event, app_id, event_id), (lang, , app_id, event_id), |
| * ( , event, app_id, event_id), ( , , app_id, event_id), (lang, event, app_id, ), |
| * (lang, , app_id, ), ( , event, app_id, ), ( , , app_id, ), (lang, event, , ), |
| * (lang, , , ), ( , event, , ), ( , , , )} |
| * |
| * Total number of combinations will be ( 2^n * (n+1) ) |
| * |
| * Since cube and rollup clause use null to represent "all" values of a dimension, |
| * if the dimension values contain null values it will be converted to "unknown" |
| * before computing cube or rollup. |
| * </p> |
| */ |
| public class LOCube extends LogicalRelationalOperator { |
| private MultiMap<Integer, LogicalExpressionPlan> mExpressionPlans; |
| private List<String> operations; |
| |
| public LOCube(LogicalPlan plan) { |
| super("LOCube", plan); |
| } |
| |
| public LOCube(OperatorPlan plan, MultiMap<Integer, LogicalExpressionPlan> expressionPlans) { |
| super("LOCube", plan); |
| this.mExpressionPlans = expressionPlans; |
| } |
| |
| @Override |
| public LogicalSchema getSchema() throws FrontendException { |
| // TODO: implement when physical operator for CUBE is implemented |
| return null; |
| } |
| |
| @Override |
| public void accept(PlanVisitor v) throws FrontendException { |
| try { |
| ((LogicalRelationalNodesVisitor) v).visit(this); |
| } catch (ClassCastException cce) { |
| throw new FrontendException("Expected LogicalPlanVisitor", cce); |
| } |
| } |
| |
| @Override |
| public boolean isEqual(Operator other) throws FrontendException { |
| try { |
| LOCube cube = (LOCube) other; |
| for (Integer key : mExpressionPlans.keySet()) { |
| if (!cube.mExpressionPlans.containsKey(key)) { |
| return false; |
| } |
| Collection<LogicalExpressionPlan> lepList1 = mExpressionPlans.get(key); |
| Collection<LogicalExpressionPlan> lepList2 = cube.mExpressionPlans.get(key); |
| |
| for (LogicalExpressionPlan lep1 : lepList1) { |
| for (LogicalExpressionPlan lep2 : lepList2) { |
| if (!lep1.isEqual(lep2)) { |
| return false; |
| } |
| } |
| } |
| } |
| return checkEquality((LogicalRelationalOperator) other); |
| } catch (ClassCastException cce) { |
| throw new FrontendException("Exception while casting CUBE operator", cce); |
| } |
| } |
| |
| public MultiMap<Integer, LogicalExpressionPlan> getExpressionPlans() { |
| return mExpressionPlans; |
| } |
| |
| public void setExpressionPlans(MultiMap<Integer, LogicalExpressionPlan> plans) { |
| this.mExpressionPlans = plans; |
| } |
| |
| @Override |
| public void resetUid() { |
| // TODO: implement when physical operator for CUBE is implemented |
| } |
| |
| public List<Operator> getInputs(LogicalPlan plan) { |
| return plan.getPredecessors(this); |
| } |
| |
| public List<String> getOperations() { |
| return operations; |
| } |
| |
| public void setOperations(List<String> operations) { |
| this.operations = operations; |
| } |
| } |