@Override public void processInstruction(ExecutionContext ec) throws DMLRuntimeException, DMLUnsupportedOperationException { SparkExecutionContext sec = (SparkExecutionContext) ec; String rddVar = (_type == CacheType.LEFT) ? input2.getName() : input1.getName(); String bcastVar = (_type == CacheType.LEFT) ? input1.getName() : input2.getName(); MatrixCharacteristics mcRdd = sec.getMatrixCharacteristics(rddVar); MatrixCharacteristics mcBc = sec.getMatrixCharacteristics(bcastVar); // get inputs JavaPairRDD<MatrixIndexes, MatrixBlock> in1 = sec.getBinaryBlockRDDHandleForVariable(rddVar); PartitionedBroadcastMatrix in2 = sec.getBroadcastForVariable(bcastVar); // empty input block filter if (!_outputEmpty) in1 = in1.filter(new FilterNonEmptyBlocksFunction()); // execute mapmult instruction JavaPairRDD<MatrixIndexes, MatrixBlock> out = null; if (requiresFlatMapFunction(_type, mcBc)) out = in1.flatMapToPair(new RDDFlatMapMMFunction(_type, in2)); else if (preservesPartitioning(mcRdd, _type)) out = in1.mapPartitionsToPair(new RDDMapMMPartitionFunction(_type, in2), true); else out = in1.mapToPair(new RDDMapMMFunction(_type, in2)); // empty output block filter if (!_outputEmpty) out = out.filter(new FilterNonEmptyBlocksFunction()); // perform aggregation if necessary and put output into symbol table if (_aggtype == SparkAggType.SINGLE_BLOCK) { MatrixBlock out2 = RDDAggregateUtils.sumStable(out); // put output block into symbol table (no lineage because single block) // this also includes implicit maintenance of matrix characteristics sec.setMatrixOutput(output.getName(), out2); } else // MULTI_BLOCK or NONE { if (_aggtype == SparkAggType.MULTI_BLOCK) out = RDDAggregateUtils.sumByKeyStable(out); // put output RDD handle into symbol table sec.setRDDHandleForVariable(output.getName(), out); sec.addLineageRDD(output.getName(), rddVar); sec.addLineageBroadcast(output.getName(), bcastVar); // update output statistics if not inferred updateBinaryMMOutputMatrixCharacteristics(sec, true); } }