Flink05:Flink核心API之DataSet:DataSource、Transformation、Sink

一、DataSet API

DataSet API主要可以分为3块来分析:DataSource、Transformation、Sink。
DataSource是程序的数据源输入。

Transformation是具体的操作,它对一个或多个输入数据源进行计算处理,例如map、flatMap、filter等操作。

DataSink是程序的输出,它可以把Transformation处理之后的数据输出到指定的存储介质中。

二、DataSet API之DataSource

针对DataSet批处理而言,其实最多的就是读取HDFS中的文件数据,所以在这里我们主要介绍两个DataSource组件。

1、基于集合
fromCollection(Collection),主要是为了方便测试使用。它的用法和DataStreamAPI中的用法一样,我们已经用过很多次了。
2、基于文件
readTextFile(path),读取hdfs中的数据文件。这个前面我们也使用过了。

三、DataSet API之Transformation

在这里插入图片描述
这里面的算子我们都是比较熟悉的,在前面DatatreamAPI中都用过,用法都是一样的,所以在这就不再演示了。
mapPartition这个算子我们在Flink中还没用过,不过在Spark 中是用过的,用法也是一样的。
其实mapPartition就是一次处理一批数据,如果在处理数据的时候想要获取第三方资源连接,建议使用mapPartition,这样可以一批数据获取一次连接,提高性能。
下面来演示一下Flink中mapPartition的使用。

1、Flink中mapPartition的使用

scala代码如下:

package com.imooc.scala.batch.transformation

import org.apache.flink.api.scala.ExecutionEnvironment

import scala.collection.mutable.ListBuffer

/**
 * MapPartition的使用:一次处理一个分区的数据
 * 
 */
object BatchMapPartitionScala {
  def main(args: Array[String]): Unit = {
    val env = ExecutionEnvironment.getExecutionEnvironment

    import org.apache.flink.api.scala._
    //生成数据源数据
    val text = env.fromCollection(Array("hello you", "hello me"))

    //每次处理一个分区的数据
    text.mapPartition(it=>{
      //可以在此处创建数据库连接,建议把这块代码放到try-catch代码块中
      //注意:此时是每个分区获取一个数据库连接,不需要每处理一条数据就获取一次连接,性能较高
      val res = ListBuffer[String]()
      it.foreach(line=>{
        val words = line.split(" ")
        for(word <- words){
          res.append(word)
        }
      })
      res
      //关闭数据库连接
    }).print()
    //No new data sinks have been defined since the last execution.
    //The last execution refers to the latest call to 'execute()', 'count()', 'collect()', or 'print()'.
    //注意:针对DataSetAPI,如果在后面调用的是count、collect、print,则最后不需要指定execute即可。
    //env.execute("BatchMapPartitionScala")
  }

}

java代码如下:

package com.imooc.java.batch.transformation;

import org.apache.flink.api.common.functions.MapPartitionFunction;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.util.Collector;

import java.util.Arrays;
import java.util.Iterator;

/**
 * MapPartition的使用:一次处理一个分区的数据
 * 
 */
public class BatchMapPartitionJava {
    public static void main(String[] args) throws Exception{
        ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
        //生成数据源数据
        DataSource<String> text = env.fromCollection(Arrays.asList("hello you", "hello me"));

        //每次处理一个分区的数据
        text.mapPartition(new MapPartitionFunction<String, String>() {
            @Override
            public void mapPartition(Iterable<String> iterable, Collector<String> out)
                    throws Exception {
                //可以在此处创建数据库连接,建议把这块代码放到try-catch代码块中
                Iterator<String> it = iterable.iterator();
                while(it.hasNext()){
                    String line = it.next();
                    String[] words = line.split(" ");
                    for(String word: words){
                        out.collect(word);
                    }
                }
                //关闭数据库连接
            }
        }).print();
    }
}

下面还有一些transformation算子。
在这里插入图片描述

distinct算子比较简单,就是对数据进行全局去重。
join:内连接,可以连接两份数据集。

2、join的用法

scala代码如下:

package com.imooc.scala.batch.transformation

import org.apache.flink.api.scala.ExecutionEnvironment

/**
 * join:内连接
 * 
 */
object BatchJoinScala {
  def main(args: Array[String]): Unit = {
    val env = ExecutionEnvironment.getExecutionEnvironment

    import org.apache.flink.api.scala._
    //初始化第一份数据  Tuple2<用户id,用户姓名>
    val text1 = env.fromCollection(Array((1, "jack"), (2, "tom"), (3, "mick")))
    //初始化第二份数据 Tuple2<用户id,用户所在城市>
    val text2 = env.fromCollection(Array((1, "bj"), (2, "sh"), (4, "gz")))

    //对两份数据集执行join操作
    text1.join(text2)
      //注意:这里的where和equalTo实现了类似于on fieldA=fieldB的效果
      //where:指定左边数据集中参与比较的元素角标
      .where(0)
      //equalTo指定右边数据集中参与比较的元素角标
      .equalTo(0){(first,second)=>{
        (first._1,first._2,second._2)
      }}.print()
  }

}

java代码如下:

package com.imooc.java.batch.transformation;

import org.apache.flink.api.common.functions.JoinFunction;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * join:内连接
 * 
 */
public class BatchJoinJava {
    public static void main(String[] args) throws Exception{
        ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();

        //初始化第一份数据 Tuple2<用户id,用户姓名>
        ArrayList<Tuple2<Integer, String>> data1 = new ArrayList<>();
        data1.add(new Tuple2<Integer,String>(1,"jack"));
        data1.add(new Tuple2<Integer,String>(2,"tom"));
        data1.add(new Tuple2<Integer,String>(3,"mick"));
        DataSource<Tuple2<Integer, String>> text1 = env.fromCollection(data1);
        //初始化第二份数据 Tuple2<用户id,用户所在城市>
        ArrayList<Tuple2<Integer, String>> data2 = new ArrayList<>();
        data2.add(new Tuple2<Integer,String>(1,"bj"));
        data2.add(new Tuple2<Integer,String>(2,"sh"));
        data2.add(new Tuple2<Integer,String>(4,"gz"));
        DataSource<Tuple2<Integer, String>> text2 = env.fromCollection(data2);

        //对两份数据集执行join操作
        text1.join(text2)
                .where(0)
                .equalTo(0)
                //三个输入参数:
                //第一个tuple2是左边数据集的类型,
                //第二个tuple2是右边数据集的类型,
                //第三个tuple3是此函数返回的数据集类型
                .with(new JoinFunction<Tuple2<Integer, String>, Tuple2<Integer, String>, Tuple3<Integer,String,String>>() {
                    @Override
                    public Tuple3<Integer, String, String> join(Tuple2<Integer, String> first, Tuple2<Integer, String> second)
                            throws Exception {
                        return new Tuple3<Integer, String, String>(first.f0,first.f1,second.f1);
                    }
                }).print();

    }
}

3、outerJoin:外连接

scala代码如下:

package com.imooc.scala.batch.transformation

import org.apache.flink.api.scala.ExecutionEnvironment

/**
 * outerJoin:外连接
 * 一共有三种情况
 * 1:leftOuterJoin
 * 2:rightOuterJoin
 * 3:fullOuterJoin
 * 
 */
object BatchOuterJoinScala {
  def main(args: Array[String]): Unit = {
    val env = ExecutionEnvironment.getExecutionEnvironment

    import org.apache.flink.api.scala._
    //初始化第一份数据 Tuple2<用户id,用户姓名>
    val text1 = env.fromCollection(Array((1, "jack"), (2, "tom"), (3, "mick")))
    //初始化第二份数据 Tuple2<用户id,用户所在城市>
    val text2 = env.fromCollection(Array((1, "bj"), (2, "sh"), (4, "gz")))

    //对两份数据集执行leftOuterJoin操作
    text1.leftOuterJoin(text2)
      .where(0)
      .equalTo(0){
        (first,second)=>{
          //注意:second中的元素可能为null
          if(second==null){
            (first._1,first._2,"null")
          }else{
            (first._1,first._2,second._2)
          }
        }
      }.print()

    println("========================================")

    //对两份数据集执行rightOuterJoin操作
    text1.rightOuterJoin(text2)
      .where(0)
      .equalTo(0){
        (first,second)=>{
          //注意:first中的元素可能为null
          if(first==null){
            (second._1,"null",second._2)
          }else{
            (first._1,first._2,second._2)
          }
        }
      }.print()


    println("========================================")

    //对两份数据集执行rightOuterJoin操作
    text1.fullOuterJoin(text2)
      .where(0)
      .equalTo(0){
        (first,second)=>{
          //注意:first和second中的元素都有可能为null
          if(first==null){
            (second._1,"null",second._2)
          }else if(second==null){
            (first._1,first._2,"null")
          }else{
            (first._1,first._2,second._2)
          }
        }
      }.print()
  }
}

java代码如下:

package com.imooc.java.batch.transformation;

import org.apache.flink.api.common.functions.JoinFunction;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;

import java.util.ArrayList;

/**
 * outerJoin:外连接
 * 一共有三种情况
 * 1:leftOuterJoin
 * 2:rightOuterJoin
 * 3:fullOuterJoin
 * 
 */
public class BatchOuterJoinJava {
    public static void main(String[] args) throws Exception{
        ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();

        //初始化第一份数据 Tuple2<用户id,用户姓名>
        ArrayList<Tuple2<Integer, String>> data1 = new ArrayList<>();
        data1.add(new Tuple2<Integer,String>(1,"jack"));
        data1.add(new Tuple2<Integer,String>(2,"tom"));
        data1.add(new Tuple2<Integer,String>(3,"mick"));
        DataSource<Tuple2<Integer, String>> text1 = env.fromCollection(data1);
        //初始化第二份数据 Tuple2<用户id,用户所在城市>
        ArrayList<Tuple2<Integer, String>> data2 = new ArrayList<>();
        data2.add(new Tuple2<Integer,String>(1,"bj"));
        data2.add(new Tuple2<Integer,String>(2,"sh"));
        data2.add(new Tuple2<Integer,String>(4,"gz"));
        DataSource<Tuple2<Integer, String>> text2 = env.fromCollection(data2);

        //对两份数据集执行leftOuterJoin操作
        text1.leftOuterJoin(text2)
                .where(0)
                .equalTo(0)
                .with(new JoinFunction<Tuple2<Integer, String>, Tuple2<Integer, String>, Tuple3<Integer,String,String>>() {
                    @Override
                    public Tuple3<Integer, String, String> join(Tuple2<Integer, String> first, Tuple2<Integer, String> second)
                            throws Exception {
                        if(second==null){
                            return new Tuple3<Integer, String, String>(first.f0,first.f1,"null");
                        }else{
                            return new Tuple3<Integer, String, String>(first.f0,first.f1,second.f1);
                        }
                    }
                }).print();
        System.out.println("==============================================");
        //对两份数据集执行rightOuterJoin操作
        text1.rightOuterJoin(text2)
                .where(0)
                .equalTo(0)
                .with(new JoinFunction<Tuple2<Integer, String>, Tuple2<Integer, String>, Tuple3<Integer,String,String>>() {
                    @Override
                    public Tuple3<Integer, String, String> join(Tuple2<Integer, String> first, Tuple2<Integer, String> second)
                            throws Exception {
                        if(first==null){
                            return new Tuple3<Integer, String, String>(second.f0,"null",second.f1);
                        }else{
                            return new Tuple3<Integer, String, String>(first.f0,first.f1,second.f1);
                        }
                    }
                }).print();
        System.out.println("==============================================");
        //对两份数据集执行rightOuterJoin操作
        text1.fullOuterJoin(text2)
                .where(0)
                .equalTo(0)
                .with(new JoinFunction<Tuple2<Integer, String>, Tuple2<Integer, String>, Tuple3<Integer,String,String>>() {
                    @Override
                    public Tuple3<Integer, String, String> join(Tuple2<Integer, String> first, Tuple2<Integer, String> second)
                            throws Exception {
                        if(first==null){
                            return new Tuple3<Integer, String, String>(second.f0,"null",second.f1);
                        }else if(second==null){
                            return new Tuple3<Integer, String, String>(first.f0,first.f1,"null");
                        }else{
                            return new Tuple3<Integer, String, String>(first.f0,first.f1,second.f1);
                        }
                    }
                }).print();
    }
}

4、cross:获取两个数据集的笛卡尔积

scala代码如下:

package com.imooc.scala.batch.transformation

import org.apache.flink.api.scala.ExecutionEnvironment

/**
 * cross:获取两个数据集的笛卡尔积
 * 
 */
object BatchCrossScala {
  def main(args: Array[String]): Unit = {
    val env = ExecutionEnvironment.getExecutionEnvironment

    import org.apache.flink.api.scala._
    //初始化第一份数据
    val text1 = env.fromCollection(Array(1, 2))
    //初始化第二份数据
    val text2 = env.fromCollection(Array("a", "b"))

    //执行cross操作
    text1.cross(text2).print()

  }

}

java代码如下:

package com.imooc.java.batch.transformation;

import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;

import java.util.Arrays;

/**
 * cross:获取两个数据集的笛卡尔积
 * 
 */
public class BatchCrossJava {
    public static void main(String[] args) throws Exception{
        ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
        //初始化第一份数据
        DataSource<Integer> text1 = env.fromCollection(Arrays.asList(1, 2));
        //初始化第二份数据
        DataSource<String> text2 = env.fromCollection(Arrays.asList("a", "b"));
        //执行cross操作
        text1.cross(text2).print();
    }
}

union:返回两个数据集的总和,数据类型需要一致。
和DataStreamAPI中的union操作功能一样。

5、first-n:获取集合中的前N个元素

scala代码如下:

package com.imooc.scala.batch.transformation

import org.apache.flink.api.common.operators.Order
import org.apache.flink.api.scala.ExecutionEnvironment

import scala.collection.mutable.ListBuffer

/**
 * first-n:获取集合中的前N个元素
 * 	 */
object BatchFirstNScala {
  def main(args: Array[String]): Unit = {
    val env = ExecutionEnvironment.getExecutionEnvironment
    val data = ListBuffer[Tuple2[Int,String]]()
    data.append((2,"zs"))
    data.append((4,"ls"))
    data.append((3,"ww"))
    data.append((1,"aw"))
    data.append((1,"xw"))
    data.append((1,"mw"))

    import org.apache.flink.api.scala._
    //初始化数据
    val text = env.fromCollection(data)

    //获取前3条数据,按照数据插入的顺序
    text.first(3).print()
    println("==================================")

    //根据数据中的第一列进行分组,获取每组的前2个元素
    text.groupBy(0).first(2).print()
    println("==================================")

    //根据数据中的第一列分组,再根据第二列进行组内排序[倒序],获取每组的前2个元素
    //分组排序取TopN
    text.groupBy(0).sortGroup(1,Order.DESCENDING).first(2).print()

  }
}

java代码如下:

package com.imooc.java.batch.transformation;

import org.apache.flink.api.common.operators.Order;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.tuple.Tuple2;

import java.util.ArrayList;

/**
 * first-n:获取集合中的前N个元素
 * 
 */
public class BatchFirstNJava {
    public static void main(String[] args) throws Exception{
        ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
        ArrayList<Tuple2<Integer, String>> data = new ArrayList<>();
        data.add(new Tuple2<Integer,String>(2,"zs"));
        data.add(new Tuple2<Integer,String>(4,"ls"));
        data.add(new Tuple2<Integer,String>(3,"ww"));
        data.add(new Tuple2<Integer,String>(1,"aw"));
        data.add(new Tuple2<Integer,String>(1,"xw"));
        data.add(new Tuple2<Integer,String>(1,"mw"));
        //初始化数据
        DataSource<Tuple2<Integer, String>> text = env.fromCollection(data);

        //获取前3条数据,按照数据插入的顺序
        text.first(3).print();
        System.out.println("====================================");

        //根据数据中的第一列进行分组,获取每组的前2个元素
        text.groupBy(0).first(2).print();
        System.out.println("====================================");

        //根据数据中的第一列分组,再根据第二列进行组内排序[倒序],获取每组的前2个元素
        //分组排序取TopN
        text.groupBy(0).sortGroup(1, Order.DESCENDING).first(2).print();
    }
}

四、DataSet API之DataSink

Flink针对DataSet提供了一些已经实现好的数据目的地
其中最常见的是向HDFS中写入数据
writeAsText():将元素以字符串形式逐行写入,这些字符串通过调用每个元素的toString()方法来获取
writeAsCsv():将元组以逗号分隔写入文件中,行及字段之间的分隔是可配置的,每个字段的值来自对象的toString()方法

还有一个是print:打印每个元素的toString()方法的值
这个print是测试的时候使用的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

做一个有趣的人Zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值