02.Spark 标签生成(Java和Scala的两种实现)

2018/10/12 17:32
阅读数 77

Spark 标签生成(Java和Scala的两种实现)

气温数据多重聚合

[Scala]实现聚合气温数据。聚合出Max,Min.AVG

/**
 *  气温数据聚合应用
*/
object TempAggDemo{
  def main(args:Array[String]):Unit={
    //配置一下
    val conf=new SparkConf()
    conf.setAppName("tempAgg")
    conf.setMaster("local")
    val sc=new SparkContext(conf)
    //1.加载文件
    val rdd1=sc.textFile("file:///d:/mr/temp3.dat")
    //2.切割成对(1930,54)
    val rdd2=rdd1.map(line=>{
      var arr=line.split(" ")
      (arr(0).toInt,arr(1).toInt)
    PairRDD
    //3.分组  按key(年度)分组RDD一但变成了二元组就变成了PairRDD
      //(19300->{23,34,67},1931->{.......})
    val rdd3=rdd2.groupByKey()
    //4.对组内元素进行统计聚合 mapValues()可以迭代的量   K不需要变,看V变
      val rdd4=rdd3.mapValues(it=>{
      val mx= it.max   //max[B >:Int](implicit cmp:Ordering[B]) 最大值
      val mn=it.min
      val sum=it.sun
      val size=it.size
      (mx,mn,sum.toFloat /size) //把每一个年度的气温数据聚合成了三元组
      })
     //5.按照年度排序
      val rdd5=rdd4.sortByKey(true) //true升序
     //6.输出
    rdd5.collect().foreach(println)
  }
}

reduceByKey的特点:reduceByKey不会改变K,V的类型。进来是什么类型,出去还是什么类型。

如果要聚合三个值,max,min,(sum,size)通过reduceByKey一次出来。原来的K,V,由于reduceByKey不能改变类型。而我们要的结果至少包含三个结果。它们起码是三元组。 [Scala]

object TempAggDemo2{
  def main(args:Array[String]):Unit={
    val conf=new SparkConf()
    conf.setAppName("tempAgg")
    conf.setMaster("local")
    val sc=new SparkContext(conf)
    //1.加载文件
    val rdd1=sc.textFile("file:///d:/mr/temp3.dat")
    //2.切割成对(1930,54)
    val rdd2=rdd1.map(line=>{
    var arr=line.split(" ")
    //(mx,mn,sum,count)
    val year=arr(0).toInt
    val tmp=arr(1).toInt
    //这里又是一个元组(temp最高气温,temp最低气温,temp气温总和,)在变换的时候我们把V当成一个元组来代替,K就是年份。按K聚合,所以所有年份相同的V都要在一起聚合。而此刻的V不是一个单纯的数字了。它是一个元组。把它重向的捏在一起。reduceByKey的特点就是它不能改变V的类型。
    (year,(temp,temp,temp,1))
})
    //每一元素后面都带1
    // rdd2.collect().foreach(println) //(1953,(23,23,23,1))(1951,(26,26,26,1))
    //3.聚合  reduceByKey(func:((Int,Int,Int,Int),(Int,Int,Int,Int))=>(Int,Int,Int,Int))  它是两个元组组成一个元组.聚合是纵向捏合的过程。两个元组,它捏合完后产生的新值。还要跟第三个再聚,不断的取最大值最小值和avg
    val rdd3=rdd2.rdd2.reduceByKey((a,b)=>{
      import scla.math._
      (max(a._1,b_1),min(a._2,b_2),a._3+b._3,a._4+b._4)
    })
    //rdd3.collect().foreach(println) //(1921,(48,-50,348,53))(1933,(41,-44,-38,49))
    //4.变换 K不需要变K是年度,把V变掉就行了 V是一个元组
    val  rdd4=rdd3.mapValue(t=>{
      (t._1,t._2,t._3.toFloat /t.-4)
    }).sortByKey()
  }
}

[Java]

map(Function<String,R>f) JavaRDD<R>它就没有各种ByKey的操作
mapToPair(PairFunction<String..>)JavaPairRDD<K2,V2>
String 输入的行 Integer K 四元组Tuple4<>
import scala.Float;
import scala.Tuple2;
import scala.Tuple3;
import scala.Tuple4;
public class TempAggDemeJava2{
   public static void main(String[] args){
        SparkConf conf=new SparkConf();
        conf.setAppName("tempAgg");
        conf.setMaster("local");
        JavaSparkContext sc=new JavaSparkContext(conf);
        //1.加载文件
       JavaRDD<String>rdd1=sc.textFile(path:"file:///d:/mr/temp3.dat");
       //2.变换(1903,(32,23,23,1))
       JavaRDD<Integer,Tuple4<Integer,Integer,Integer,Integer>>rdd2=
       rdd1.mapToPair(newPairFunction<String,Integer,
       Tuple4<Integer,Integer,Integer,Integer>>(){
       public Tuple2<Integer,Tuple4<Integer,Integer,Integer,Integer>>
       call(String s)throws Exception{
       String[] arr=s.plit(regex:" ");
       int year=Integer.parseInt(arr[0]);
       int tmp=Integer.parseInt(arr[1]);
       Tuple4<Integer,Integer,Integer,Integer> v=new                              Tuple4<Integer,Integer,Integer,Integer>(tmp,tmp,temp,_4:1);
       
      return new Tuple2<Integer,Tuple4<Integer,Integer,Integer,Integer>>(year,v);
       }
      });
      //3.聚合
      JavaPairRDD<Integer,Tuple4<Integer,Integer,Integer,Integer>>redd2.reduceByKey(
             new Function2<Tuple4<Integer,Integer,Integer,Integer>,
             Tuple4<Integer,Integer,InInteger,Integer,Integer,Integer>,
             Tuple4<Integer,Integer,Integer,Integer>>(){
             public Tuple4<Integer,Integer,Integer,Integer>call
             (Tuple4<Integer,Integer,Integer,Integer>v1,
              Tuple4<Integer,Integer,Integer,Integer>v2)throws Exception{
                 //v1和v2是返回一个新的元组
                 int mx=Math.max(v1._1(),v2._1());
                 int mn=Math.min(v1._2(),v2._2());
                 int sum=v1._3()+v2._3();
                 int count=v1._4()+v2._4();
                 return new Tuple4<Integer,Integer,Integer,Integer>(mx,mn,sum,count);
               }
             });
       //4.map取出avg K是年度  V变成了三元组
            JavaPairRDD rdd4=rdd3.mapValues(new Function<Tuple4<Integer,Integer,Integer,Integer>,
            Tuple3<Integer,Integer,Float>>(){
            public Tuple3<Integer,Integer,Float>call
            (Tuple4<Integer,Integer,Integer>v1)throws Exception{
            return new Tuple3<Integer,Integer,Float>(v1._1(),v1._2(),_3:         (float)v1._3() /v1._4());
            }
       });
     //5.排序
     JavaPairRDD<Integer,Tuple3<Integer,Integer,Float>>rdd5=rdd4.sortByKey();
     //6.列表
     List<Tuple2<Integer,Tuple3<Integer,Integer,Float>>> list=rdd5.collect();
     for(Tuple2<Integer,Tuple3<Integer,Integer,Float>> t:list){
       System.out.println(t);
     }
   }
}

[标签生成Scala版本]

[TaggejScala.scala]标签生成Scala
​```scala
/**
*
*标签生成
*/
object TaggenScala{
  def main(args:Array[String]):Unit={
    val conf=new SparkConf()
    conf.setAppName("Taggen")
    conf.setMaster("local")
    val sc=new SparkContext(conf)
    //1.加载文件,将泛型加全
    val rdd1:RDD[(String,util.List[String])]=
    sc.textFile("file:///d:/mr/temptags.txt")
    //2.解析每行的json数据成为集合  //map这种是变换
    val rdd2:RDD[(String)]=rdd1.map(line=>{
      val arr:Array[String]=line.split("\t")
      //提取商家id
      val busii:String=arr(0)
      //json对象
      val json:String=arr(1)
      val list:java.util.List[String]=TagUtil.extractTag(json)
      Tuple2[String,java.util.List[String]](busid,list)
    })
    //3.过滤空集合  filter(f:((String,util.List[String]))=>Boolean),(String,util.List[String])这个参数是二元组,返回值是Boolean,rdd2.filter()这里可以用一个高阶函数传进去。传清楚的话它就是一个元组rdd2.filter(t=>{ }),要把这个元组定义齐全的话。类型可以声明,它的类型是一个二元组rdd2.filter((t:Tuple2[String,java.util.List[String]])=>
    val rdd3:RDD[(String,util.List[String])]=
    rdd2.filter((t:Tuple2[String,java.util.List[String]])=>{
      !t._2.isEmpty  //二元组一旦进来就可以拿到它第二个元素,看它是否为空
    })
    //4.将值压扁 flatMapValues[U](f:(util.List[String]))=>TraversableOnce[U]):这个是对值进行压扁,如果对值一旦压扁。值压扁之后值压扁之后,每一值都会跟K从新组合新的K。 flatMap:
    val rdd4:RDD[(String,String)]rdd3.flatMapValues((list:java.util.List[String])=>{
      //导入隐式转换
      import scala.collection.JavaConversions._
      //返回list的话它需要返回可以迭代的量,需要导入隐式转换
    })
    //5.滤掉数组的tag,它的类型没有变还是元组
    val rdd5:RDD[(String,String)]=rdd4.filter((t:Tuple2[String,String])=>{
      try{
        //
        Integer.pparseInt(t._2)
        false 
      }catch{
        case _=>true
      }
    })
    //6.标一成对,第5步已经是一对了但是不是想要的。需要重新配对成新的一对。
    val rdd6:RDD[Tuple2[Tuple2[String,String],Int]]=
    rdd5.map((t:Tuple2[String,String])=>{
          Tuple2[Tuple2[String,String],Int](t,1)
    })              //新的二元组是一个嵌套的二元组,元组是Optin的方法
    //7.聚合
    val rdd7:RDD[Tuple2[Tuple2[String,String],Int]]=
    rdd6.reduceByKey((a:Int,b:Int)=>{
      a+b
    })
    //8.重组
    val rdd8:RDD[Tuple2[String,Tuple2[String,Int]]]=
    rdd7.map((t:Tuple2[Tuple2[String,String],Int])=>{
      Tuple2[String,List[Tuple2[String,Int]]](t._1._1,Tuple2[String,Int](t._1._2,t._2)::Nil)  //List里面的元素是二元组
      //Tuple2[String,Tuple2[String,Int]](t._1._1,Tuple2[String,Int](t._1._2,t._2)::Nil) //在reduceByKey它是纵向捏合,把一个K下所有的V聚合在一起形成一个值。但又不能改变V的类型。如果原来的K是一个二元组。最终把所有的V聚完之后还是一个二元组。这是不合适的。此刻的目的是把它同一商家下的所有评论都放一起。每一个二元组都做到集合里面去。这样一来两个集合就可以聚到一个集里面去了。当我们变换的时候,我们不会把它变成一个二元组。 而是把它变成集合。(Tuple2[String,Int](t._1._2,t._2)::Nil)    
    })     //
    //9.reduceByKey
    val rdd9:RDD[Tuple2[String,List[Tuple2[String,Int]]]] =
    rdd8.reduceByKey((a:List[Tuple2[String,Int]],b:List[Tuple2[String,Int]])=>{
      a:::b  //::是一个数字和一个集合的添加,[B >:(String,Int)](x:B):它是一个元组结尾的操作符是右操作符。
            //:::[B >: (String,Int)](prefix: List[B])这是一个界定,B是List 它是柯里化函数
    })
    //10.分组内排序
    val rdd10:RDD[Tuple2[String,List[Tuple2[String,Int]]]] =
    rdd9.mapValues((list:List[Tuple2[String,Int]]))=>{
      //sortBy[B](f:((String,Int))=>B)(implicit ord:Ordering[B]),sortBy它要排序它的元素是一个元组,把它的类型(二元组)给它。  List集合是不可变集合(immutable)  源码  typeList[+A]=scala.collection.immutable.List[A] val List=scala.collection.immutable.List  所以它排序完之后产生的是新集合。
      val list2:List[Tuple2[String,Int]]=list.sortBy((t:Tuple2[String,Int])=>{
        -t._2
      })
      //取前5
      list2.take(5) 
    })
    //11.商家间排序  sortBy[K](f:((String,List[(String,Int)]))=>K,A,ASCENDING:Boolean=true,numpartitions:Int...)它是一个高阶
    val rdd11:RDD[Tuple2[String,List[Tuple2[String,Int]]]] =
    rdd10.sortBy((t:Tuple2[String,List[Tuple2[String,Int]]])=>{
      t.-2(0)._2  //t.-2就是集合(0)就是商家的评论最大数。再把它取出来。
    },false)
    //收集  打印
    rdd11 .collect().foreach(println)
  }
}
总结:把所有泛型类型都定义上。
public class TagUtil{
  /*
  *从json中抽取评论集合
  */
  public static List<String>extractTag(String json){
    List<String>list=new ArrayList<String>();
    //将字符串解析成json对象
    JSONObject obj=JSON.parseObject(json);
    JSONArray arr=obj.getJSONArray(key:"extInfoList");
    if(arr !=null && arr.size()>0){
       //得到数组的第一json对象
      JSONObject firstObj=arr.getJSONObject(index:0);
      JSONArray values=firstObj.getJSONArray(key:"values");
      if(arr !=null &&arr.size()>0){
        //得到数组的第一个json对象
        JSONObject firstObj=arr.getJSONObject(index:0);
        JSONArray values=firstObj.getJSONArray(key:"values");
        if(values !=null && arr.size()>0){
          //得到字符串解析成json对象
          JSONObject firstObj=arr.getJSONObject(index:0);
          JSONArray values=firstObj.getJSONArray(key:"values");
          if(values !=null &&values.size()>0){
            for(int i=0;i<values.size();i++){
              String tag=values.getString(i);
              list.add(tag);
            }
          }
        }
        return list;
      }
      
  }
}

[TagUtil.java]

public class TagUtil{
  //从json中抽取评论集合
  public static List<String>extractTag(String json){
    List<Stromg>list=new ArrayList<String>();
    //将字符串解析成json对象
    JSONObject obj=JSON.parseObject(json);
    JSONArray arr=obj.getJSONArray("extInfoList");
    if(arr !=null && arr.size()>0){
      //得到数组的第一个json对象
      JSONObject firstObj=arr.getJSONObject(0);
      JSONArray values=firstObj.getJSONArray("values");
      if(arr !=null && arr.size()>0){
        //得到数组的第一个json对象
        JSONObject firstObj=arr.getJSONObject(0);
        JSONArray values=firstObj.getJSONArray("values");
        if(values !=null &&values.size()>0){
          for(int i=0;i<values.size();i++){
            String tag=values,getString(i);
            list.add(tag);
          }
        }
      }
      return list;
    }
  }
}

//java方法定义
public staic <T>T getMiddle(List<T>list){
  return list.get(list.size() /2);
}
@Test
public void testMethod(){
  List<Integer>list=new ArrayList<Integer>();
  list.add(1);
  list.add(2);
  list.add(3);
  System.out.println(getMiddle(list));
}

Maven

<dependency>
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId> fastjson</artifactId>
    <version>1.2.24</version>
  </dependency>
</dependency>

[标签生成Java版本]

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;

public class TaggenJava2{
  public static void main(String[] args){
    SparkConf conf=new SparkConf();
    conf.setAppName("tempAgg");
    conf,setMaster("local");
    JavaSparkContext sc=new JavaSparkContext(conf);
    //1.加载文件
    JavaRDD<String>rdd1=sc.textFile(path:"file:///d:/tenotags.txt");
    //变换   2. 切割
    JavaPairRDD<String,List<String>>rdd2=
    rdd1.mapToPair(new PairFunction<String,String,List<String>>(){
      public Tuple2<String,List<String>>call(String s)throws Exception{
        String[] arr=s.split(regex:"\t");
        String busid=arr[0];
        List<String>tags=TagUtil.extractTag(arr[1]);
        return new Tuple2<String,List<String>>(busid,tags); //现在已经把它变成集合了,空集合要把它滤掉
      }
    });
    //注意:操作过程期间,集合过滤越往前越好。
    //3.过滤空集合
    JavaPairRDD<String,List<String>>rdd3=
      rdd2.filter(new Function<Tuple2<String,List<String>>,Boolean>(){
        public Boolean call(Tuple2<String,List<String>>t)throws Exception{
          return !t._2().isEmpty();
        }
      });
     //4.压扁值
    JavaPairRDD<String,String>rdd4=
      rdd3.flatMapValues(new Function<List<String>,Iterable<String>>(){
      public Iterable<String> call(List<String> v1)throws Exception{
        return v1;
      }
    });
    //5.过滤掉数字标签,过滤的话需要把K和V传进来,它是过滤不会改变内容
    rdd4.filter(new Function<Tuple2<String,String>,Boolean>(){
      public Boolean call(Tuple2<String,String>t)throws Exception{
        try{
          Integer.parseInt(t._2());
          return false;
        }catch(Exception e){
          e.printStackTrace();
        }
        return true;
      }
    });
     //6.重组,标1成对 新K是二元组
    JavaPairRDD<Tuple2<String,String>,Integer> rdd6=
      rdd5.mapToPair(new PairFunction<Tuple2<String,String>,
      Tuple2<String,String>,Integer>(){
            public Tuple2<Tuple2<String,String>,Integer>call
               (Tuple2<String,String>t)throws Exception{
                  return new Tuple2<Tuple2<String,String>,Integer>(t,1);
                }
        });
      //7.聚合值
    JavaPairRDD<Tuple2<String,String>,Integer> rdd7=
      rdd6.reduceByKey(new Function2<Integer,Integer,Integer>(){
        public Integer call(Integer v1,Integer v2)throws Exception{
         return v1+v2;
      }
    });
    //8.重组组员(busid,(tag,num))  不是把它变成元组是把它变成集合
    JavaPairRDD<String,List<Tuple2<String,Integer>>>rdd8=
    rdd7.mapToPair(new PairFunction<Tuple2<Tuple2<String,String>,Integer>,
    String,Tuple2<String,Integer>>(){
      public Tuple2<String,List<Tuple2<String,Integer>>>call
       (Tuple2<Tuple2<String,String>,Integer>t)thros Exception{
         List<Tuple2<String,Integer>>list=new ArrayList<Tuple2<String,Integer>>();
          list.add(new Tuple2<String,Integer>(t._1._2,t._2));
            return new Tuple2<String,Tuple2<String,Integer>>(t._1._1,
                   new Tuple2<String,Integer>(t._1._2,t._2));            
      } 
    });
    //9.聚合  变成集合了,把两个集合变成一个集合
    JavaPairRDD<String,List<Tuple2<String,Integer>>> rdd9=rdd8.reduceByKey(
      new Function2<List<Tuple2<String,Integer>>,List<Tuple2<String,Integer>>,
      List<Tuple2<String,Integer>>>(){
        public List<Tuple2<String,Integer>>call(List<Tuple2<String,Intger>>
        v1,List<Tuple2<String,Integer>>v2)throws Exception{
           v1.addAll(v2); //v1的所有集合添加所有v2的集合,没有返回值
            return v1;
        }
      });
    //10.商家内排序,对V变换,此时list是V
    JavaPairRDD<String,List<Tuple2<String,Integer>>> rdd10=
    rdd9.mapValues(new Funciton<List<Ti[le2<String,Integer>>,
    List<Tuple2<String,Integer>>>(){
    public List<Tuple2<String,Integer>>call(List<Tuple2<String,Integer>>v1)
      throws Exception{
     //Comparator对比器二元元组sort(Comparator<?super Tuple2<String,Integer>>>c])
      v1.sort(new Comparator<Tuple2<String,Integer>>(){
        //比较集合中的两个元素的大小有三家评论和数量
        public int compare(Tuple2<String,Intger>o1,Tuple2<String,Integer>o2){
          return -(o1._2-o2._2); //-()降序
        }
      });
      
      //subList返回的列表是不能串行化的,要用一个串行化的方法返回这个值。
      List<Tuple2<String,Integer>>newList=new ArrayList<Tuple2<String,Integer>>();
      newList.addAll(v1.subList(0,v1.size()>5?5:v1.size()));
      
      //subList(int fromIndex,int toIndex)
     // return v1;//sort是没有返回值的,它是对V本身排序的
     //return v1.subList(0,4);//前5  有些集合里面可能没有5个元素会报错要先判断一下
      //return v1.subList(0,v1.size()>5?5:v1.size());//>5就5否则的话就v1.size
      return newList;
    }
    }); 
   //11.变换pairRDD到普通RDD,否则没有sortBy方法,这里先把它转成非JavaPairRDD的  JavaPairRDD它没有排序的方法,只有按Key
     //第一个是二元组,第二个是List 这个是评论数量<Tuple2<String,Ingerger>                 
     JavaRDD<Tuple2<String,List<Tuple2<String,Ingerger>>>>rdd11=
     rdd10.map(newFunction<Tuple2<String,List<Tuple2<String,
     Integer>>>,Tuple2<String,List<Tuple2<String,Integer>>>>(){
       public Tuple2<String,List<Tuple2<String,Integer>>>call
      (Tuple2<String,List<Tuple2<String,Integer>>>v1)throws Exception{
         return t;
       }                                 
      });
      //12.商家间排序                                 
     //Object这是你要返回的值,Function这是一个元组,它返回的是一个整数
     //按照每一个商家它第一个评论的数量,来倒排
     rdd11.sortBy(new Function<Tuple2<String,List<Tuple2<String,Integer>>>,
     Integer(){
       public Integer call(Tuple2<String,List<Tuple2<String,Integer>>>t)
       throw Exception{
         return -t._2.get(0)._2;
       }
      },true,2);// sortBy 
                                                                         
      List<Tuple2<String,String>>list=rdd5.collect();
       for(Tuple2 t:list){
            System.out.println(t);
      }
    
    //输出rdd7
     List list=rdd8.collect();
       for(Object o:list){
            System.out.println(o);
      }
  }
}
                                        
[sort源码]//sort没有返回值
default void sort(Comparator<?super E>c){
   Object[] a=this.toArray();
   Arrays.sort(a,(Comparator)c);
   ListIterator<E>i=this.listIterator();
  for(Object e : a){
    i.next();
    i.set((E)e);
  }
}  
                                        
                                        JavaRDD<Tuple2<String,List<Tuple2<String>>>>.....      
[sortBy]
//JFunction[T,S]参数,ascending:升降序  numPartition:分区                             
def sortBy[S](f:JFunction[T,S],ascending:Boolean,numPartition:Int):JavaRDD[T]
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部