使用Apache Kafka构建实时数据流-数据见UserBehavior.csv

Spark Streaming+kafka任务实践

任务描述

Spark Streaming + Kafka(但是Python)

1. 使用Apache Kafka构建实时数据流

参考文档链接:https://cloud.tencent.com/developer/article/1814030

2. 数据见UserBehavior.csv

数据解释:本次实战用到的数据集是CSV文件,里面是一百零四万条淘宝用户行为数据,该数据来源是阿里云天池公开数据集

在这里插入图片描述

根据这一csv文档运用Kafka模拟实时数据流,作为Spark Streaming的输入源,两条记录实际的间隔时间如果是1分钟,那么Java应用在发送消息时也可以间隔一分钟再发送。
在这里插入图片描述

要求

  1. • 找出最受欢迎的前三名商品ID
  2. • 找出订单数量最多的日期。

环境使用的配置清单(大概)

  • 操作系统:Windows 10
  • 编程语言:Python 3
  • IDE:PyCharm2021,
  • 解释器:python3(但是配置的远程虚拟机上的python),如果是本地模式可以直接用本机python
  • 基于Kafka2.12_2.4.1+Spark3.1.2+Hadoop3.1.2+zookeeper平台
  • Python包 依赖 kafka-python,pyspark,Kafka—Spark连接依赖包(放到Spark的jar包目录)

在这里插入图片描述

代码展示

数据生产者:

import csv
import json
import time
from kafka import KafkaProducer

# 配置Kafka连接信息
bootstrap_servers = 'node1:9092' #broke监听地址信息
topic = 'flink-user-behavior' #主题信息

# 创建Kafka生产者
producer = KafkaProducer(bootstrap_servers=bootstrap_servers,
                         value_serializer=lambda v: json.dumps(v).encode('utf-8'))

# 读取CSV文件并逐条上传数据到Kafka,这里我直接将csv文件放到了代码文件同一位置,你可以使用绝对路径来试试
with open('UserBehavior.csv', 'r') as file:
    reader = csv.reader(file)
    #header = next(reader)  # 文件没有表头无需跳过头行
    prev_timestamp = None  # 上一条数据的时间戳
    for row in reader:
        user_ID, product_ID, productsort_ID, behavior_data, time_data, date_string = row

        # 计算当前记录与上一条记录的时间差,以秒为单位
        current_timestamp = int(time_data)
        if prev_timestamp is not None:
            time_diff = current_timestamp - prev_timestamp

            # 如果时间差大于一分钟,则延迟一分钟上传
            if time_diff > 60:
                time.sleep(60)

        # 构建JSON对象
        data = {
            'user_ID': int(user_ID),
            'product_ID': int(product_ID),
            'productsort_ID': int(productsort_ID),
            'behavior_data': behavior_data,
            'time_data': int(time_data),
            'date_string': date_string
        }

        # 序列化为JSON并发送到Kafka
        producer.send(topic, value=data)

        # 更新上一条记录的时间戳
        prev_timestamp = current_timestamp

# 文件数据上传结束 关闭Kafka生产者
producer.close()

数据消费者代码:

from pyspark.sql import SparkSession
from pyspark.sql.functions import *
from pyspark.sql.types import *

# 创建SparkSession
spark = SparkSession.builder.appName("RealTimeAnalytics").getOrCreate()

# 配置Kafka连接信息
bootstrap_servers = 'node1:9092'
topic = 'flink-user-behavior'

# 定义Schema,根据实际数据结构进行调整
schema = StructType([
    StructField("user_ID", IntegerType()),
    StructField("product_ID", IntegerType()),
    StructField("productsort_ID", IntegerType()),
    StructField("behavior_data", StringType()),
    StructField("time_data", IntegerType()),
    StructField("date_string", StringType())
])
# 读取Kafka流数据
df1 = spark.readStream.format("kafka") \
    .option("kafka.bootstrap.servers", bootstrap_servers) \
    .option("subscribe", topic) \
    .load() \
    .selectExpr("CAST(value AS STRING)")

# 解析JSON数据
parsed_df0 = df1.select(from_json(col("value"), schema).alias("data")) \
    .select("data.*")
#parsed_df0.printSchema()#检查信息表创建是否正常
#parsed_df.printSchema()
parsed_df = parsed_df0.withColumn('date', to_date('date_string', 'yyyy/M/d H:m')).select("*")#将日期字符串修改为时间数据,不要忘记添加格式'yyyy/M/d H:m'

# # 检查数据是否整合好
total_amount_df = parsed_df.select(col("*"))
# 找出订单数量最多的日期
most_orders_date_df = parsed_df.groupBy("date") \
    .agg(count(col("product_ID")).alias("order_count")) \
    .orderBy(col("order_count").desc()) \
    .limit(1)
# 找出最受欢迎的前三名商品ID
popular_products_df = parsed_df.groupBy("product_ID") \
    .count() \
    .withColumnRenamed("count", "popularity") \
    .orderBy(col("popularity").desc()) \
    .limit(3)

# 启动流计算并输出结果
query1 = total_amount_df.writeStream \
    .outputMode("append") \
    .format("console") \
    .option("truncate", "false") \
    .start()

query2 = most_orders_date_df.writeStream \
    .outputMode("complete") \
    .format("console") \
    .option("truncate", "false") \
    .start()

query4 = popular_products_df.writeStream \
    .outputMode("complete") \
    .format("console") \
    .option("truncate", "false") \
    .start()
# 计算商品热度并输出结果

query2.awaitTermination()

运行结果图片展示

数据生产者控制台:(我用的是linux服务器集群模式搭建的平台系统,并配置了远程主机运行,所以会这样显示)生产者读取数据,根据数据时间戳的差值来延迟上传数据到kafka中

在这里插入图片描述

数据消费者控制台:第11次流处理

在这里插入图片描述

时间戳差值小于等于1分钟同时上传的记录证实
在这里插入图片描述

时间戳相差超过一分钟延时一分钟再上传数据

在这里插入图片描述

消费者实时计算数据流显示订单最多的日期和最受欢迎的前三商品id
实际运行能够做到每上传一条数据就进行实时计算,所以可以做到一分钟后上传的数据就一分钟后进行计算,立刻上传的数据,可以立刻计算。

总结

之前参考了scala项目的代码,发现还是python的简洁易用,不过不同语言各有不同的开发优势,不能片面的评价一个语言的优劣,只能说用python写不容易因为一些环境的配置而感到脑淤血,只需要添加好包环境就行。而之前弄java的项目环境配的,也不能说很难,但是很容易脑淤血。弄不好一个下午就这么耗下去了。
这次项目用到的环境搭建还是挺顺利的,必须确保本地的Hdfs+Spark能正常运行,同时python3有pip install 相应的依赖包,然后再启动zookeeper正常运行Kafka进程,配置好主题和监听地址,就可以正常运行以上代码。如果大家对我的环境搭建感兴趣,不用多说,call me!!
分享就到这里,希望各位在大数据开发之路勇往直前的伙伴们都能披荆斩棘!!

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
#定义三大组件的名称 a.sources = r a.sinks = k1 k2 k3 a.channels = c1 c2 c3 #将数据流复制给所有channel a.sources.r.selector.type = replicating  # 配置Source组件 a.sources.r.type = exec #exec表示数据源来自运行给定的Unix命令后生成的数据 a.sources.r.command = cat /home/bit/ys/hngyzd.csv # kafka a.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink a.sinks.k1.kafka.topic = data a.sinks.k1.kafka.bootstrap.servers = localhost:9092 a.sinks.k1.kafka.flumeBatchSize = 20 a.sinks.k1.kafka.producer.acks = 1 a.sinks.k1.kafka.producer.linger.ms = 1 a.sinks.k1.kafka.producer.compression.type = snappy a.channels.c1.type = memory a.channels.c1.capacity = 100000 a.channels.c1.transactionCapacity = 100 # mysql a.sinks.k2.type =com.us.flume.MysqlSink a.sinks.k2.hostname=localhost a.sinks.k2.port=3306 a.sinks.k2.databaseName=ys a.sinks.k2.tableName=table1 a.sinks.k2.user=bit a.sinks.k2.password=123456 a.channels.c2.type = memory a.channels.c2.capacity = 100000 a.channels.c2.transactionCapactiy = 2000 # hdfs a.sinks.k3.type = hdfs a.sinks.k3.hdfs.path = hdfs://localhost:9000/user/bit/ys #积攒多少个Event才flush到HDFS一次 a.sinks.k3.hdfs.batchSize = 100 #设置文件类型,可支持压缩 a.sinks.k3.hdfs.fileType = DataStream #多久生成一个新的文件 a.sinks.k3.hdfs.rollInterval = 5 a.channels.c3.type = memory a.channels.c3.capacity =100000 a.channels.c3.transactionCapacity = 100 # Bind the source and sink to the channel a.sources.r.channels = c1 c2 c3 a.sinks.k1.channel = c1 a.sinks.k2.channel = c2 a.sinks.k3.channel = c3
05-23
这段代码是一个 Apache Flume 的配置文件,用于将数据从一个源头复制到多个目的地。其中,a.sources 定义了数据源,a.sinks 定义了数据的目的地,a.channels 定义了数据在传输过程中的缓存区。具体配置如下: - 数据源:a.sources.r.type = exec 表示数据源来自运行给定的 Unix 命令后生成的数据,a.sources.r.command = cat /home/bit/ys/hngyzd.csv 表示运行 cat 命令读取指定文件中的数据作为数据源。 - Kafka 目的地:a.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink 表示将数据发送到 Kafka,a.sinks.k1.kafka.bootstrap.servers = localhost:9092 表示连接到本地的 Kafka 服务器,a.sinks.k1.channel = c1 表示从名为 c1 的缓存区取出数据发送到 Kafka。 - MySQL 目的地:a.sinks.k2.type = com.us.flume.MysqlSink 表示将数据写入 MySQL 数据库,a.sinks.k2.hostname = localhost、a.sinks.k2.port = 3306、a.sinks.k2.databaseName = ys、a.sinks.k2.tableName = table1、a.sinks.k2.user = bit、a.sinks.k2.password = 123456 分别表示连接到本地的 MySQL 数据库 ys 中的 table1 表,并使用 bit 用户名和 123456 密码进行认证。a.sinks.k2.channel = c2 表示从名为 c2 的缓存区取出数据写入 MySQL。 - HDFS 目的地:a.sinks.k3.type = hdfs 表示将数据写入 HDFS,a.sinks.k3.hdfs.path = hdfs://localhost:9000/user/bit/ys 表示将数据写入到本地的 HDFS 文件系统中的 /user/bit/ys 目录下。a.sinks.k3.hdfs.batchSize = 100 表示积攒多少个事件才将它们一起 flush 到 HDFS 中,a.sinks.k3.hdfs.rollInterval = 5 表示每隔 5 秒生成一个新的文件。a.sinks.k3.channel = c3 表示从名为 c3 的缓存区取出数据写入 HDFS。 最后,a.sources.r.channels、a.sinks.k1.channel、a.sinks.k2.channel 和 a.sinks.k3.channel 分别将数据源和目的地绑定到缓存区 c1、c2 和 c3。这样,数据在传输过程中会先进入缓存区,再从缓存区分别发送到 Kafka、MySQL 和 HDFS 中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值