/** * Copyright [2011] [Datasalt Systems S.L.] * * Licensed 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 com.datasalt.utils.mapred.joiner; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.hadoop.io.Text; import org.apache.hadoop.io.WritableComparable; import org.apache.hadoop.mapreduce.lib.input.GetInputFileFromTaggedInputSplit; /** * This mapper is associated with one channel and emits always the same kind of data. This enables concise code and code * reusing in some cases. It must be configured with the appropriate methods in {@link MultiJoiner} that accept such * mapper classes. * * @author pere * * @param <INPUT_KEY> * Any type for the input key * @param <INPUT_VALUE> * Any type for the input value * @param <OUTPUT_VALUE> * A type that will be serialized through the channel */ @SuppressWarnings({ "rawtypes" }) public class MultiJoinChanneledMapper<INPUT_KEY, INPUT_VALUE, OUTPUT_VALUE> extends MultiJoinMapperBase<INPUT_KEY, INPUT_VALUE> { public static final String MULTIJOINER_CHANNELED_FILES = "datasalt.multijoiner.channeled.files"; public static final String MULTIJOINER_CHANNELED_CHANNELS = "datasalt.multijoiner.channeled.channels"; private Map<String, Integer> idByFile = new HashMap<String, Integer>(); /** * Don't forget to call super.setup() if you override this method. */ @Override protected void setup(Context context) throws IOException, InterruptedException { super.setup(context); int id = 0; List<String> channels = MultiJoiner.readStringListFromConfig(context.getConfiguration(), MULTIJOINER_CHANNELED_CHANNELS); Set<String> distinctChannels = new HashSet<String>(); for(String file : MultiJoiner.readStringListFromConfig(context.getConfiguration(), MULTIJOINER_CHANNELED_FILES)) { String thisChannel = channels.get(id); distinctChannels.add(thisChannel); int channel = Integer.parseInt(thisChannel); idByFile.put(file, channel); id++; } } /* * The following methods can be used as a shortcut for emit(Object, SS, T) */ protected void emit(String grouping, OUTPUT_VALUE datum) throws IOException, InterruptedException { byte[] array = grouping.getBytes("UTF-8"); emitBytes(array, 0, array.length, null, datum); } protected void emit(String grouping, WritableComparable secondarySort, OUTPUT_VALUE datum) throws IOException, InterruptedException { byte[] array = grouping.getBytes("UTF-8"); emitBytes(array, 0, array.length, secondarySort, datum); } protected void emit(Object grouping, OUTPUT_VALUE datum) throws IOException, InterruptedException { byte[] array = ser.ser(grouping); emitBytes(array, 0, array.length, null, datum); } protected void emit(Text grouping, WritableComparable secondarySort, OUTPUT_VALUE datum) throws IOException, InterruptedException { emitBytes(grouping.getBytes(), 0, grouping.getLength(), secondarySort, datum); } protected void emit(Text grouping, OUTPUT_VALUE datum) throws IOException, InterruptedException { emitBytes(grouping.getBytes(), 0, grouping.getLength(), null, datum); } /** * You can use whichever WritableComparable as secondary sort, but you have to do two things:<br> * 1) Create a {@link MultiJoinPair} for your WritableComparable. Look for example {@link MultiJoinPairText}. 2) Call * the method {@link MultiJoiner#setMultiJoinPairClass(Class)} to set the proper {@link MultiJoinPair} */ protected void emit(Object grouping, WritableComparable secondarySort, OUTPUT_VALUE datum) throws IOException, InterruptedException { byte[] array = ser.ser(grouping); emitBytes(array, 0, array.length, secondarySort, datum); } /** * Emits any object as key, any object as value and optionally a WritableComparator for secondary sorting. The * WritableComparator used here must be consistent with the {@link MultiJoinPair} class defined in the MultiJoiner * configuration. * * @param <SS> * @param grouping * @param secondarySort * @param datum * @throws IOException * @throws InterruptedException */ private void emitBytes(byte[] grouping, int offset, int length, WritableComparable secondarySort, OUTPUT_VALUE datum) throws IOException, InterruptedException { String path = GetInputFileFromTaggedInputSplit.get(context.getInputSplit()); if (path == null){ throw new IOException("Null path for inputSplit:" + context.getInputSplit() + "\ncontext:" + context + "\nidByFile:" + idByFile); } Integer classId = idByFile.get(path); if (classId == null){ throw new IOException("Class id null for path: " + path + "\nidByFile:" + idByFile); } emitBytes(grouping, offset, length, secondarySort, datum, classId); } }