案例:

数据:

邮编   |     日期     |金额

ILMN,2013-12-05,97.65
GOOD,2013-12-09,1078.14
IBM,2013-12-09,177.46
ILMN,2013-12-09,101.33
ILMN,2013-12-06,99.25,
GOOD,2013-12-06,1069.87
IBM,2013-12-06,177.67
GOOD,2013-12-05,1057.34
GOOD,2013-12-05,10.23
GOOD,2013-12-05,11.43
GOOD,2013-12-05,17.34

要求:把同一个邮编的放在一起,然后根据日期和金额降序排列。

效果如下:

思路:在map阶段,构造的key(CompositeKey)是:(邮编,日期);value(NaturalValue)是(日期,价格)。然后key继承

WritableComparable,实现比较函数这样就可以保证一份数据出来是分区且区内有序的。

然后在shuffle过程中,指定一个key比较器(CompositeKeyComparator),使得在聚合过程后,对key按照先邮编,再时间,最后金额的顺序排序,key-value是键值对,key按照我们的意愿排好序了,

value也就排好了。

总的来说:降序什么的都是CompositeKeyComparator来决定的。

代码结构:

(1)key:组合键

 package com.book.test1;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException; import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;
/**
* 这个的作用就是要数据在分区里面有序
*/
/**
* 定义组合键:就是可以把自己要比较的字段写入
* @author Sxq
*
*/
//必须要时间这个WritableComparable这个类
public class CompositeKey implements Writable, WritableComparable<CompositeKey> { // 股票的名字
private Text stockSymbol;
// 日期
private LongWritable timestamp;
private DoubleWritable price; public DoubleWritable getPrice() {
return price;
}
public void setPrice(DoubleWritable price) {
this.price = price;
}
public CompositeKey()
{ }
public CompositeKey(Text _stockSymbol, LongWritable _timestamp,DoubleWritable _price) {
this.stockSymbol = _stockSymbol;
this.timestamp = _timestamp;
this.price=_price;
} public Text getStockSymbol() {
return stockSymbol;
} public void setStockSymbol(Text stockSymbol) {
this.stockSymbol = stockSymbol;
} public LongWritable getTimestamp() {
return timestamp;
} public void setTimestamp(LongWritable timestamp) {
this.timestamp = timestamp;
} //读出
public void readFields(DataInput input) throws IOException {
String value1=input.readUTF();
long value2=input.readLong();
this.stockSymbol=new Text( value1);
this.timestamp= new LongWritable(value2);
this.price=new DoubleWritable(input.readDouble());
} //写入 //@Override
public void write(DataOutput output) throws IOException {
output.writeUTF(this.stockSymbol.toString());
output.writeLong(this.timestamp.get());
output.writeDouble(this.price.get());
} public int compareTo(CompositeKey other) { int comparator=this.stockSymbol.compareTo(other.stockSymbol);
if(comparator==0)
{
comparator=this.timestamp.compareTo(other.timestamp);
} //升序
//return comparator; return -comparator;
} @Override
public String toString() {
return "CompositeKey [stockSymbol=" + stockSymbol + ", timestamp=" + timestamp + "]";
} }

(2)key对应的value:

package com.book.test1;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable; public class NaturalValue implements Writable {
private long timestamp;
private double privce; public long getTimestamp() {
return timestamp;
} public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
} public double getPrivce() {
return privce;
} public void setPrivce(double privce) {
this.privce = privce;
} public void readFields(DataInput input) throws IOException {
this.timestamp=input.readLong();
this.privce=input.readDouble(); } public void write(DataOutput output) throws IOException { output.writeLong(this.timestamp);
output.writeDouble(this.privce); } }

(3)分区器:

NaturalKeyPartitioner

package com.book.test1;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
/**
* 分区:按照邮编分,把邮编相同的放在一起
* @author Sxq
*/ public class NaturalKeyPartitioner extends Partitioner<CompositeKey, NaturalValue> { @Override
public int getPartition(CompositeKey key, NaturalValue value, int numPartitions) {
return Math.abs((int)(key.getStockSymbol().hashCode())%numPartitions);
} }

(4)把key排序的比较器:在shuffle过程中用到的

package com.book.test1;

import javax.print.attribute.standard.MediaSize.Other;

import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator; /**
* 这个类的作用是把组合键排序,使得组合键也有顺序
* @author Sxq
*
*/
public class CompositeKeyComparator extends WritableComparator { public CompositeKeyComparator() {
super(CompositeKey.class,true);
} @Override
public int compare(WritableComparable a, WritableComparable b) {
CompositeKey ck1 = (CompositeKey) a;
CompositeKey ck2 = (CompositeKey) b;
int comparison = ck1.getStockSymbol().compareTo(ck2.getStockSymbol());
//如果邮编相同,则根据日期进一步处理。
if (comparison == 0) { int comparison2=ck1.getTimestamp().compareTo(ck2.getTimestamp());
// 如果日期相同,则需要根据价格进一步处理
if (comparison2==0) {
//按照价格降序
return ck1.getPrice().compareTo(ck2.getPrice())>0?-1:1; } else {
//日期不同,就按照日期降序
return ck1.getTimestamp().compareTo(ck2.getTimestamp())>0?-1:1;
}
}
else {
return comparison;
}
}
static {
WritableComparator.define(CompositeKey.class, new CompositeKeyComparator());
} }

(5)reduce的分区器:

CompositeGroupingComparator

package com.book.test1;

import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator; /**
* 分组:就是在reduce阶段分到一个组;
* 就是邮编相同的放在一个组里面
* @author Sxq
*
*/
public class CompositeGroupingComparator extends WritableComparator{ public CompositeGroupingComparator() { super(CompositeKey.class,true);
} @Override
public int compare(WritableComparable a, WritableComparable b) {
CompositeKey v1=(CompositeKey)a;
CompositeKey v2=(CompositeKey)b; return v1.getStockSymbol().compareTo(v2.getStockSymbol()); } }

(6)驱动类:

package com.book.test1;

import java.io.IOException;
import java.util.Date;
import java.util.Iterator; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class Cmain {
static class Map1 extends Mapper<LongWritable, Text, CompositeKey, NaturalValue> {
@Override
protected void map(LongWritable key, Text value,
Mapper<LongWritable, Text, CompositeKey, NaturalValue>.Context context)
throws IOException, InterruptedException {
String line = value.toString().trim();
String[] lines = line.split(",");
Date date = DateUtil.getDate(lines[1]);
//long timestamp = date.getTime(); long timestamp=UtilsCmain.DataTranform(lines[1]);
CompositeKey compositeKey = new CompositeKey();
NaturalValue naturalValue = new NaturalValue();
naturalValue.setPrivce(Double.valueOf(lines[2]));
naturalValue.setTimestamp(timestamp);
compositeKey.setStockSymbol(new Text(lines[0]));
compositeKey.setPrice(new DoubleWritable(Double.valueOf(lines[2])));
compositeKey.setTimestamp(new LongWritable(timestamp));
context.write(compositeKey, naturalValue);
} } static class reduce1 extends Reducer<CompositeKey, NaturalValue, Text, Text> {
@Override
protected void reduce(CompositeKey key, Iterable<NaturalValue> vlaue,
Reducer<CompositeKey, NaturalValue, Text, Text>.Context context) throws IOException, InterruptedException { Iterator<NaturalValue> iterator = vlaue.iterator();
StringBuffer stringBuffer = new StringBuffer();
while (iterator.hasNext()) {
NaturalValue naturalValue=iterator.next();
stringBuffer.append("(");
stringBuffer.append(naturalValue.getTimestamp());
stringBuffer.append(","+naturalValue.getPrivce()+")");
} context.write(new Text(key.getStockSymbol()), new Text(stringBuffer.toString()));
}
} public static void main(String[] args) throws Exception { Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(Cmain.class); job.setMapperClass(Map1.class);
job.setReducerClass(reduce1.class); job.setMapOutputKeyClass(CompositeKey.class);
job.setMapOutputValueClass(NaturalValue.class); job.setOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class); job.setSortComparatorClass(CompositeKeyComparator.class);
// 在Reduce端设置分组,使得同一个邮编的在同一个组
job.setGroupingComparatorClass(CompositeGroupingComparator.class);
// 设置分区
job.setPartitionerClass(NaturalKeyPartitioner.class); // 指定输入的数据的目录
FileInputFormat.setInputPaths(job, new Path("/Users/mac/Desktop/stock.txt")); FileOutputFormat.setOutputPath(job, new Path("/Users/mac/Desktop/flowresort")); boolean result = job.waitForCompletion(true);
System.exit(result ? 0 : 1); } }

(7)工具类:将2012-12-09转为20121209这种形式:

package com.book.test1;

public class UtilsCmain {
/**
* 时间
*/
public static long DataTranform(String vaule)
{
String[] args=vaule.split("-");
String datatime=args[0]+args[1]+args[2]; return Long.valueOf(datatime); } }

运行结果:



02Hadoop二次排序2的更多相关文章

  1. MapReduce二次排序

    默认情况下,Map 输出的结果会对 Key 进行默认的排序,但是有时候需要对 Key 排序的同时再对 Value 进行排序,这时候就要用到二次排序了.下面让我们来介绍一下什么是二次排序. 二次排序原理 ...

  2. Hadoop Mapreduce分区、分组、二次排序过程详解[转]

    原文地址:Hadoop Mapreduce分区.分组.二次排序过程详解[转]作者: 徐海蛟 教学用途 1.MapReduce中数据流动   (1)最简单的过程:  map - reduce   (2) ...

  3. Hadoop.2.x_高级应用_二次排序及MapReduce端join

    一.对于二次排序案例部分理解 1. 分析需求(首先对第一个字段排序,然后在对第二个字段排序) 杂乱的原始数据 排序完成的数据 a,1 a,1 b,1 a,2 a,2 [排序] a,100 b,6 == ...

  4. Hadoop学习笔记: MapReduce二次排序

    本文给出一个实现MapReduce二次排序的例子 package SortTest; import java.io.DataInput; import java.io.DataOutput; impo ...

  5. Spark基础排序+二次排序(java+scala)

    1.基础排序算法 sc.textFile()).reduceByKey(_+_,).map(pair=>(pair._2,pair._1)).sortByKey(false).map(pair= ...

  6. (转)MapReduce二次排序

    一.概述 MapReduce框架对处理结果的输出会根据key值进行默认的排序,这个默认排序可以满足一部分需求,但是也是十分有限的.在我们实际的需求当中,往往有要对reduce输出结果进行二次排序的需求 ...

  7. MapReduce自定义二次排序流程

    每一条记录开始是进入到map函数进行处理,处理完了之后立马就入自定义分区函数中对其进行分区,当所有输入数据经过map函数和分区函数处理完之后,就调用自定义二次排序函数对其进行排序. MapReduce ...

  8. Hadoop MapReduce 二次排序原理及其应用

    关于二次排序主要涉及到这么几个东西: 在0.20.0 以前使用的是 setPartitionerClass setOutputkeyComparatorClass setOutputValueGrou ...

  9. hadoop2.2编程:mapreduce编程之二次排序

    mr自带的例子中的源码SecondarySort,我重新写了一下,基本没变. 这个例子中定义的map和reduce如下,关键是它对输入输出类型的定义:(java泛型编程) public static ...

随机推荐

  1. yii2 用 bootstrap 给元素添加背景色

    使用 bootstrap 给元素添加背景色 1.bootstrap 官网:http://getbootstrap.com/ 2.bootstrap 中文官网:http://v3.bootcss.com ...

  2. python之多态与多态性

    1.多态的概念:多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的的概念依赖于继承) 比如:序列类型有多种形态:字符串,列表,元组 动物有多种形态:人,狗,猪 import abc cl ...

  3. __c语言__测一段代码的运行时间

    2017-09-16 13:35:56 感觉很实用. /************************************** time ./a.out 命令所花费的real时间.user时间和 ...

  4. Linux Performance Profiling & Visualization

    https://github.com/figozhang/CLK/tree/master/CLK2016 http://www.linuxep.com/

  5. dom4j解析xml字符串实例

    DOM4J 与利用DOM.SAX.JAXP机制来解析xml相比,DOM4J 表现更优秀,具有性能优异.功能强大和极端易用使用的特点,只要懂得DOM基本概念,就可以通过dom4j的api文档来解析xml ...

  6. 9款国内外垂直领域的在线作图工具:那些可以替代Visio的应用!【转】

    http://www.csdn.net/article/2015-02-12/2823939 摘要:现在越来越多的创业公司都希望提升办公的效率,今天介绍的几款也能提升办公效率,不过它们都属于垂直领域的 ...

  7. PDF.js 分片下载的介绍2:分片下载demo

    上一个章节,简要说了以下分片下载的几个特性.今天主要用示例说明一下pdf.js分片下载. 服务器环境: php7.2 nginx 1.14 ubuntu 18.04测试浏览器:谷歌浏览器 70.0.3 ...

  8. 如何在一小时内更新100篇文章?-Evernote Sync插件介绍

    上一篇"手把手教你制作微信小程序,开源.免费.快速搞定",已经教会你如何快速制作一个小程序,但作为资讯类小程序,内容不可少,并且还需要及时更新. 但是,如果让你复制粘贴,可能还需要 ...

  9. 【ASP.NET Core】浅说目录浏览

    何谓“浅说”?就是一句话说不完,顶多两句话就介绍完毕,然后直接给上实例的解说方式.化繁为简,从七千年前到现在,从老祖宗到咱们,一直都在追求的理想目标,尽可能把复杂的东西变成简单的. 老周告诉你一个可以 ...

  10. 前端切图实战(PSD设计稿转化为前端)

    课程来源:https://www.imooc.com/learn/668 一:读设计稿 划分:头部.尾部.公共部分.大概分多少块.logo的重用.列表有哪些.各部分用什么技术实现等等. 二:建立项目目 ...