DataSet API编程指南之计数器和分布式缓存(六)

DataSet API编程指南之计数器和分布式缓存(六)

1、计数器

需求:统计DataSet中元素的数量。

常规实现思路:

object CounterApp {
    
    
    def main(args: Array[String]): Unit = {
    
    
        val env: ExecutionEnvironment = ExecutionEnvironment
                .getExecutionEnvironment
        val data: DataSet[String] = env
                .fromElements("hadoop", "spark", "flink")
        data.map(new RichMapFunction[String, Long] {
    
    
			// 1、定义计数器
            var counter = 0L
            override def map(value: String): Long = {
    
    

                counter = counter + 1
                println("counter ", counter)
                counter

            }
        }).setParallelism(2).print()	// 设置并行度2
        // 每个并行度中的counter都是从1开始的
    }
}

存在的问题:counter在每个并行度数据集中都是从1开始的,从上述程序的运行结果来看,这并不能够满足我们计数的需求。

下面我们将通过使用Flink自带的计数器实现计数功能。

/** 如何使用计数器实现计数呢 */
def counterInFlink(env:ExecutionEnvironment,
                   data: DataSet[String]) = {
    
    
    data.map(new RichMapFunction[String, String] {
    
    
        // 1、定义计数器
        private val counter = new LongCounter()
        override def open(parameters: Configuration): Unit = {
    
    
            // 2、注册计数器
            getRuntimeContext.addAccumulator("ele-counter", counter)
        }

        override def map(value: String): String = {
    
    
            counter.add(1)
            value
        }
    }).setParallelism(2).writeAsText("data/output/sink/counter",
        writeMode = WriteMode.OVERWRITE)

    val result: JobExecutionResult = env.execute("CounterApp")
    // 3、获取计数器
    println(result.getAccumulatorResult("ele-counter"))
}

总结:基于Flink编程的计数器开发步骤如下,

  • 定义计数器
  • 注册计数器
  • 获取计数器

2、分布式缓存

Flink提供了分布式缓存,和hadoop比较类似,能够使得其他并行用户函数的实例像访问本地文件一样使用。这个功能可用于共享包含静态外部数据的文件,如字典或机器学习回归模型。

缓存工作机制如下,程序以特定的名称在ExecutionEnvironment中注册文件或者目录(可以时本地文件,也可以是HDFS或者S3上的文件)。当程序执行时,Flink会自动将文件或目录复制到所有Worker节点的本地文件系统中。用户函数可以查找指定名称下的文件或目录,并从Worker节点的本地文件系统中访问它。

可以通过如下方式,使用分布式缓存:

val env = ExecutionEnvironment.getExecutionEnvironment

// register a file from HDFS
env.registerCachedFile("hdfs:///path/to/your/file", "hdfsFile")

// register a local executable file (script, executable, ...)
env.registerCachedFile("file:///path/to/exec/file", "localExecFile", true)

// define your program and execute
...
val input: DataSet[String] = ...
val result: DataSet[Integer] = input.map(new MyMapper())
...
env.execute()

可以通过一个用户函数(例子中的是MapFunction)访问缓存文件。这个函数必须继承RichFunction类,这是因为它需要访问RuntimeContext。

// extend a RichFunction to have access to the RuntimeContext
class MyMapper extends RichMapFunction[String, Int] {
    
    

  override def open(config: Configuration): Unit = {
    
    

    // access cached file via RuntimeContext and DistributedCache
    val myFile: File = getRuntimeContext.getDistributedCache.getFile("hdfsFile")
    // read the file (or navigate the directory)
    ...
  }

  override def map(value: String): Int = {
    
    
    // use content of cached file
    ...
  }
}

基于上述分布式缓存介绍,下面通过注册本地文件作为分布式缓存,来详细说明分布式缓存的使用。

object DistributedCacheApp {
    
    
    def main(args: Array[String]): Unit = {
    
    
        val env: ExecutionEnvironment = ExecutionEnvironment
                .getExecutionEnvironment
        val filePath = "data/input/words.txt"
        // 1、注册一个本地文件/HDFS文件
        env.registerCachedFile(filePath, "wc")
        val data: DataSet[String] = env
                .fromElements("hadoop", "spark", "flink, zookeeper")
        data.map(new RichMapFunction[String, String] {
    
    

            override def open(parameters: Configuration): Unit = {
    
    
                // 2、获取注册文件
                val cacheFile: File = getRuntimeContext.getDistributedCache.getFile("wc")
                // 3、读取文件内容
                val lines: util.List[String] = FileUtils.readLines(cacheFile)
                // 注意:此时会出现一个异常:java集合和scala集合不兼容的问题
                import scala.collection.JavaConverters._
                for (ele <- lines.asScala)
                    println(ele)
            }

            override def map(value: String): String = value
        }).print()

    }
}

猜你喜欢

转载自blog.csdn.net/kaizuidebanli/article/details/106671650
今日推荐