flink学习(二)

学习目标

1.入门案例(掌握)
2.输入数据集DataSource(掌握)
3.DataSet的Transformation(掌握)
4.数据的输出DataSink(掌握)
5.Flink的广播变量(掌握)
6.Flink的分布式缓存(掌握)
7.Flink的累加器(了解)

1.入门案例

/**
 * 单词统计,入门案例
 */
object BatchWordCount {
  def main(args: Array[String]): Unit = {
    //1.创建批处理执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.构建数据源
    //导入隐式转换包
    import org.apache.flink.api.scala._
    val sourceDataSet: DataSet[String] = env.fromCollection(List("hadoop hadoop spark","flink flink hive"))
    //3.数据处理
    val wordAndOne: DataSet[(String, Int)] = sourceDataSet.flatMap(x=>x.split(" ")).map((_,1))
    val resultDataSet: DataSet[(String, Int)] = wordAndOne.groupBy(0).reduce((v1, v2)=>(v1._1,v1._2+v2._2))
    //4.打印测试
    resultDataSet.print()

  }
}

2.输入数据集DataSource

1) 基于本地集合的 source

1.1 使用 env.fromElements(), 这种方式也支持 Tuple, 自定义对象等复合形式。

//使用 env.fromElements(), 这种方式也支持 Tuple, 自定义对象等复合形式
object BatchFromElementsDemo {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.使用 env.fromElements构建数据集
    import org.apache.flink.api.scala._
    val sourceElement: DataSet[String] = env.fromElements("hadoop hadoop hive flink")
    //3.输出测试
    sourceElement.print()

  }
}

1.2 使用 env.fromCollection(),这种方式支持多种 Collection 的具体类型

 

object BatchFromCollectionDemo {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.使用env.fromCollection()构建数据集
    import org.apache.flink.api.scala._
    val sourceCollection: DataSet[String] = env.fromCollection(List("hadoop hadoop","flink flink"))
    //3.输出打印
    sourceCollection.print()
  }
}

1.3 使用 env.generateSequence()方法创建基于 Sequence 的 DataSet

object BatchGenerateSequenceDemo {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.使用generateSequence构建数据集
    val numberDataSet: DataSet[Long] = env.generateSequence(1,10)
    //3.打印输出
    numberDataSet.print()
  }
}

2) 基于文件的 source

2.1 读取本地文件

object BatchFromLocalFileSource {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.从本地文件构建数据集
    val localFileSource: DataSet[String] = env.readTextFile("day02/data/input/wordcount.txt")
    //3.打印输出
    localFileSource.print()
  }
}

2.2 读取 HDFS 数据

object BatchFromLocalFileSource {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.从本地文件构建数据集
    val localFileSource: DataSet[String] = env.readTextFile("day02/data/input/wordcount.txt")
    //3.打印输出
    localFileSource.print()
  }
}

2.3 读取 CSV 数据

object BatchFromCSVFileSource {
  case class Subject(id:Int,name:String)
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.从csv文件构建数据集
    import org.apache.flink.api.scala._
    val csvDataSet: DataSet[Subject] = env.readCsvFile[Subject]("day02/data/input/subject.csv")
    //3.输出打印
    csvDataSet.print()
  }
}

2.4 读取压缩文件

在这里插入代码片 

object BatchFromCompressFileSource {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.从压缩文件中构建数据集
    val compressFileSource: DataSet[String] = env.readTextFile("day02/data/input/wordcount.txt.gz")
    //3.输出打印
    compressFileSource.print()
  }
}

2.5 基于文件的 source(遍历目录)

在这里插入代码片object BatchFromFolderSource {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.开启recursive.file.enumeration
    val configuration: Configuration = new Configuration()
    configuration.setBoolean("recursive.file.enumeration", true)
    //3.根据遍历多级目录来构建数据集
    val result: DataSet[String] = env.readTextFile("day02/data/input/a").withParameters(configuration)
    result.print()
  }
}

3、DateSet 的 Transformation

3.1 map 函数

  1. 获取 ExecutionEnvironment 运行环境

  2. 使用 fromCollection 构建数据源

  3. 创建一个 User 样例类

  4. 使用 map 操作执行转换

  5. 打印测试

package com.czxy.flink.batch.transfromation

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

/**
 * 需求:
 * 使用 map 操作, 将以下数据
 * "1,张三", "2,李四", "3,王五", "4,赵六"
 * 转换为一个 scala 的样例类。
 */
object BatchMapDemo {
  //3.创建样例类
  case class user(id:Int,name:String)
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env = ExecutionEnvironment.getExecutionEnvironment
    //2.构建数据集
    import org.apache.flink.api.scala._
    val sourceDataSet: DataSet[String] = env.fromElements("1,张三", "2,李四", "3,王五", "4,赵六")
    //4.数据转换处理
    val userDataSet: DataSet[user] = sourceDataSet.map(item => {
      val itemsArr: Array[String] = item.split(",")
      user(itemsArr(0).toInt, itemsArr(1))
    })
    //5.打印输出
    userDataSet.print()
  }
}

3.2 flatMap 函数

package com.czxy.flink.batch.transfromation

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

import scala.collection.mutable

/**
 * 需求:
 * 分别将以下数据, 转换成 国家 、 省份 、 城市 三个维度的数据。
 * 将以下数据
 * 张三,中国,江西省,南昌市
 * 李四,中国,河北省,石家庄市
 * Tom,America,NewYork,Manhattan
 * 转换为
 * 张三,中国
 * 张三,中国江西省
 * 张三,中国江西省南昌市
 */
object BatchFlatMapDemo {
  def main(args: Array[String]): Unit = {
    /**
     * 1) 构建批处理运行环境
     * 2) 构建本地集合数据源
     * 3) 使用 flatMap 将一条数据转换为三条数据
     * a. 使用逗号分隔字段
     * b. 分别构建国家、 国家省份、 国家省份城市三个元组
     * 4) 打印输出
     */
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    import org.apache.flink.api.scala._
    val sourceDatSet: DataSet[String] = env.fromCollection(List(
      "张三,中国,江西省,南昌市",
      "李四,中国,河北省,石家庄市",
      "Tom,America,NewYork,Manhattan"
    ))
    val resultDataSet: DataSet[(String, String)] = sourceDatSet.flatMap(item => {
      val itemsArr: mutable.ArrayOps[String] = item.split(",")
      List(
        (itemsArr(0), itemsArr(1)),
        (itemsArr(0), itemsArr(1) + itemsArr(2)),
        (itemsArr(0), itemsArr(1) + itemsArr(2) + itemsArr(3))
      )
    })

    resultDataSet.print()
  }
}

3.3 mapPartition 函数

package com.czxy.flink.batch.transfromation

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

/**
 * 需求:
 * 使用 mapPartition 操作, 将以下数据
 * "1,张三", "2,李四", "3,王五", "4,赵六"
 * 转换为一个 scala 的样例类。
 */
object BatchMapPartitionDemo {

  case class user(id:Int,name:String)
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.构建数据集
    import org.apache.flink.api.scala._
    val sourceDataSet: DataSet[String] = env.fromElements("1,张三", "2,李四", "3,王五", "4,赵六")

    //3数据处理
    val userDataSet: DataSet[user] = sourceDataSet.mapPartition(itemPartition => {
      itemPartition.map(item => {
        val itemsArr: Array[String] = item.split(",")
        user(itemsArr(0).toInt, itemsArr(1))
      })
    })
    //4.打印数据
    userDataSet.print()


  }
}

3.4 Rebalance

在这里插入代码片package com.czxy.flink.batch.transfromation

import org.apache.flink.api.common.functions.RichMapFunction
import org.apache.flink.api.scala.{DataSet, ExecutionEnvironment}

/**
 * 实现步骤:
 * 1) 构建批处理运行环境
 * 2) 使用 env.generateSequence 创建 0-100 的并行数据
 * 3) 使用 fiter 过滤出来 大于 8 的数字
 * 4) 使用 map 操作传入 RichMapFunction , 将当前子任务的 ID 和数字构建成一个元组
 * 5) 在 RichMapFunction 中可以使用 getRuntimeContext.getIndexOfThisSubtask 获取子
 * 任务序号
 * 6) 打印测试
 */
object BatchRebalanceDemo {
  def main(args: Array[String]): Unit = {
    //1) 构建批处理运行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2) 使用 env.generateSequence 创建 0-100 的并行数据
    val source: DataSet[Long] = env.generateSequence(0,100)
    //3) 使用 fiter 过滤出来 大于 8 的数字
    val filter: DataSet[Long] = source.filter(_>8)
    //使用rebalance进行处理数据
    val rebalance: DataSet[Long] = filter.rebalance()
    //4) 使用 map 操作传入 RichMapFunction , 将当前子任务的 ID 和数字构建成一个元组
    import org.apache.flink.api.scala._
    val result: DataSet[(Int, Long)] = rebalance.map(new RichMapFunction[Long, (Int, Long)] {
      override def map(value: Long): (Int, Long) = {
        (getRuntimeContext.getIndexOfThisSubtask, value)
      }
    })
    result.print()
  }
}

4 数据输出 Data Sinks

1) 基于本地集合的 sink

package com.czxy.flink.batch.sink

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

//基于本地集合的sink
object BatchSinkCollection {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.构建数据集
    import org.apache.flink.api.scala._
    val source: DataSet[(Int, String, Double)] = env.fromElements(
      (19, "zhangsan", 178.8),
      (17, "lisi", 168.8),
      (18, "wangwu", 184.8),
      (21, "zhaoliu", 164.8)
    )
    //3.数据打印
    source.print()
    println(source.collect())
    source.printToErr()
  }
}

2) 基于文件的 sink

package com.czxy.flink.batch.sink

import org.apache.flink.api.scala.ExecutionEnvironment
import org.apache.flink.core.fs.FileSystem.WriteMode

//基于文件的 sink
object BatchSinkFile {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.构建数据集
    import org.apache.flink.api.scala._
    val source: DataSet[(Int, String, Double)] = env.fromElements(
      (19, "zhangsan", 178.8),
      (17, "lisi", 168.8),
      (18, "wangwu", 184.8),
      (21, "zhaoliu", 164.8)
    )
    //保存到本地文件
//    source.writeAsText("day02/data/output/sinkLocalFile").setParallelism(1)
    //保存到HDFS文件中
    source.writeAsText("hdfs://node01:8020/test/output/sinkHDFSFile0708",WriteMode.OVERWRITE).setParallelism(1)
    env.execute(this.getClass.getSimpleName)
  }
}
package com.czxy.flink.batch.sink

import org.apache.flink.api.scala.ExecutionEnvironment
import org.apache.flink.core.fs.FileSystem.WriteMode

//基于文件的 sink
object BatchSinkFile {
  def main(args: Array[String]): Unit = {
    //1.创建执行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    //2.构建数据集
    import org.apache.flink.api.scala._
    val source: DataSet[(Int, String, Double)] = env.fromElements(
      (19, "zhangsan", 178.8),
      (17, "lisi", 168.8),
      (18, "wangwu", 184.8),
      (21, "zhaoliu", 164.8)
    )
    //保存到本地文件
//    source.writeAsText("day02/data/output/sinkLocalFile").setParallelism(1)
    //保存到HDFS文件中
    source.writeAsText("hdfs://node01:8020/test/output/sinkHDFSFile0708",WriteMode.OVERWRITE).setParallelism(1)
    env.execute(this.getClass.getSimpleName)
  }
}

5 、Flink 的广播变量

广播就是一个公共的共享变量 ,将一个数据集广播后, 不同的 Task 都可以在节点上获取到 ,每个节点 只存一份 ,广播变量的数据大小要小于内存的大小,在这里插入代码片如果不使用广播, 每一个 Task 都会拷贝一份数据集, 造成内存资源浪费

package com.czxy.flink.batch

import java.util

import org.apache.flink.api.common.functions.RichMapFunction
import org.apache.flink.api.scala.ExecutionEnvironment
import org.apache.flink.configuration.Configuration

/**
 * 需求:
 * 创建一个 学生 数据集, 包含以下数据
 * |学生 ID | 姓名 |
 * |------|------|
 * List((1, "张三"), (2, "李四"), (3, "王五"))
 * 将该数据, 发布到广播。
 * 再创建一个 成绩 数据集,
 * |学生 ID | 学科 | 成绩 |
 * |------|------|-----|
 * List( (1, "语文", 50),(2, "数学", 70), (3, "英文", 86))
 * 请通过广播获取到学生姓名, 将数据转换为
 * List( ("张三", "语文", 50),("李四", "数学", 70), ("王五", "英文", 86))
 */
object BatchBroadcastDemo {
  def main(args: Array[String]): Unit = {
    /**
     * 实现步骤:
     * 1) 获取批处理运行环境
     * 2) 分别创建两个数据集
     * 3) 使用 RichMapFunction 对 成绩 数据集进行 map 转换
     * 4) 在数据集调用 map 方法后, 调用 withBroadcastSet 将 学生 数据集创建广播
     * 5) 实现 RichMapFunction
     *  a. 将成绩数据(学生 ID, 学科, 成绩) -> (学生姓名, 学科, 成绩)
     *  b. 重写 open 方法中, 获取广播数据
     *  c. 导入 scala.collection.JavaConverters._ 隐式转换d. 将广播数据使用 asScala 转换为 Scala 集合, 再使用 toList 转换为 scala List
     * 集合
     *  e. 在 map 方法中使用广播进行转换
     * 6) 打印测试
     */
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
    import org.apache.flink.api.scala._
    val studentDataSet: DataSet[(Int, String)] = env.fromCollection(List((1, "张三"), (2, "李四"), (3, "王五")))
    val scoreDataSet: DataSet[(Int, String, Int)] = env.fromCollection(List((1, "语文", 50), (2, "数学", 70), (3, "英文", 86)))

    val resultDataSet: DataSet[(String, String, Int)] = scoreDataSet.map(new RichMapFunction[(Int, String, Int), (String, String, Int)] {

      var stuMap: Map[Int, String] = null

      override def open(parameters: Configuration): Unit = {
        import scala.collection.JavaConversions._
        val student: util.List[(Int, String)] = getRuntimeContext.getBroadcastVariable[(Int, String)]("student")
        stuMap = student.toMap
      }

      //每一条数据都会执行一次
      override def map(value: (Int, String, Int)): (String, String, Int) = {
        val name: String = stuMap.getOrElse(value._1, "")
        (name, value._2, value._3)
      }
    }).withBroadcastSet(studentDataSet, "student")

    resultDataSet.print()

  }
}

6 、Flink 的分布式缓存

【 注意】 广播是将变量分发到各个 worker 节点的内存上, 分布式缓存是将文件缓存到各个worker 节点上;

package com.czxy.flink.batch

import java.io.File

import org.apache.flink.api.common.functions.RichMapFunction
import org.apache.flink.api.scala.ExecutionEnvironment
import org.apache.flink.configuration.Configuration

import scala.io.Source

/**
 * 需求:
 * 创建一个 成绩 数据集
 * List( (1, "语文", 50),(2, "数学", 70), (3, "英文", 86))
 * 请通过分布式缓存获取到学生姓名, 将数据转换为
 * List( ("张三", "语文", 50),("李四", "数学", 70), ("王五", "英文", 86))
 * 注: distribute_cache_student 测试文件保存了学生 ID 以及学生姓名
 */
object BatchDisCachedFile {
  def main(args: Array[String]): Unit = {
    /**
     * 实现步骤:
     * 1) 将 distribute_cache_student 文件上传到 HDFS / 目录下
     * 2) 获取批处理运行环境
     * 3) 创建成绩数据集
     * 4) 对 成绩 数据集进行 map 转换, 将( 学生 ID, 学科, 分数) 转换为( 学生姓名, 学科,
     * 分数)
     *  a. RichMapFunction 的 open 方法中, 获取分布式缓存数据
     *  b. 在 map 方法中进行转换
     * 5) 实现 open 方法
     *  a. 使用 getRuntimeContext.getDistributedCache.getFile 获取分布式缓存文件
     *  b. 使用 Scala.fromFile 读取文件, 并获取行
     *  c. 将文本转换为元组( 学生 ID, 学生姓名) , 再转换为 List
     * 6) 实现 map 方法
     *  a. 从分布式缓存中根据学生 ID 过滤出来学生b. 获取学生姓名
     *  c. 构建最终结果元组
     * 7) 打印测试
     */

    // 获取批处理运行环境
    val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment

    //注册分布式缓存文件
    env.registerCachedFile("hdfs://node01:8020/test/input/distribute_cache_student", "student")
    //创建成绩数据集
    import org.apache.flink.api.scala._
    val scoreDataSet: DataSet[(Int, String, Int)] = env.fromCollection(List((1, "语文", 50), (2, "数学", 70), (3, "英文", 86)))
    val resultDataSet: DataSet[(String, String, Int)] = scoreDataSet.map(new RichMapFunction[(Int, String, Int), (String, String, Int)] {
      var stuMap: Map[Int, String] = null

      //初始化的时候只被执行一次
      override def open(parameters: Configuration): Unit = {
        val studentFile: File = getRuntimeContext.getDistributedCache.getFile("student")
        val linesIter: Iterator[String] = Source.fromFile(studentFile).getLines()
        stuMap = linesIter.map(item => {
          val itemArr: Array[String] = item.split(",")
          (itemArr(0).toInt, itemArr(1))
        }).toMap
      }

      //每条数据都会执行一次
      override def map(value: (Int, String, Int)): (String, String, Int) = {
        val name: String = stuMap.getOrElse(value._1, "")
        (name, value._2, value._3)
      }
    })
    resultDataSet.print()
  }
}

咳咳!你懂的,下回再讲。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值