我们将一起探索Apache Flink的Python API,也就是PyFlink,并通过一个批处理和实时WordCount的案例来深入了解其在大数据处理中的应用。在开始之前,我们需要确保已经正确地安装了PyFlink,以及相关的环境变量也已经配置完毕。
环境设置
1、搭建虚拟环境
到Miniconda官网下载适用于Linux的Python 3版本安装包,例如:
# 官网
https://docs.conda.io/en/latest/miniconda.html#installing
# 按照自己的系统来下载安装即可
[hadoop@node01 opt]$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
# 运行下载的脚本进行安装,按照提示操作即可,可以将Miniconda安装到默认位置,也可以自定义安装目录。
[hadoop@node01 opt]$ bash Miniconda3-latest-Linux-x86_64.sh
# 安装完成后,重新载入PATH环境变量
[hadoop@node01 opt]$ source /etc/profile
2、Miniconda3的使用
# 查看当前的conda环境
conda info --envs
# 创建新环境
conda create -n pyflink17 python=3.10
# 激活某个环境
conda activate pyflink17
# 删除环境
conda remove -n pyflink17 --all
# 安装包
conda install numpy
# 更新包
conda update numpy
# 退出激活的虚拟环境
conda deactivate
3、安装pyflink
无论是Window、Mac、Linux都只需要在命令行中输入以下命令,就可以使用pip来安装PyFlink,目前pyflink支持Python 3.7, 3.8, 3.9 or 3.10。
# 官网
https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/dev/python/datastream_tutorial/
# 进入 pyflink17 虚拟环境,执行
python -m pip install apache-flink
Java 环境建议安装 java8或者java11,至此我们就可以开始编写Python代码了。
WordCount案例
WordCount 是一个经典的案例,它可以帮助我们理解如何使用 PyFlink 处理数据。我们的任务是统计文本中每个单词的实时出现次数。为了实现这个功能,我们需要对输入的数据进行切割、分组和计数。
1、导入必要的模块
from pyflink.common import Types
from pyflink.datastream import StreamExecutionEnvironment, RuntimeExecutionMode
2、创建 StreamExecutionEnvironment 执行环境
# 创建执行环境
env = StreamExecutionEnvironment.get_execution_environment()
# env.set_runtime_mode(RuntimeExecutionMode.BATCH)
env.set_parallelism(1)
# 定义输入数据源和输出结果
file_name = '/Users/oscar/data/word.txt'
# 读取数据:从文件中读取,一行一行的读取
data_source = env.read_text_file(file_name)
word.txt里的数据格式如下所示:
hello flink
hello spark
hello spark
hello python
hello flink
hello spark
hello flink
hello flink
3、切分
# 切分函数
def get_words(lines):
yield from lines.split(' ')
data_source.flat_map(get_words)
# 从 flat_map() 的源码知道,要传入一个func函数,所以这里就是切割函数:get_words()
def flat_map(self,
func: Union[Callable, FlatMapFunction],
output_type: TypeInformation = None) -> 'DataStream':
切分后的结果是:
['hello', 'flink']
['hello', 'spark']
['hello', 'java']
['hello', 'python']
['hello', 'golang']
['hello', 'php']
['hello', 'mysql']
['hello', 'doris']
4、转换:(word, 1)
# 使用 lambda 匿名函数方式把格式转换成 (word, 1)
.map(lambda x: (x, 1), output_type=Types.TUPLE([Types.STRING(), Types.INT()]))
# Map 源码
def map(self, func: Union[Callable, MapFunction], output_type: TypeInformation = None) \
-> 'DataStream':
转换后的结果如下所示:
(hello, 1)
(flink, 1)
4、分组
按照 key 分组,把key相同的分在同一组
# (flink, 1) 元组,x[0]取的值就是 flink
.key_by(lambda x: x[0])
分组后的结果
(flink,1)
(flink,1)
(flink,1)
(flink,1)
(hello,1)
(hello,1)
(hello,1)
(hello,1)
(hello,1)
(hello,1)
(hello,1)
(hello,1)
(spark,1)
(spark,1)
(spark,1)
(python,1)
5、分组内聚合
按照key把值累加起来就得到最后的结果
.reduce(lambda i, j: (i[0], i[1] + j[1]))
批处理案例
from pyflink.common import Types
from pyflink.datastream import StreamExecutionEnvironment
def get_flat_map(lines):
r = lines.split(' ')
yield from r
def word_count_batch_demo():
"""
DataStream 实现 WordCount 有界流(读文件)
:return:
"""
# 1、创建执行环境
env = StreamExecutionEnvironment.get_execution_environment()
env.set_parallelism(1)
# 2、从文件中读取数据
file_name = '/Users/oscar/projects/big_data/flink_tutorial/data/word.txt'
data_source = env.read_text_file(file_path=file_name)
# 3、数据处理
ds = data_source\
.flat_map(get_flat_map)\
.map(lambda x: (x, 1), output_type=Types.TUPLE([Types.STRING(), Types.INT()]))\
.key_by(lambda x: x[0]).sum(1)
# 4、输出
ds.print()
# 5、执行
env.execute()
if __name__ == '__main__':
word_count_batch_demo()
流处理案例
#!/usr/bin/python
# -*- coding:UTF-8 -*-
from pyflink.common import SimpleStringSchema, WatermarkStrategy
from pyflink.datastream import StreamExecutionEnvironment
from pyflink.datastream.connectors.kafka import KafkaSource, KafkaOffsetsInitializer
def word_count_unbounded_demo():
"""
DataStream 实现 WordCount 无界流(读kafka)
:return:
"""
# 1、创建执行环境
env = StreamExecutionEnvironment.get_execution_environment()
env.set_parallelism(1)
# 2、读取数据:kafka
brokers = "node01:9092"
source = KafkaSource.builder() \
.set_bootstrap_servers(brokers) \
.set_topics("flink_tutorial") \
.set_group_id("flink-tutorial") \
.set_starting_offsets(KafkaOffsetsInitializer.latest()) \
.set_value_only_deserializer(SimpleStringSchema()) \
.build()
ds = env.from_source(source, WatermarkStrategy.no_watermarks(), "Kafka Source")
# 3、数据处理
result = ds.flat_map(lambda x: x.split(' ')).map(lambda x: (x, 1)).key_by(lambda x: x[0]).sum(1)
# 4、输出
result.print()
# 5、执行
env.execute()
if __name__ == '__main__':
word_count_unbounded_demo()
通过今天的课程,我们学习了如何使用PyFlink的DataStream API实现实时WordCount。希望这个案例能够帮助大家更好地理解PyFlink在实时数据流处理中的应用。如果你想了解更多关于PyFlink的内容,可以继续观看后面的课程,或者参考我们在视频描述中提供的代码和学习资源链接。
详细资料关注公众号