☰
Hadoop与Spark电商数据分析实战:从架构选型到答辩全流程解析
2026/10/24 3:01:43 网站建设 项目流程

这个标题我太熟了,每年毕业季都能看到一批“Hadoop + Spark + Python + 淘宝商品数据分析”的组合出现在选题清单上。乍一看像是把大数据全家桶都堆上去了,实际上这类题目的核心就一句话:基于分布式计算框架完成电商数据的采集、清洗、分析,并用可视化手段把销售规律呈现出来。

先说结论:这个题能过,而且只要不是纯糊弄,答辩时被质疑的概率很低。原因在于它的技术栈覆盖足够完整——数据采集、分布式存储、离线计算、内存计算、数据可视化五个环节全都有对应技能点,评委可以从任何一层切入提问,你只要把任意两层吃透,就能撑住场面。但这也意味着,如果你只是照着教程敲一遍命令、跑通几个 demo,答辩时大概率会翻车。这篇就按我从选题到答辩梳理的完整思路来拆解,覆盖架构选型、数据来源、核心分析指标、可视化实现,以及真正值得写进论文的进阶点。

1. 项目到底在做什么:需求拆解与技术选型

毕业设计最忌讳的是“需求不清就开始装环境”。先花两天时间把题目的隐含要求逐条拆开,你会发现自己要做的事其实非常具体。

1.1 拆分业务目标:从"分析"到"洞察"

题目里写了“商品数据分析”“销售数据分析”,这两个词在业务上是有区别的:

  • 商品数据分析:关注商品维度的静态特征与表现差异,比如不同价格区间的商品数量分布、各品类商品的销量占比、不同店铺的爆款商品特征。
  • 销售数据分析:关注时间维度与用户行为维度的动态变化,比如每天的销售额趋势、月度环比增长率、重复购买率、高价值用户画像。

两条线最终要落到一组可量化的业务问题上,我当初给自己定的分析目标是:

  1. 哪些品类的商品贡献了主要销售额(二八定律验证);
  2. 价格区间与销量之间是否存在明显规律;
  3. 商品标题长度、关键词数量是否影响曝光量;
  4. 不同地区用户的消费偏好差异(如果有地域字段);
  5. 销售额随时间变化的趋势与季节性特征。

这五个问题对应着不同的数据字段和处理方法,后续所有代码、表结构设计、可视化图表都围绕这五条线展开。这个步骤叫“需求倒推法”,先定分析目标,再定数据字段,再定技术方案。

1.2 技术选型逻辑:为什么是Hadoop + Spark + Python

题目给定的框架组合本身就是一套经典的“离线+实时”分层方案,我先说每层干什么用,再说不这么选行不行。

层级技术选型职责定位
分布式存储Hadoop HDFS存储原始日志与清洗后的宽表数据
离线批量计算MapReduce / Hive处理T+1级别的统计报表
内存迭代计算Spark SQL / PySpark复杂维度分析、多表关联、机器学习特征提取
数据采集Python + requests / Selenium获取淘宝商品页面数据
数据预处理Pandas + NumPy清洗缺失值、去重、格式转换
数据可视化ECharts / Flask / Vue搭建可视化大屏与交互图表

这套组合的好处在于每一层都有明确的存在理由。HDFS解决的是“数据量超过单机内存后怎么存”的问题,Hive/Spark解决的是“怎么在分布式环境下写SQL做统计”的问题,Python解决的是“怎么把非结构化网页数据变成结构化表格”的问题,可视化框架解决的是“分析结果怎么让非技术人员看懂”的问题。

如果不用Hadoop,单机Pandas就能处理几百万行数据,这对毕业设计来说工作量是变小了,但技术亮点也消失了。如果不用Spark,纯Hive跑复杂的滑动窗口计算和机器学习特征工程会非常痛苦。所以这个技术组合不是堆砌,而是功能互补。

1.3 系统架构设计:一张图说清数据流向

我习惯把整个系统画成“数据管道”的结构,答辩时这张图能帮你省下大量解释成本:

数据源(淘宝商品页面) → Python采集器 → 原始数据集(JSON/CSV) → HDFS存储 → Hive/Spark ETL清洗 → 数据仓库(分区表) → Spark SQL统计分析 → MySQL/ClickHouse结果表 → Flask后端API → ECharts可视化前端

这套架构里有两个关键设计:

  • 原始数据与结果数据分离:HDFS里保留一份raw_data,怎么洗都不影响原始底账;统计结果单独落到MySQL,查报表时毫秒级响应。
  • 计算层与应用层解耦:分析任务用Spark跑完出结果,可视化系统只读结果表,互相不干扰。

答辩时你可以补一句:“这套架构是从Lambda架构简化来的,去掉了实时计算层,因为淘宝商品销售数据分析对实时性要求不高,T+1频率已经满足业务需求。”这句话说出来,评委就知道你不是只会调包。

2. 数据从哪来:淘宝商品数据的获取与预处理

这个环节是很多人翻车的第一步——题目写了“淘宝商品数据”,但淘宝的反爬机制非常严格,直接抓商品详情页经常被重定向到登录页。我当初试过三种方案,优先级从高到低排序。

2.1 方案一:使用公开数据集(其实是最稳妥的路)

很多数据竞赛平台和GitHub上有现成的淘宝商品数据集,字段通常包括:商品标题、价格、销量、店铺名、所在地、商品链接、图片链接、评论数、收藏数等。

这类数据集的好处是:字段规整、量级充足、已经去掉敏感信息,完全满足分析的合法性和体量要求。缺点是:部分字段缺失、时间跨度不会太大、数据新鲜度一般。

如果要走这条路,重点是做数据说明分析——在论文里写清楚数据来源、采集时间、字段含义、样本量,不要含糊带过。这反而是加分项,说明你具备数据治理意识。

2.2 方案二:自己写爬虫(适合补充小样本数据)

如果你想让项目更完整,可以考虑“公共数据集为主+自采小样本为辅”的组合方式。自采时需要注意:

  • 用Selenium模拟浏览器滚动加载,避开接口加密的问题;
  • 控制爬取频率,设置随机延时,避免触发反爬;
  • 只采集公开可见的商品列表页信息,不做登录态采集、不碰用户隐私数据。

我当时采集了一部分搜索结果页的商品数据,解析逻辑是:

from selenium import webdriver from selenium.webdriver.common.by import By import time import random import csv def fetch_search_page(keyword, pages=5): options = webdriver.ChromeOptions() options.add_argument('--headless') driver = webdriver.Chrome(options=options) for page in range(pages): url = f"https://s.taobao.com/search?q={keyword}" driver.get(url) time.sleep(random.uniform(2, 5)) # 解析商品卡片 items = driver.find_elements(By.CSS_SELECTOR, '.Content--contentInner--QVTcDA') for item in items: title = item.find_element(By.CSS_SELECTOR, '.Title--title--jCOPWpf').text price = item.find_element(By.CSS_SELECTOR, '.Price--priceText--Z3MZPc').text sales = item.find_element(By.CSS_SELECTOR, '.SalesPoint--salesPoint--W9w_hY').text shop = item.find_element(By.CSS_SELECTOR, '.ShopLink--shopLink--HqjvXv').text writer.writerow([keyword, title, price, sales, shop]) driver.quit()

注意:这个代码要根据实际页面结构调整选择器,淘宝页面经常改版,写死选择器基本活不过一个月。所以我更建议把它当作“数据获取过程的演示样例”,而不是主要数据来源。

2.3 方案三:构造模拟业务数据(打底必备)

如果你觉得数据集字段太杂、爬虫反爬太麻烦,还有一种兜底方案——根据电商业务的真实规律模拟生成销售数据。这不是造假,而是“基于业务逻辑的数据合成”。

我当时用Python生成了一份包含40个字段、50万行记录的订单表,字段包括订单ID、用户ID、商品ID、商品类目、标题关键词、价格、成本、销量、评论数、店铺ID、店铺所在地、买家所在地、下单时间、付款时间、是否复购等。

关键是要让数据“长得像真的”:价格服从正态分布加长尾、销量与价格呈负相关、下单时间存在晚上8点到10点的高峰、地域分布参考人口比例。让导师看到你的数据不是拍脑袋编的,而是有业务规律的,这一步对后续的“业务洞察”尤其重要。

2.4 数据清洗的经验教训

无论是数据集的原始数据还是合成数据,都必须走一套标准的清洗流程:

  • 去重:同一商品ID、同一订单ID的重复记录直接删掉;
  • 缺失值处理:价格或销量缺失的,先用同店铺同品类均值填充,填充不了就删除;
  • 格式统一:时间字段统一转成datetime类型,价格统一转成float并去掉“元”字,销量统一处理掉“万”这类中文单位;
  • 异常值过滤:价格小于1元、销量为负、销量高但评论数为0这些明显不合逻辑的数据,单独存到一个异常表里,不要直接丢弃,留着写进论文里能体现你的数据质量评估能力。

数据预处理的时间往往占整个项目的一半还多,这是正常的。越早开始洗数据,后面的分析越省力。

3. 数据分析核心实现:Spark与Hive的协同工作

数据准备好之后,就进入整个项目的“计算核心”环节。这一步的任务是把清洗后的数据导入HDFS,利用Hive完成基础统计,再用Spark完成复杂的关联分析和特征计算。

3.1 数据入库:从本地CSV到Hive分区表

  • 先把清洗后的CSV文件上传到HDFS:
hdfs dfs -mkdir -p /user/hadoop/taobao/data hdfs dfs -put order_data_clean.csv /user/hadoop/taobao/data/
  • 创建Hive外部表,注意指定字段分隔符和表头跳过逻辑:
CREATE EXTERNAL TABLE if not exists taobao_orders( order_id STRING, user_id STRING, product_id STRING, category STRING, title STRING, price FLOAT, cost FLOAT, sales INT, comment_count INT, shop_id STRING, shop_location STRING, buyer_location STRING, order_time TIMESTAMP, payment_time TIMESTAMP, is_repurchase INT ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE LOCATION '/user/hadoop/taobao/data';
  • 为了避免全表扫描拖慢后续分析,建议再做一层“分区分桶”优化:
CREATE TABLE taobao_orders_partitioned ( order_id STRING, user_id STRING, ... ) PARTITIONED BY (dt STRING); INSERT INTO taobao_orders_partitioned PARTITION(dt='2025-01-01') SELECT * FROM taobao_orders WHERE date(order_time) = '2025-01-01';

这里一定要理解为什么要分区:Spark跑统计分析时,默认扫描全表数据,数据量一大就慢到怀疑人生。加了分区之后,查询只需要扫描对应分区的文件,性能能提升一个量级。论文里调优部分写这个,非常真实。

3.2 基础成交分析:Hive SQL与Spark SQL对拍

Hive适合跑T+1的基础统计,Spark SQL适合跑需要复杂逻辑的临时分析。我通常两边都跑一遍,既能验证结果一致性,又能在答辩时多说一句“用两种引擎对拍,确保计算正确性”。

基础统计第一组:成交趋势

-- Hive版本 SELECT date(order_time) as dt, count(distinct order_id) as order_cnt, sum(price * sales) as gmv, avg(price) as avg_price FROM taobao_orders_partitioned WHERE dt >= '2024-06-01' GROUP BY date(order_time) ORDER BY dt;

基础统计第二组:品类贡献度

SELECT category, count(order_id) as order_cnt, sum(sales) as total_sales, sum(price * sales) as category_gmv, round(sum(price * sales) / sum(sum(price * sales)) over (), 4) as gmv_ratio FROM taobao_orders_partitioned GROUP BY category ORDER BY category_gmv DESC;

这里用到了窗口函数 sum() over (),目的不是炫技,而是直接算出每个类目的销售额占全盘的比例。这样后面画“品类销售额占比饼图”时,就不用再导出去拿Excel二次加工了。

3.3 进阶分析:Spark的用武之地

如果说基础统计用Hive就够了,那下面这些需求就强烈建议改用Spark——因为这些统计算法逻辑复杂,需要多步骤迭代,Hive的MR模型跑起来可能会比较吃力:

复杂指标一:复购率分析(涉及多行数据)

复购率的定义是“同一用户在不同时间购买了同一类目商品的比例”。逻辑是:

from pyspark.sql import SparkSession from pyspark.sql import functions as F spark = SparkSession.builder.appName("repurchaseAnalysis").getOrCreate() df = spark.read.table("taobao_orders_partitioned") # 统计每个用户-品类维度的购买次数和首末次购买时间 repurchase_df = df.groupBy("user_id", "category").agg( F.count("order_id").alias("buy_cnt"), F.min("order_time").alias("first_buy"), F.max("order_time").alias("last_buy") ) # 判断是否复购 repurchase_df = repurchase_df.withColumn( "is_repurchase", F.when(F.col("buy_cnt") > 1 & (F.datediff(F.col("last_buy"), F.col("first_buy")) > 7), 1).otherwise(0) ) repurchase_df.groupBy("category").agg( F.sum("is_repurchase").alias("repurchase_users"), F.count("*").alias("total_users"), (F.sum("is_repurchase") / F.count("*")).alias("repurchase_rate") ).orderBy(F.col("repurchase_rate").desc()).show(20)

复杂指标二:价格敏感度分析(涉及分箱)

把价格按业务含义分成几档,然后统计每个档位对应的平均销量和转化率,能直接看出该平台用户的消费能力和价格偏好。

# 价格分箱 df_with_bucket = df.withColumn( "price_bucket", F.when(F.col("price") < 50, "0-50") .when(F.col("price") < 100, "50-100") .when(F.col("price") < 200, "100-200") .when(F.col("price") < 500, "200-500") .otherwise("500+") ) df_with_bucket.groupBy("price_bucket").agg( F.count("*").alias("order_cnt"), F.avg("sales").alias("avg_sales"), F.sum("price").alias("total_revenue") ).orderBy("price_bucket").show()

之所以用Spark而不用Hive跑这些,核心原因是Spark的DataFrame API比Hive SQL更擅长表达条件判断、时间差计算这类复合逻辑,而且跑起来快很多。一个简单的对比:我在测试环境里用Hive跑20万行的价格分箱统计,耗时50秒左右,同一个任务Spark只需要5到8秒。

3.4 数据倾斜与Spark调优

只要用Spark处理过真实数据,大概率会碰上一个叫“数据倾斜”的鬼东西。现象是某个reduce task要跑十几分钟,其他task几秒就结束了。

我当时就踩过这个坑。做地域销售分析时,买家所在地字段里“广东/浙江/江苏”的记录几乎占到总量的一半,group by时这三个key分到了同一个task,直接导致那个task内存溢出。

解决方案有两个,按实惠程度排序:

  1. 加盐随机前缀,把大key拆成多个小key,算完再合并;
  2. 用Spark的AQE自动优化,开启spark.sql.adaptive.skewJoin.enabled=true,让它自动检测倾斜key并拆分join。
spark.conf.set("spark.sql.adaptive.enabled", "true") spark.conf.set("spark.sql.adaptive.coalescePartitions.enabled", "true") spark.conf.set("spark.sql.adaptive.skewJoin.enabled", "true") spark.conf.set("spark.sql.adaptive.skewJoin.skewedPartitionFactor", "5") spark.conf.set("spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes", "256MB")

加盐的代码也顺便贴一下:

from pyspark.sql.functions import rand, lit, concat, substring # 给倾斜key加一个随机后缀把它拆散 df_salted = df.withColumn("salt", (rand() * 10).cast("int")) df_salted = df_salted.withColumn("salted_key", concat(col("buyer_location"), lit("_"), col("salt"))) # group by加盐key,最后再按原key汇总 result = df_salted.groupBy("salted_key").agg(F.sum("sales").alias("sales_partial")) result = result.withColumn("buyer_location", substring(col("salted_key"), 1, length(col("salted_key")) - 2)) result.groupBy("buyer_location").agg(F.sum("sales_partial")).show()

这类处理经验写在论文的“系统调优”章节里,含金量比抄一段Spark调优文档高得多。

4. 可视化系统:让数据自己说话

数据分析做完只是项目的一半,另一半是让导师和评委能在3分钟内看懂你的分析结论。可视化系统的设计原则只有一条:每一张图表都必须对应一个分析结论,没有结论的图表宁可不放。

4.1 技术方案选择

我推荐“Flask + ECharts”的组合,原因有三:

  • ECharts是国产可视化库,社区案例多,模板丰富,改起来快;
  • Flask写后端API非常简单,直接把Spark计算好的结果从MySQL读出来返回JSON就行;
  • Vue或React对毕设来说太重了,前端实现和数据展示本身不是重点,稳定输出结果才是。

4.2 页面布局与图表规划

我当时把可视化系统分成了四个模块:

第一模块:整体概览

  • 顶部放四个KPI卡片:总销售额、总订单量、总商品数、平均客单价
  • 核心图:销售额七日移动平均线图(用ECharts的line图)

第二模块:商品分析

  • 左侧:价格区间与销量关系的柱状图
  • 右侧:品类销售额占比的环形饼图
  • 下方:销量Top10商品横向条形图

第三模块:销售趋势分析

  • 核心图:按月、按季度、按年三种粒度的销售趋势对比
  • 辅助:热力图展示星期几×几点的销量分布

第四模块:用户与地域分析

  • 左:复购率最高的Top10品类
  • 右:地图展示各省销售额分布(用ECharts的map组件)

每个图表下方要配一句“图表结论”,比如“价格区间在100-200元的商品贡献了45%的销售额,但销量只占25%,说明该平台消费者更看重品质而非低价”。这比光秃秃的图有说服力得多。

4.3 Flask后端API实现

写一个简单的接口返回图表数据,关键是把Spark分析结果刷到MySQL里:

import pymysql import pandas as pd from flask import Flask, jsonify app = Flask(__name__) def query_db(sql): conn = pymysql.connect(host='localhost', user='root', password='123456', database='taobao_analysis') df = pd.read_sql(sql, conn) conn.close() return df @app.route('/api/sales_trend') def sales_trend(): df = query_db("SELECT dt, order_cnt, gmv FROM sales_daily ORDER BY dt") return jsonify({ "dates": df['dt'].astype(str).tolist(), "order_cnt": df['order_cnt'].tolist(), "gmv": df['gmv'].tolist() }) @app.route('/api/category_ratio') def category_ratio(): df = query_db("SELECT category, gmv_ratio FROM category_sales ORDER BY gmv_ratio DESC") return jsonify({ "categories": df['category'].tolist(), "ratios": df['gmv_ratio'].tolist() }) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)

4.4 ECharts前端实现

ECharts的使用非常模板化:先引入JS库,再准备一个固定高度的div,然后初始化图表、塞入option。

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>淘宝商品销售数据分析系统</title> <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <style> .chart { margin: 20px auto; width: 90%; height: 500px; background: #fff; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } h2 { text-align: center; margin: 30px 0 10px; font-size: 22px; } .desc { text-align: center; color: #666; } </style> </head> <body> <h2>销售趋势分析</h2> <p class="desc">按日统计的订单量与GMV走势</p> <div id="salesChart" class="chart"></div> <script> axios.get('/api/sales_trend').then(function(res) { var chart = echarts.init(document.getElementById('salesChart')); chart.setOption({ tooltip: { trigger: 'axis' }, legend: { data: ['订单量', 'GMV'] }, xAxis: { type: 'category', data: res.data.dates }, yAxis: [ { type: 'value', name: '订单量' }, { type: 'value', name: 'GMV' } ], series: [ { name: '订单量', type: 'line', data: res.data.order_cnt }, { name: 'GMV', type: 'line', yAxisIndex: 1, data: res.data.gmv } ] }); }); </script> </body> </html>

4.5 一张能打的“大屏”长什么样

答辩时最适合压轴的是一张综合大屏。我当时花了三个晚上搭出来的效果是:深色背景、顶部KPI滚动更新、中间是销售趋势主图,两侧分别是品类占比与地域热力。大屏的技术含量不高,但视觉效果影响答辩观感这是客观事实。

一个很重要的提醒:div容器高度必须显式设置,比如height: 500px,否则ECharts会一直显示“未获取到容器高度”而无法渲染。这个坑我至少见过五个同学踩过。

5. 常见问题与排查技巧实录

这部分才是真正省时间的。下面这些问题,基本都是每年做类似题目必翻车的点,提前帮你踩平了。

5.1 Spark连接Hive时的“数据库不存在”错误

最常见的报错是:

java.sql.SQLSyntaxErrorException: Unknown database 'taobao_analysis'

原因通常不是代码问题,而是Spark没有正确加载Hive的元数据。检查两点:

  • 确保hive-site.xml在Spark的classpath下:$SPARK_HOME/conf/hive-site.xml
  • 启动Spark时加上参数:--files /etc/hive/conf/hive-site.xml

5.2 HDFS NameNode启动失败或DataNode起不来

新手最常犯错的点:格式化NameNode只执行一次,千万别第二次格式化。如果执行了多次,会引发NameNode is not formatted或DataNode目录不一致的错误,此时最简单的解决方案是:

stop-all.sh rm -rf /tmp/hadoop-* hdfs namenode -format start-all.sh

属于暴力重建,但有效。注意提前备份重要数据,别把洗好的数据丢掉。

5.3 Python中文乱码

Selenium爬下来的数据写进CSV后,用Excel打开全是乱码?

  • 写入时指定编码为utf-8-sig:
with open('taobao_data.csv', 'w', newline='', encoding='utf-8-sig') as f:
  • 不是encoding='utf-8',必须带-sig,因为Windows记事本和Excel默认用带BOM的UTF-8识别文件。

5.4 数据清洗时把时间字段搞崩

淘宝页面里的时间格式一般是“2024-06-01 10:30:00”,但如果你从数据集拿到的是“2024/06/01”这种格式,直接用pd.to_datetime()会报错或者全变NaT。

解决办法是统一格式:

df['order_time'] = pd.to_datetime(df['order_time'], format='%Y/%m/%d')

如果拿到的是时间戳,加参数unit='s'或unit='ms'。

5.5 Spark任务OOM(内存溢出)

如果你是跑在本地模式或者单机伪分布式,spark.driver.memory和spark.executor.memory需要手动限制:

spark-submit --master local[4] \ --driver-memory 2g \ --executor-memory 2g \ analysis.py

如果数据量实在太大,优先过滤早期数据,只保留最近3个月的数据用于分析。这个操作不会影响毕业设计的完整性,反而能体现你的成本意识。

5.6 可视化图表不显示数据/一片空白

90%的概率是“后端接口没启动”或者“跨域问题”。先访问http://localhost:5000/api/sales_trend确认返回了JSON数据,再检查前端控制台有没有报错。不要把时间浪费在调ECharts参数上。

5.7 论文查重时技术方案描述雷同

这是最容易被忽略但最致命的问题。很多人的论文里技术方案都是从博客里抄的,查重率直接飙升。

我的建议:

  • 把技术选型的理由换成自己的话,比如“为什么用Spark不用Flink”这个问题不要只写“因为Spark快”,要写成“因为本项目以离线分析为主,数据实时性要求不高,Flink的流处理优势在本场景中无法发挥,而Spark在批处理生态和SQL兼容性上更成熟”。
  • 每一段代码都要能讲清楚:输入是什么、输出是什么、为什么这么写。

这样的论文,查重这关一般比较好过,答辩时被追问也能对答如流。

6. 还能再加什么:几个让答辩稳过的进阶点

如果你还想在基础功能之上加一点亮点,让评委觉得“这个学生是真做过的”,可以选择下面任意两个方向:

方向一:用Spark MLlib做商品销量预测

在Spark里用线性回归或者随机森林,基于历史销量、价格、评论数、收藏数等字段预测未来7天的销量。这个工作量不大,但能让项目从“纯统计”升级到“统计+机器学习”,含金量立刻不同。

from pyspark.ml.feature import VectorAssembler from pyspark.ml.regression import RandomForestRegressor from pyspark.ml.evaluation import RegressionEvaluator feature_cols = ['price', 'comment_count', 'collect_count', 'avg_sales_7d', 'title_length'] assembler = VectorAssembler(inputCols=feature_cols, outputCol="features") data = assembler.transform(df) train, test = data.randomSplit([0.8, 0.2], seed=42) rf = RandomForestRegressor(featuresCol="features", labelCol="future_sales") model = rf.fit(train) predictions = model.transform(test) evaluator = RegressionEvaluator(labelCol="future_sales", metricName="rmse") rmse = evaluator.evaluate(predictions) print("RMSE:", rmse)

方向二:基于用户行为的协同过滤推荐

如果你有用户浏览、收藏、购买三个层次的行为数据,可以做一个简单的ItemCF推荐引擎,输出“看了又看”“买了又买”的Top5商品。实现不复杂,但写进引言里就是“从数据分析延伸到智能推荐”的完整故事线。

方向三:用ClickHouse替代MySQL做结果存储

如果你的数据量超过千万级别,MySQL的group by响应时间会明显变慢,可以把Spark跑完的结果表导入ClickHouse,前端API查询速度能控制在100ms以内。这个优化写进“性能测试”章节,非常有效。

我个人在带类似项目时的体会是:毕业设计评审最看重的不是技术栈多新,而是你是否展示出了“完整的数据思维链路”——从业务问题出发,到数据采集、清洗、分析、可视化解释,每一步都有目的、有产出、有验证。这个思维链路比任何单个组件的熟练程度都值钱。

最后再分享一个小细节:所有代码、SQL、配置文件不要只放在一个文件夹里,从一开始就按collect / etl / analysis / visual / docs分目录管理,最后打包提交时你会感谢当时的自己。这个习惯不仅对毕设有用,后续进入工作岗位也一样受益。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询