blob: b262efbe45676faec3781a38b5ecd13e0467a37b [file] [log] [blame]
/*
* 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;
}
}