reducejoin
product.txt
p0001,小米5,1000,2000
p0002,锤子T1,1000,3000
orders.txt
1001,20150710,p0001,2
1002,20150710,p0002,3
/*
K1: LongWritable
V1: Text
K2: Text 商品的id
V2: Text 行文本信息(商品的信息)
*/
public class ReduceJoinMapper extends Mapper
/*
product.txt K1 V1
0 p0001,小米5,1000,2000
orders.txt K1 V1
0 1001,20150710,p0001,2
-------------------------------------------
K2 V2
p0001 p0001,小米5,1000,2000
p0001 1001,20150710,p0001,2
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//1:判断数据来自哪个文件
FileSplit fileSplit = (FileSplit) context.getInputSplit();
String fileName = fileSplit.getPath().getName();
if(fileName.equals("product.txt")){
//数据来自商品表
//2:将K1和V1转为K2和V2,写入上下文中
String[] split = value.toString().split(",");
String productId = split[0];
context.write(new Text(productId), value);
}else{
//数据来自订单表
//2:将K1和V1转为K2和V2,写入上下文中
String[] split = value.toString().split(",");
String productId = split[2];
context.write(new Text(productId), value);
}
}
}
public class JobMain extends Configured implements Tool {
@Override
public int run(String[] args) throws Exception {
//1:获取Job对象
Job job = Job.getInstance(super.getConf(), "reduce_join");
//2:设置job任务
//第一步:设置输入类和输入路径
job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job, new Path("xxxx"));
//第二步:设置Mapper类和数据类型
job.setMapperClass(ReduceJoinMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
//第三,四,五,六
//第七步:设置Reducer类和数据类型
job.setReducerClass(ReduceJoinReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
//第八步:设置输出类和输出的路径
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job, new Path("xxxxx"));
//3:等待job任务结束
boolean bl = job.waitForCompletion(true);
return bl ? 0: 1;
}
public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
//启动job任务
int run = ToolRunner.run(configuration, new JobMain(), args);
System.exit(run);
}
}
输出结果:
p0001 p0001,小米5,1000,2000 1001,20150710,p0001,2
p0002 p0002,锤子T1,1000,3000 1002,20150710,p0002,3
mapreduce手机流量统计:
可自行查一下,因为数据量大且网上资料非常多
大概就是建一个手机的Bean类
然后mapreduce一下
Note:可以查下分区以及排序怎么实现,大致就是用Partitioner跟WritableComparable
共同好友:
数据:
A:B,C,D,F,E,O
B:A,C,E,K
C:A,B,D,E,I
D:A,E,F,L
E:B,C,D,M,L
F:A,B,C,D,E,O,M
G:A,C,D,E,F
H:A,C,D,E,O
I:A,O
J:B,O
K:A,C,D
L:D,E,F
M:E,F,G
O:A,H,I,J
public class Step1Mapper extends Mapper
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//1.以冒泡拆分行文本数据,冒泡左边就是V2
String[] split = value.toString().split(":");
String userStr = split[0];
//2.将冒泡右边的字符串以逗号拆分,每个成员就是k2
//拿A为例子。 split1就是 B,C,D,F,E,O
String[] split1 = split[1].split(",");
for(String s: split1){
//3.将k2和v2写入上下文中
context.write(new Text(s),new Text(userStr));
}
}
}
public class Step1Reducer extends Reducer
@Override
protected void reduce(Text key, Iterable
//1:遍历集合,并将每一个元素拼接,得到K3
StringBuffer buffer = new StringBuffer();
for (Text value : values) {
buffer.append(value.toString()).append("-");
}
//2:K2就是V3
//3:将K3和V3写入上下文中
context.write(new Text(buffer.toString()), key);
}
}
public class JobMain extends Configured implements Tool {
@Override
public int run(String[] args) throws Exception {
//1:获取Job对象
Job job = Job.getInstance(super.getConf(), "common_friends_step1_job");
//2:设置job任务
//第一步:设置输入类和输入路径
job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job, new Path("xxxxxx"));
//第二步:设置Mapper类和数据类型
job.setMapperClass(Step1Mapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
//第三,四,五,六
//第七步:设置Reducer类和数据类型
job.setReducerClass(Step1Reducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
//第八步:设置输出类和输出的路径
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job, new Path("xxxxx"));
//3:等待job任务结束
boolean bl = job.waitForCompletion(true);
return bl ? 0: 1;
}
public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
//启动job任务
int run = ToolRunner.run(configuration, new JobMain(), args);
System.exit(run);
}
}
结果:
I-K-B-G-F-H-O-C-D- A
A-F-C-J-E- B
E-A-H-B-F-G-K- C
K-E-C-L-A-F-H-G- D
F-M-L-H-G-D-C-B-A- E
G-D-A-M-L- F
M- G
O- H
C-O- I
O- J
B- K
D-E- L
E-F- M
J-I-H-A-F- O
第二部:
public class Step2Mapper extends Mapper
/*
K1 V1
0 A-F-C-J-E- B
----------------------------------
K2 V2
A-C B
A-E B
A-F B
C-E B
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//1:拆分行文本数据,结果的第二部分可以得到V2
String[] split = value.toString().split("\t");
String friendStr = split[1];
//2:继续以'-'为分隔符拆分行文本数据第一部分,得到数组
String[] userArray = split[0].split("-");
//3:对数组做一个排序
Arrays.sort(userArray);
//4:对数组中的元素进行两两组合,得到K2
/*
A-E-C-J -----> A C E
A C E
A C E
*/
for (int i = 0; i < userArray.length - 1; i++) {
for (int j = i + 1; j < userArray.length; j++) {
//5:将K2和V2写入上下文中
context.write(new Text(userArray[i] + "-" + userArray[j]), new Text(friendStr));
}
}
}
}
public class Step2Reducer extends Reducer
@Override
protected void reduce(Text key, Iterable
//1:原来的K2就是K3
//2:将集合进行遍历,将集合中的元素拼接,得到V3
StringBuffer buffer = new StringBuffer();
for (Text value : values) {
buffer.append(value.toString()).append("-");
}
//3:将K3和V3写入上下文中
context.write(key, new Text(buffer.toString()));
}
}
public class JobMain extends Configured implements Tool {
@Override
public int run(String[] args) throws Exception {
//1:获取Job对象
Job job = Job.getInstance(super.getConf(), "common_friends_step2_job");
//2:设置job任务
//第一步:设置输入类和输入路径
job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job, new Path("xxxxx"));
//第二步:设置Mapper类和数据类型
job.setMapperClass(Step2Mapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
//第三,四,五,六
//第七步:设置Reducer类和数据类型
job.setReducerClass(Step2Reducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
//第八步:设置输出类和输出的路径
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job, new Path("xxxxx"));
//3:等待job任务结束
boolean bl = job.waitForCompletion(true);
return bl ? 0 : 1;
}
public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
//启动job任务
int run = ToolRunner.run(configuration, new JobMain(), args);
System.exit(run);
}
}
结果:
A-B C-E-
A-C B-E-D-
A-D F-E-
A-E B-D-C-
A-F O-E-D-B-C-
A-G C-F-D-E-
A-H O-D-C-E-
A-I O-
A-J B-O-
A-K C-D-
A-L D-E-F-
A-M E-F-
B-C A-E-
B-D E-A-
B-E C-
B-F E-C-A-
B-G E-A-C-
B-H C-A-E-
B-I A-
B-K C-A-
B-L E-
B-M E-
B-O A-
C-D E-A-
C-E D-B-
C-F E-B-A-D-
C-G D-E-A-
C-H A-E-D-
C-I A-
C-J B-
C-K A-D-
C-L D-E-
C-M E-
C-O A-I-
D-E L-
D-F A-E-
D-G E-F-A-
D-H E-A-
D-I A-
D-K A-
D-L E-F-
D-M F-E-
D-O A-
E-F M-C-D-B-
E-G D-C-
E-H C-D-
E-J B-
E-K C-D-
E-L D-
F-G E-D-C-A-
F-H A-D-O-C-E-
F-I O-A-
F-J B-O-
F-K D-C-A-
F-L E-D-
F-M E-
F-O A-
G-H D-C-E-A-
G-I A-
G-K D-A-C-
G-L F-D-E-
G-M E-F-
G-O A-
H-I A-O-
H-J O-
H-K A-D-C-
H-L E-D-
H-M E-
H-O A-
I-J O-
I-K A-
I-O A-
K-L D-
K-O A-
L-M F-E-
好评差评:
大概数据:
1 2018-03-15 22:29:06 2018-03-15 22:29:06 我想再来一个 \N 1 3 hello 来就来吧 0 2018-03-14 22:29:03
2 2018-03-15 22:42:08 2018-03-15 22:42:08 好的 \N 1 1 添加一个吧 说走咱就走啊 0 2018-03-14 22:42:04
3 2018-03-15 22:55:21 2018-03-15 22:55:21 haobuhao \N 1 1 nihao 0 2018-03-24 22:55:17
4 2018-03-23 11:15:28 2018-03-23 11:15:28 店家很好 非常好 \N 1 3 666 谢谢 0 2018-03-23 11:15:20
5 2018-03-23 14:52:48 2018-03-23 14:53:22 a'da'd \N 0 4 da'd's 打打操作 0 2018-03-22 14:52:42
6 2018-03-23 14:53:52 2018-03-23 14:53:52 达到 \N 1 4 1313 13132131 0 2018-03-07 14:30:38
7 2018-03-23 14:54:29 2018-03-23 14:54:29 321313 \N 1 4 111 1231231 1 2018-03-06 14:54:24
8 2018-03-23 14:54:48 2018-03-29 03:00:12 1 \N 1 4 1 110000 0 2018-03-23 14:54:42
9 2018-03-29 02:58:34 2018-03-29 02:58:34 666666666666666 \N 1 4 4444 7777777777777777 0 2018-03-01 10:58:24
public class MyOutputFormatMapper extends Mapper
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
context.write(value,NullWritable.get());
}
}
public class MyRecordWriter extends RecordWriter
private FSDataOutputStream goodCommentsOutputStream;
private FSDataOutputStream badCommentsOutputStream;
public MyRecordWriter(){
}
public MyRecordWriter(FSDataOutputStream goodCommentsOutputStream, FSDataOutputStream badCommentsOutputStream){
this.goodCommentsOutputStream = goodCommentsOutputStream;
this.badCommentsOutputStream = badCommentsOutputStream;
}
/**
*
* @param text 行文本内容
* @param nullWritable
* @throws IOException
* @throws InterruptedException
*/
@Override
public void write(Text text, NullWritable nullWritable) throws IOException, InterruptedException {
//1:从行文本数据中获取第9个字段
String[] split = text.toString().split("\t");
String numStr = split[9];
//2:根据字段的值,判断评论的类型,然后将对应的数据写入不同的文件夹文件中
if(Integer.parseInt(numStr) <= 1){
//好评或者中评
goodCommentsOutputStream.write(text.toString().getBytes());
goodCommentsOutputStream.write("\r\n".getBytes());
}else{
//差评
badCommentsOutputStream.write(text.toString().getBytes());
badCommentsOutputStream.write("\r\n".getBytes());
}
}
@Override
public void close(TaskAttemptContext context) throws IOException, InterruptedException {
IOUtils.closeStream(goodCommentsOutputStream);
IOUtils.closeStream(badCommentsOutputStream);
}
}
public class MyOutputFormat extends FileOutputFormat
@Override
public RecordWriter
//1:获取目标文件的输出流(两个)
FileSystem fileSystem = FileSystem.get(taskAttemptContext.getConfiguration());
FSDataOutputStream goodCommentsOutputStream = fileSystem.create(new Path("xxxx/good_comments.txt"));
FSDataOutputStream badCommentsOutputStream = fileSystem.create(new Path("xxxxx/bad_comments.txt"));
//2:将输出流传给MyRecordWriter
MyRecordWriter myRecordWriter = new MyRecordWriter(goodCommentsOutputStream,badCommentsOutputStream);
return myRecordWriter;
}
}
public class JobMain extends Configured implements Tool {
@Override
public int run(String[] args) throws Exception {
//1:获取job对象
Job job = Job.getInstance(super.getConf(), "myoutputformat_job");
//2:设置job任务
//第一步:设置输入类和输入的路径
job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job, new Path("xxxx"));
//第二步:设置Mapper类和数据类型
job.setMapperClass(MyOutputFormatMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(NullWritable.class);
//第八步:设置输出类和输出的路径
job.setOutputFormatClass(MyOutputFormat.class);
MyOutputFormat.setOutputPath(job, new Path("xxxx"));
//3:等待任务结束
boolean bl = job.waitForCompletion(true);
return bl ? 0 : 1;
}
public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
int run = ToolRunner.run(configuration, new JobMain(), args);
System.exit(run);
}
}
结果example:
好评:
1 2018-03-15 22:29:06 2018-03-15 22:29:06 我想再来一个 \N 1 3 hello 来就来吧 0 2018-03-14 22:29:03
10 2018-03-29 02:58:54 2018-03-29 02:58:54 00000000 \N 1 4 55555555555 009999999 1 2018-03-02 10:58:47
100 2018-04-16 15:43:04 2018-04-16 15:43:04 买给爸爸吃的,包装有点简陋,发货挺快的,还没吃,不知道效果咋样,后面再来追评吧 \N 1 90 156******90 0 2017-12-22 09:55:46
101 2018-04-16 16:01:04 2018-04-16 16:01:04 还行吧 \N 1 84 131******13 0 2018-01-01 00:00:57
102 2018-04-16 16:01:47 2018-04-16 16:01:47 喝了 但感觉没明显的变化 \N 1 84 135******66 0 2018-03-09 13:45:37
103 2018-04-16 16:02:34 2018-04-16 16:02:34 收到的宝贝货真价实 \N 1 84 139******16 0 2018-04-03 20:30:25
104 2018-04-16 16:06:12 2018-04-16 16:06:12 刚吃,还没有发现效果,期待见效。 \N 1 82 131******85 0 2018-04-13 00:06:02
105 2018-04-16 16:06:46 2018-04-16 16:06:46 特别好用,下次再买 \N 1 82 137******77 0 2018-01-03 13:40:38
106 2018-04-16 16:07:13 2018-04-16 16:07:13 吃着没有什么感觉,说不好管用不管用 \N 1 82 136******51 0 2018-02-28 10:55:02
107 2018-04-16 16:07:38 2018-04-16 16:07:38 不错一直吃!贵在坚持吧!期待效果!! \N 1 82 133******66 0 2018-03-21 17:40:29
108 2018-04-16 16:10:11 2018-04-16 16:10:11 看销量挺高,以前吃的在澳门买的,网上没发现卖的,只能换个牌子,吃吃这个试试 \N 1 81 131******55 0 2017-12-05 00:10:03
差评:
109 2018-04-16 16:10:55 2018-04-16 16:10:55 打开瓶子有股下水道和大粪池一样的臭味啊,臭的好恶心,不敢吃 \N 1 81 133******39 2 2017-12-20 20:50:31
11 2018-03-29 02:59:17 2018-03-29 02:59:42 311111111111 \N 0 4 999999 1333333333 2 2018-03-03 10:59:10
155 2018-04-18 12:03:36 2018-04-18 12:03:36 这奶粉大家不要买,我小孩一吃就有问题,吃两次生病两次,建议大家不要买,我现在都没有让孩子吃 \N 1 42 r***r ,我们承诺所售商品均为百分之百的原产原装进口,有正规链路证明,海关报关单,100%正品保证,可以接受任何验证方式,请亲放心购买和使用呢!宝宝生病是多种因素影响的哦,季节变化还请妈妈们多注意下宝宝的身体情况和饮食哦,有什么问题可以及时联系我们在线客服处理,这边会给您满意的答复的,祝您生活愉快!!! 2 2017-12-13 14:40:19
156 2018-04-18 12:03:37 2018-04-18 12:04:14 这奶粉大家不要买,我小孩一吃就有问题,吃两次生病两次,建议大家不要买,我现在都没有让孩子吃 \N 0 42 r***r ,我们承诺所售商品均为百分之百的原产原装进口,有正规链路证明,海关报关单,100%正品保证,可以接受任何验证方式,请亲放心购买和使用呢!宝宝生病是多种因素影响的哦,季节变化还请妈妈们多注意下宝宝的身体情况和饮食哦,有什么问题可以及时联系我们在线客服处理,这边会给您满意的答复的,祝您生活愉快!!! 2 2017-12-13 14:40:19
170 2018-04-18 12:31:46 2018-04-18 12:31:46 不明白一罐奶粉里有两个勺子! \N 1 40 136******11 2 2018-01-03 12:30:40
195 2018-04-18 15:44:31 2018-04-18 15:44:31 女儿不喜欢吃,味道不好 \N 1 34 139******88 您好,羊奶粉营养成分高,是最接近母乳的奶粉,口味清淡不易上火,个人口味不一样,这个可以理解的哦~如果是换的新奶粉,也建议您给宝宝转奶适应下哦~直接换奶粉,宝宝不习惯味道吃的也会吃的比较少哦~如有疑问可联系店铺客服为您解答呢~ 2 2018-04-03 14:15:22
250 2018-04-19 15:07:15 2018-04-19 15:07:15 不好不好一点也不好我家宝宝抹完就过敏 \N 1 139 137******72 2 2018-03-13 12:40:04
253 2018-04-19 15:25:40 2018-04-19 15:25:52 第一次购买,物流是真的没的说!不过打开防晒有一股发酵的酸味不好闻,都不敢用!这么贵,唉!白瞎了 \N 1 138 138******13 2 2017-12-06 14:35:30
363 2018-04-23 04:29:58 2018-04-23 04:29:58 感觉粉质有点潮潮的 \N 1 125 134****** 2 2018-03-06 12:29:53
388 2018-04-23 09:46:18 2018-04-23 09:46:18 有些贵,其实是很贵!太贵了,而且也不知道怎么验证真假 \N 1 120 133****** 2 2018-04-18 22:10:08
409 2018-04-23 13:50:25 2018-04-23 13:50:25 东西无两样但我帮海外购服务态度0分推诿10分 \N 1 183 131****** 2 2018-01-02 21:50:18
436 2018-04-23 15:15:56 2018-04-23 15:15:56 没有前一次买的好吃 \N 1 178 134****** 2 2018-04-06 23:15:50
459 2018-05-07 14:39:14 2018-05-07 14:39:14 口味非常一般不会再购买 \N 1 172 136******31 2 2018-04-11 18:39:04
469 2018-05-07 14:48:49 2018-05-07 14:49:15 订了一个月拿到货,又太难吃了 \N 1 170 131******44 2 2018-02-28 22:48:43
83 2018-04-16 14:33:47 2018-04-16 14:33:47 瓶子口有点脏 买了好几次 希望改进 发短消息说有活动 立马问客服 客服说是前几天的活动 不知道短信发了有什么意义 \N 1 94 行***键 2 2018-01-04 14:10:35
TopN:
相当重要,hive里也是重点
资料:
Order_0000001 Pdt_01 222.8
Order_0000001 Pdt_05 25.8
Order_0000002 Pdt_03 522.8
Order_0000002 Pdt_04 122.4
Order_0000002 Pdt_05 722.4
Order_0000003 Pdt_01 222.8
public class OrderBean implements WritableComparable
private String orderId;
private Double price;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return orderId + "\t" + price;
}
//指定排序规则
@Override
public int compareTo(OrderBean orderBean) {
//先比较订单ID,如果订单ID一致,则排序订单金额(降序)
int i = this.orderId.compareTo(orderBean.orderId);
if(i == 0){
i = this.price.compareTo(orderBean.price) * -1;
}
return i;
}
//实现对象的序列化
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(orderId);
out.writeDouble(price);
}
//实现对象反序列化
@Override
public void readFields(DataInput in) throws IOException {
this.orderId = in.readUTF();
this.price = in.readDouble();
}
}
// 1: 继承WriteableComparator
public class OrderGroupComparator extends WritableComparator {
// 2: 调用父类的有参构造
public OrderGroupComparator() {
super(OrderBean.class,true);
}
//3: 指定分组的规则(重写方法)
@Override
public int compare(WritableComparable a, WritableComparable b) {
//3.1 对形参做强制类型转换
OrderBean first = (OrderBean)a;
OrderBean second = (OrderBean)b;
//3.2 指定分组规则
return first.getOrderId().compareTo(second.getOrderId());
}
}
public class OrderPartition extends Partitioner
/**
*
* @param orderBean K2
* @param text V2
* @param i ReduceTask个数
* @return 返回分区的编号
*/
@Override
public int getPartition(OrderBean orderBean, Text text, int i) {
return (orderBean.getOrderId().hashCode() & 2147483647) % i; //分区规则,相同的key分到一组,2147483647为整型最大数,为什么取这个没看到讲解,但我猜用这个可以减少hash冲突
}
}
public class GroupMapper extends Mapper
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//1:拆分行文本数据,得到订单的ID,订单的金额
String[] split = value.toString().split("\t");
//2:封装OrderBean,得到K2
OrderBean orderBean = new OrderBean();
orderBean.setOrderId(split[0]);
orderBean.setPrice(Double.valueOf(split[2]));
//3:将K2和V2写入上下文中
context.write(orderBean, value);
}
}
public class GroupReducer extends Reducer
@Override
protected void reduce(OrderBean key, Iterable
int i = 0;
for (Text value : values) {
context.write(value, NullWritable.get());
i++;
if (i >= 2) { //取top2
break;
}
}
}
}
public class JobMain extends Configured implements Tool {
@Override
public int run(String[] args) throws Exception {
//1:获取Job对象
Job job = Job.getInstance(super.getConf(), "mygroup_job");
//2:设置job任务
//第一步:设置输入类和输入路径
job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job, new Path("xxxxx"));
//第二步:设置Mapper类和数据类型
job.setMapperClass(GroupMapper.class);
job.setMapOutputKeyClass(OrderBean.class);
job.setMapOutputValueClass(Text.class);
//第三,四,五,六
//设置分区
job.setPartitionerClass(OrderPartition.class);
//设置分组
job.setGroupingComparatorClass(OrderGroupComparator.class);
//第七步:设置Reducer类和数据类型
job.setReducerClass(GroupReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);
//第八步:设置输出类和输出的路径
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job, new Path("xxxx"));
//3:等待job任务结束
boolean bl = job.waitForCompletion(true);
return bl ? 0: 1;
}
public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
//启动job任务
int run = ToolRunner.run(configuration, new JobMain(), args);
System.exit(run);
}
}
最后结果:
Order_0000001 Pdt_01 222.8
Order_0000001 Pdt_05 25.8
Order_0000002 Pdt_05 722.4
Order_0000002 Pdt_03 522.8
Order_0000003 Pdt_01 222.8