package org.openflamingo.mapreduce.etl.groupby; import org.apache.commons.collections.list.TreeList; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; import org.openflamingo.mapreduce.core.Delimiter; import org.openflamingo.mapreduce.util.CounterUtils; import java.io.IOException; import java.util.Collections; import java.util.List; /** * 지정한 키로 Group By하여 하나의 로우로 키와 값을 취합하는 Transpose ETL 리듀서 * * @author Edward KIM * @author Seo Ji Hye * @since 0.1 */ public class GroupByReducer extends Reducer<Text, Text, NullWritable, Text> { /** * Key와 Value의 구분자. */ private String outputDelimiter; /** * Value를 구성하는 값들의 구분자. */ private String valueDelimiter; /** * 중복 허용 여부. <tt>true</tt>인 경우 중복을 허용한다. */ private boolean allowDuplicate = true; /** * Value를 구성하는 값들을 정렬할지 여부. <tt>true</tt>인 경우 정렬한다. */ private boolean allowSort = false; @Override protected void setup(Context context) throws IOException, InterruptedException { Configuration configuration = context.getConfiguration(); outputDelimiter = configuration.get("keyValueDelimiter", Delimiter.TAB.getDelimiter()); valueDelimiter = configuration.get("valueDelimiter"); allowDuplicate = configuration.getBoolean("allowDuplicate", false); allowSort = configuration.getBoolean("allowSort", false); } @Override protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { CounterUtils.writerReducerCounter(this, "ITEMS", context); List<String> items = new TreeList(); StringBuilder builder = new StringBuilder(); for (Text value : values) { if (allowDuplicate) { // 중복을 허용하면 그대로 추가 items.add(value.toString()); } else if (!items.contains(value.toString())) { // 중복을 허용하지 않으면 없는 아이템만 추가 items.add(value.toString()); } } if (allowSort) { Collections.sort(items); // FIXME Comparator를 정의하지 않아도 되나? } for (String item : items) { builder.append(item).append(valueDelimiter); } String valueString = builder.toString(); String finalValueString = valueString.substring(0, valueString.length() - 1); context.write(NullWritable.get(), new Text(key.toString() + outputDelimiter + finalValueString)); } }