1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.mapreduce;
20
21 import java.io.IOException;
22 import java.util.Collections;
23 import java.util.List;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.conf.Configurable;
28 import org.apache.hadoop.conf.Configuration;
29 import org.apache.hadoop.hbase.KeyValue;
30 import org.apache.hadoop.hbase.TableName;
31 import org.apache.hadoop.hbase.classification.InterfaceAudience;
32 import org.apache.hadoop.hbase.classification.InterfaceStability;
33 import org.apache.hadoop.hbase.client.Connection;
34 import org.apache.hadoop.hbase.client.ConnectionFactory;
35 import org.apache.hadoop.hbase.client.RegionLocator;
36 import org.apache.hadoop.hbase.client.Scan;
37 import org.apache.hadoop.hbase.util.Bytes;
38 import org.apache.hadoop.mapreduce.InputSplit;
39 import org.apache.hadoop.mapreduce.JobContext;
40 import org.apache.hadoop.hbase.util.Pair;
41 import org.apache.hadoop.mapreduce.Job;
42 import org.apache.hadoop.util.StringUtils;
43
44
45
46
47 @InterfaceAudience.Public
48 @InterfaceStability.Stable
49 public class TableInputFormat extends TableInputFormatBase
50 implements Configurable {
51
52 @SuppressWarnings("hiding")
53 private static final Log LOG = LogFactory.getLog(TableInputFormat.class);
54
55
56 public static final String INPUT_TABLE = "hbase.mapreduce.inputtable";
57
58
59
60
61 private static final String SPLIT_TABLE = "hbase.mapreduce.splittable";
62
63
64
65 public static final String SCAN = "hbase.mapreduce.scan";
66
67 public static final String SCAN_ROW_START = "hbase.mapreduce.scan.row.start";
68
69 public static final String SCAN_ROW_STOP = "hbase.mapreduce.scan.row.stop";
70
71 public static final String SCAN_COLUMN_FAMILY = "hbase.mapreduce.scan.column.family";
72
73 public static final String SCAN_COLUMNS = "hbase.mapreduce.scan.columns";
74
75 public static final String SCAN_TIMESTAMP = "hbase.mapreduce.scan.timestamp";
76
77 public static final String SCAN_TIMERANGE_START = "hbase.mapreduce.scan.timerange.start";
78
79 public static final String SCAN_TIMERANGE_END = "hbase.mapreduce.scan.timerange.end";
80
81 public static final String SCAN_MAXVERSIONS = "hbase.mapreduce.scan.maxversions";
82
83 public static final String SCAN_CACHEBLOCKS = "hbase.mapreduce.scan.cacheblocks";
84
85 public static final String SCAN_CACHEDROWS = "hbase.mapreduce.scan.cachedrows";
86
87 public static final String SCAN_BATCHSIZE = "hbase.mapreduce.scan.batchsize";
88
89 public static final String SHUFFLE_MAPS = "hbase.mapreduce.inputtable.shufflemaps";
90
91
92 private Configuration conf = null;
93
94
95
96
97
98
99
100 @Override
101 public Configuration getConf() {
102 return conf;
103 }
104
105
106
107
108
109
110
111
112
113 @Override
114 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="REC_CATCH_EXCEPTION",
115 justification="Intentional")
116 public void setConf(Configuration configuration) {
117 this.conf = configuration;
118
119 Scan scan = null;
120
121 if (conf.get(SCAN) != null) {
122 try {
123 scan = TableMapReduceUtil.convertStringToScan(conf.get(SCAN));
124 } catch (IOException e) {
125 LOG.error("An error occurred.", e);
126 }
127 } else {
128 try {
129 scan = createScanFromConfiguration(conf);
130 } catch (Exception e) {
131 LOG.error(StringUtils.stringifyException(e));
132 }
133 }
134
135 setScan(scan);
136 }
137
138
139
140
141
142
143
144
145
146
147
148 public static Scan createScanFromConfiguration(Configuration conf) throws IOException {
149 Scan scan = new Scan();
150
151 if (conf.get(SCAN_ROW_START) != null) {
152 scan.setStartRow(Bytes.toBytesBinary(conf.get(SCAN_ROW_START)));
153 }
154
155 if (conf.get(SCAN_ROW_STOP) != null) {
156 scan.setStopRow(Bytes.toBytesBinary(conf.get(SCAN_ROW_STOP)));
157 }
158
159 if (conf.get(SCAN_COLUMNS) != null) {
160 addColumns(scan, conf.get(SCAN_COLUMNS));
161 }
162
163 if (conf.get(SCAN_COLUMN_FAMILY) != null) {
164 scan.addFamily(Bytes.toBytes(conf.get(SCAN_COLUMN_FAMILY)));
165 }
166
167 if (conf.get(SCAN_TIMESTAMP) != null) {
168 scan.setTimeStamp(Long.parseLong(conf.get(SCAN_TIMESTAMP)));
169 }
170
171 if (conf.get(SCAN_TIMERANGE_START) != null && conf.get(SCAN_TIMERANGE_END) != null) {
172 scan.setTimeRange(
173 Long.parseLong(conf.get(SCAN_TIMERANGE_START)),
174 Long.parseLong(conf.get(SCAN_TIMERANGE_END)));
175 }
176
177 if (conf.get(SCAN_MAXVERSIONS) != null) {
178 scan.setMaxVersions(Integer.parseInt(conf.get(SCAN_MAXVERSIONS)));
179 }
180
181 if (conf.get(SCAN_CACHEDROWS) != null) {
182 scan.setCaching(Integer.parseInt(conf.get(SCAN_CACHEDROWS)));
183 }
184
185 if (conf.get(SCAN_BATCHSIZE) != null) {
186 scan.setBatch(Integer.parseInt(conf.get(SCAN_BATCHSIZE)));
187 }
188
189
190 scan.setCacheBlocks((conf.getBoolean(SCAN_CACHEBLOCKS, false)));
191
192 return scan;
193 }
194
195 @Override
196 protected void initialize(JobContext context) throws IOException {
197
198
199 TableName tableName = TableName.valueOf(conf.get(INPUT_TABLE));
200 try {
201 initializeTable(ConnectionFactory.createConnection(new Configuration(conf)), tableName);
202 } catch (Exception e) {
203 LOG.error(StringUtils.stringifyException(e));
204 }
205 }
206
207
208
209
210
211
212
213
214
215
216 private static void addColumn(Scan scan, byte[] familyAndQualifier) {
217 byte [][] fq = KeyValue.parseColumn(familyAndQualifier);
218 if (fq.length == 1) {
219 scan.addFamily(fq[0]);
220 } else if (fq.length == 2) {
221 scan.addColumn(fq[0], fq[1]);
222 } else {
223 throw new IllegalArgumentException("Invalid familyAndQualifier provided.");
224 }
225 }
226
227
228
229
230
231
232
233
234
235
236
237 public static void addColumns(Scan scan, byte [][] columns) {
238 for (byte[] column : columns) {
239 addColumn(scan, column);
240 }
241 }
242
243
244
245
246
247
248
249
250
251
252
253 @Override
254 public List<InputSplit> getSplits(JobContext context) throws IOException {
255 List<InputSplit> splits = super.getSplits(context);
256 if ((conf.get(SHUFFLE_MAPS) != null) && "true".equals(conf.get(SHUFFLE_MAPS).toLowerCase())) {
257 Collections.shuffle(splits);
258 }
259 return splits;
260 }
261
262
263
264
265
266
267
268 private static void addColumns(Scan scan, String columns) {
269 String[] cols = columns.split(" ");
270 for (String col : cols) {
271 addColumn(scan, Bytes.toBytes(col));
272 }
273 }
274
275 @Override
276 protected Pair<byte[][], byte[][]> getStartEndKeys() throws IOException {
277 if (conf.get(SPLIT_TABLE) != null) {
278 TableName splitTableName = TableName.valueOf(conf.get(SPLIT_TABLE));
279 try (Connection conn = ConnectionFactory.createConnection(getConf())) {
280 try (RegionLocator rl = conn.getRegionLocator(splitTableName)) {
281 return rl.getStartEndKeys();
282 }
283 }
284 }
285
286 return super.getStartEndKeys();
287 }
288
289
290
291
292 public static void configureSplitTable(Job job, TableName tableName) {
293 job.getConfiguration().set(SPLIT_TABLE, tableName.getNameAsString());
294 }
295 }