Project

General

Profile

1
package eu.dnetlib.data.mapreduce.hbase.dedup;
2

    
3
import java.io.IOException;
4
import java.util.Queue;
5

    
6
import com.google.common.collect.Iterables;
7
import com.google.common.collect.Lists;
8
import com.google.protobuf.InvalidProtocolBufferException;
9
import eu.dnetlib.data.mapreduce.JobParams;
10
import eu.dnetlib.data.mapreduce.util.DedupUtils;
11
import eu.dnetlib.data.mapreduce.util.OafDecoder;
12
import eu.dnetlib.data.mapreduce.util.OafHbaseUtils;
13
import eu.dnetlib.data.mapreduce.util.OafRowKeyDecoder;
14
import eu.dnetlib.data.proto.DedupProtos.Dedup;
15
import eu.dnetlib.data.proto.KindProtos.Kind;
16
import eu.dnetlib.data.proto.OafProtos.Oaf;
17
import eu.dnetlib.data.proto.OafProtos.OafRel;
18
import eu.dnetlib.data.proto.TypeProtos.Type;
19
import eu.dnetlib.data.transform.xml.AbstractDNetXsltFunctions;
20
import eu.dnetlib.pace.config.DedupConfig;
21
import org.apache.commons.lang.StringUtils;
22
import org.apache.hadoop.hbase.client.Put;
23
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
24
import org.apache.hadoop.hbase.mapreduce.TableReducer;
25
import org.apache.hadoop.hbase.util.Bytes;
26
import org.apache.hadoop.io.Text;
27

    
28
public class SimpleDedupPersonReducer extends TableReducer<Text, ImmutableBytesWritable, ImmutableBytesWritable> {
29

    
30
	private static final int MAX_Q_SIZE = 3000;
31

    
32
	private DedupConfig dedupConf;
33

    
34
	public static String findMin(final Iterable<String> keys) {
35
		String min = Iterables.getFirst(keys, null);
36
		for (final String iq : keys) {
37
			if (min.compareTo(iq) > 0) {
38
				min = iq;
39
			}
40
		}
41
		return min;
42
	}
43

    
44
	@Override
45
	protected void setup(final Context context) throws IOException, InterruptedException {
46
		dedupConf = DedupConfig.load(context.getConfiguration().get(JobParams.DEDUP_CONF));
47
	}
48

    
49
	@Override
50
	protected void reduce(final Text key, final Iterable<ImmutableBytesWritable> values, final Context context) throws IOException, InterruptedException {
51
		try {
52
			final Queue<OafDecoder> q = prepare(key, values, context);
53
			if (q.size() > 1) {
54

    
55
				if (q.size() < JobParams.MAX_COUNTERS) {
56
					context.getCounter(dedupConf.getWf().getEntityType() + " root group size", lpad(q.size())).increment(1);
57
				} else {
58
					context.getCounter(dedupConf.getWf().getEntityType() + " root group size", "> " + JobParams.MAX_COUNTERS).increment(1);
59
				}
60
				final String min = findMin(Iterables.transform(q, eu.dnetlib.data.transform.OafUtils.idDecoder()));
61
				if (min == null) {
62
					context.getCounter(dedupConf.getWf().getEntityType(), "unable to find min").increment(1);
63
					return;
64
				}
65
				final String rootId = DedupUtils.newId(min, dedupConf.getWf().getDedupRun());
66

    
67
				while (!q.isEmpty()) {
68
					markDuplicate(context, rootId, q.remove());
69
				}
70
			} else {
71
				context.getCounter(dedupConf.getWf().getEntityType(), "1").increment(1);
72
			}
73
		} catch (final Throwable e) {
74
			System.out.println("GOT EX " + e);
75
			e.printStackTrace(System.err);
76
			context.getCounter(dedupConf.getWf().getEntityType(), e.getClass().toString()).increment(1);
77
		}
78
	}
79

    
80
	private Queue<OafDecoder> prepare(final Text key, final Iterable<ImmutableBytesWritable> values, final Context context) {
81
		final Queue<OafDecoder> q = Lists.newLinkedList();
82
		for (final OafDecoder decoder : Iterables.transform(values, OafHbaseUtils.decoder())) {
83
			q.add(decoder);
84
			if (q.size() >= MAX_Q_SIZE) {
85
				//COMMENTED OUT TO AVOID THE JOB FAILS BECAUSE OF MAX NUMBER OF COUNTERS REACHED
86
				//context.getCounter("[" + key.toString() + "]", "size > " + MAX_Q_SIZE).increment(1);
87
				break;
88
			}
89
		}
90
		return q;
91
	}
92

    
93
	private void markDuplicate(final Context context, final String rootId, final OafDecoder decoder) throws InvalidProtocolBufferException, IOException,
94
			InterruptedException {
95

    
96
		final Oaf.Builder builder = Oaf.newBuilder(decoder.getOaf());
97
		builder.getDataInfoBuilder().setDeletedbyinference(true).setInferenceprovenance(dedupConf.getWf().getConfigurationId());
98

    
99
		final Oaf oaf = builder.build();
100
		final byte[] oafId = Bytes.toBytes(oaf.getEntity().getId());
101

    
102
		// writes the body, marked as deleted
103
		final String entityName = dedupConf.getWf().getEntityType();
104
		emit(context, oafId, entityName, DedupUtils.BODY_B, oaf.toByteArray());
105
		context.getCounter(entityName, "marked as deleted").increment(1);
106

    
107
		// writes the dedupRels in both directions
108
		final Type entityType = Type.valueOf(entityName);
109
		final byte[] rowkey = Bytes.toBytes(rootId);
110

    
111
		final String merges = DedupUtils.getDedupCF_merges(entityType);
112
		emit(context, rowkey, merges, oafId, buildRel(rowkey, oafId, Dedup.RelName.merges));
113

    
114
		final String mergedIn = DedupUtils.getDedupCF_mergedIn(entityType);
115
		emit(context, oafId, mergedIn, rowkey, buildRel(oafId, rowkey, Dedup.RelName.isMergedIn));
116

    
117
		context.getCounter(entityName, merges).increment(1);
118
		context.getCounter(entityName, mergedIn).increment(1);
119
	}
120

    
121
	private void emit(final Context context, final byte[] rowkey, final String family, final byte[] qualifier, final byte[] value) throws IOException,
122
			InterruptedException {
123

    
124
		final Put put = new Put(OafRowKeyDecoder.decode(rowkey).getKey().getBytes());
125
		put.setWriteToWAL(JobParams.WRITE_TO_WAL);
126
		put.add(Bytes.toBytes(family), qualifier, value);
127

    
128
		context.write(new ImmutableBytesWritable(rowkey), put);
129
	}
130

    
131
	private byte[] buildRel(final byte[] from, final byte[] to, final Dedup.RelName relClass) {
132
		final OafRel.Builder oafRel = DedupUtils.getDedup(dedupConf, new String(from), new String(to), relClass);
133
		final Oaf oaf =
134
				Oaf.newBuilder()
135
				.setKind(Kind.relation)
136
				.setLastupdatetimestamp(System.currentTimeMillis())
137
						.setDataInfo(
138
								AbstractDNetXsltFunctions.getDataInfo(null, "", "0.8", false, true).setInferenceprovenance(
139
								dedupConf.getWf().getConfigurationId())).setRel(oafRel)
140
								.build();
141
		return oaf.toByteArray();
142
	}
143

    
144
	private String lpad(final int s) {
145
		return StringUtils.leftPad(String.valueOf(s), String.valueOf(MAX_Q_SIZE).length());
146
	}
147

    
148
}
(16-16/16)