李翔-大数据技术

Big data technology!

《大数据综合项目实训》练习04

《大数据综合项目实训》练习04


学生提交材料清单

1.Spark 项目运行结果截图

2.Hive数据库查询截图

3.接口测试截图

4.数据可视化网页截图

5.分别导出Spark项目,前后端项目的Zip(压缩包)

注意:

1.所有截图请统一粘贴到一个 Word 文件中,命名为:提交截图_姓名_班级.docx

2.最终考生提交内容打包为一个总压缩包,命名格式如下:张三-大数据高23-1班-大数据实训.rar


一、Hive 环境启动

【题目要求】

  • 启动 Hadoop 分布式文件系统(HDFS)与 YARN;

  • 启动 Hive Metastore 与 HiveServer2 服务。

# 启动 Hadoop 文件系统
start-dfs.sh
start-yarn.sh

# 启动 Hive 服务
hive --service metastore &
hive --service hiveserver2 &

二、Hive 数据库与数据导入

【题目要求】

  • 创建数据库 salesdb

  • 创建表 salesinfo,包含字段 sale_date;

  • 从本地路径 /opt/exam_spark/sales_data.csv 加载数据;

  • 确认数据中有多个年份存在。

DROP DATABASE IF EXISTS salesdb CASCADE;
CREATE DATABASE IF NOT EXISTS salesdb;
USE salesdb;

CREATE TABLE IF NOT EXISTS salesinfo (
   order_id STRING,
   customer_id STRING,
   product_id STRING,
   sale_date DATE,
   quantity INT,
   unit_price INT,
   payment_method STRING,
   region STRING,
   product_name STRING,
   category STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE
TBLPROPERTIES ("skip.header.line.count"="1");

LOAD DATA LOCAL INPATH '/opt/exam_spark/sales_data.csv' INTO TABLE salesinfo;

SELECT DISTINCT year(sale_date) AS sale_year FROM salesinfo;

三、Spark SQL 年度销售对比分析

【题目要求】

  • 创建 Spark 项目 SparkTask ,并导入 Pom.xml 文件;

  • 创建 Scala 类 YearSalesAnalysis,路径为: src/main/scala/org/example/YearSalesAnalysis.scala

  • 使用 Spark SQL 分析 Hive 表 salesinfo

    1. 从 Hive 表 salesinfo 中提取 sale_date 中的年份;

    2. 统计北京每年的订单总数、销售总额;

    3. 按年份升序排序;

    4. 保存结果到 Hive 表 year_sales_result

【参考代码】

package org.example

import org.apache.spark.sql.SparkSession

object YearSalesAnalysis {
 def main(args: Array[String]): Unit = {

   // 设置 Hadoop 用户(避免权限问题)
   System.setProperty("HADOOP_USER_NAME", "root")

   // 1. 初始化 SparkSession,开启 Hive 支持
   val spark = SparkSession.builder()
     .appName("YearSalesStat")
     .master("local[*]")
     .enableHiveSupport()
     .getOrCreate()

   println("1.SparkSession 初始化成功,Hive 支持开启")
   // 2. 使用 salesdb 数据库
   spark.sql("USE salesdb")

   // 3. 统计每年销售总额与订单数量
   println("2.正在统计北京地区各年份的订单数量与销售总额...")
   val result = spark.sql(
     """
       |SELECT
       |  year(sale_date) AS sale_year,
       |  COUNT(*) AS order_count,
       |  ROUND(SUM(quantity * unit_price)/10000, 2) AS total_sales
       |FROM salesinfo
       |WHERE sale_date IS NOT NULL and region='北京'
       |GROUP BY year(sale_date)
       |ORDER BY sale_year ASC
       |""".stripMargin)

   // 4. 展示结果
   val count = result.count()
   println(s"3.查询完成,共获得 $count 条年度销售记录:")
   result.show(truncate = false)

   // 5. 保存结果为 Hive 表
   println("4.正在将结果写入 Hive 表:salesdb.year_sales_result...")
   result.write
     .mode("overwrite")
     .saveAsTable("salesdb.year_sales_result")

   println("5.结果已成功写入 Hive 表:salesdb.year_sales_result")

   // 6. 关闭 Spark
   spark.stop()
   println("6.程序结束,SparkSession 已关闭。")
 }
}

四、Spring Boot 接口开发 + Vue 可视化


4.1 后端接口开发

【题目要求】

  • 创建 Spring Boot 项目 ,名称为Backend,并导入 Pom.xml 文件;

  • 创建类 YearController,路径为: src/main/java/com/example/backend/controller/YearController.java

  • 使用 Spring Boot 创建接口 /year-sales,请求方式为 GET

  • 在接口中通过 JDBC 查询 Hive 表 year_sales_result

  • 查询字段包括:sale_year, order_count, total_sales

  • 将查询结果以 JSON 列表形式返回,每条记录包含上述字段键值对。

【参考代码】

package com.example.backend.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.sql.*;
import java.util.*;

@RestController // 标注为一个 REST 控制器,返回 JSON 数据
public class YearController {

   @GetMapping("/year-sales") // 映射 GET 请求路径为 /year-sales
   public List<Map<String, Object>> getYearSales() {
       // 用于存放查询结果的列表,每个 Map 表示一条记录
       List<Map<String, Object>> result = new ArrayList<>();

       try {
           // 加载 Hive JDBC 驱动类
           Class.forName("org.apache.hive.jdbc.HiveDriver");

           // 通过 JDBC 连接到 HiveServer2(地址、库名、用户名、密码)
           Connection conn = DriverManager.getConnection(
               "jdbc:hive2://master:10000/salesdb", "root", "123456");

           // 创建 SQL 执行对象
           Statement stmt = conn.createStatement();

           // 执行 Hive 查询:按年汇总的订单数量和销售总额
           ResultSet rs = stmt.executeQuery(
               "SELECT sale_year, order_count, total_sales FROM year_sales_result");

           // 遍历结果集,每行数据封装为一个 Map,添加到结果列表
           while (rs.next()) {
               Map<String, Object> map = new HashMap<>();
               map.put("sale_year", rs.getInt("sale_year"));         // 年份(如 2021)
               map.put("order_count", rs.getInt("order_count"));     // 对应年份的订单数量
               map.put("total_sales", rs.getDouble("total_sales"));  // 对应年份的销售总额
               result.add(map); // 加入结果列表
           }

           // 关闭资源:结果集、语句、连接
           rs.close();
           stmt.close();
           conn.close();

       } catch (Exception e) {
           // 捕获并打印异常信息(如连接失败、SQL 错误)
           e.printStackTrace();
       }

       // 返回包含年份销售统计数据的列表,自动转换为 JSON
       return result;
   }
}

4.2 Vue + ECharts 可视化

【题目要求】

  • 创建 VUE 项目 ,名称为Frontend

  • 创建组件文件 components/YearChart.vue 和主页面 App.vue,配置代理文件 vite.config.js

  • 使用 Vue3 + ECharts 创建折线图组件,并启用面积图效果;

  • 从接口 /api/year-sales 获取数据;

  • 显示北京各年份的销售额变化趋势(单位:万元),并通过折线图动态展示。

【参考代码】

vite.config.js

// 引入 Vite 的配置函数和 Vue 插件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// 默认导出配置对象
export default defineConfig({
 // 注册插件:使用 Vue 插件支持 .vue 文件
 plugins: [vue()],

 // 本地开发服务器配置
 server: {
   port: 5173, // 本地开发服务器端口(默认也是 5173,可自定义)

   // 配置代理:解决前端开发中跨域请求后端的问题
   proxy: {
     '/api': {
       target: 'http://localhost:8080', // 后端服务器地址(Spring Boot 或其他服务)
       changeOrigin: true,              // 修改请求头中的 origin 字段,避免跨域
       rewrite: path => path.replace(/^\/api/, '')
       // 将请求路径中的 `/api` 前缀去掉,例如:
       // 前端请求:/api/region-sales → 实际转发为:http://localhost:8080/region-sales
     }
   }
 }
})

App.vue

<!-- 页面结构区域 -->
<template>
 <div class="chart-wrapper">
   <h1>数据可视化</h1>
   <h2>大数据高23-1班 张三</h2>
   <!-- 引入的图表组件,用于展示区域销售数据 -->
   <YearChart />
 </div>
</template>

<!-- 脚本逻辑区域 -->
<script setup>
 // 引入封装好的区域图表组件
 import YearChart from './components/YearChart.vue'
</script>

<!-- 页面样式区域 -->
<style>
/* 设置整个页面的背景色和默认字体样式 */
body {
 background-color: #f0f2f5; /* 浅灰背景色 */
 margin: 0;
 padding: 20px;
 font-family: "Microsoft YaHei", sans-serif;
}

/* 图表容器样式:限制最大宽度、居中显示 */
.chart-wrapper {
 max-width: 1400px;
 margin: 40px auto; /* 上下间距 40px,左右居中 */
 font-family: sans-serif;
}
</style>

YearChart.vue

<template>
 <!-- 图表容器,通过 ref 引用,用于挂载 ECharts -->
 <div class="chart-container" ref="chartRef"></div>
</template>

<script setup>
import { ref, onMounted } from 'vue'         // Vue 的响应式变量 + 生命周期钩子
import * as echarts from 'echarts'           // 引入 ECharts 主库
import axios from 'axios'                    // 引入 Axios 用于发送请求

// 1.定义响应式变量,用于绑定图表 DOM 节点
const chartRef = ref()

// 2.渲染图表函数:请求数据并绘制图表
const renderChart = async () => {
 // 向后端发送请求,获取每年销售数据(格式:[{sale_year:2020, total_sales:123.45}, ...])
 const res = await axios.get('/api/year-sales')
 const data = res.data

 // 拆分出图表的 X 轴(年份) 和 Y 轴(销售额)
 const xData = data.map(item => item.sale_year)                // 年份数组
 const yData = data.map(item => item.total_sales.toFixed(2))   // 销售额数组,保留两位小数

 // 初始化 ECharts 图表实例,挂载到 DOM 元素 chartRef 上
 const chart = echarts.init(chartRef.value)

 // 配置图表选项(option)
 chart.setOption({
   title: {
     text: '北京各年份销售额趋势图',     // 主标题
     subtext: '单位:万元',          // 副标题
     left: 'center'                 // 居中显示
   },
   tooltip: {
     trigger: 'axis',               // 提示框触发条件:鼠标悬浮在坐标轴上
     formatter: params => {
       const d = params[0]
       return `${d.name} 年<br/>销售额:${d.value} 万元`  // 自定义提示框内容
     }
   },
   grid: {
     top: 80,
     bottom: 60,
     left: 80,
     right: 30
   },
   xAxis: {
     type: 'category',             // 类目轴(x 轴显示文字)
     data: xData,                  // 年份数组
     boundaryGap: false,           // 图线贴边
     axisLabel: { fontSize: 14 }   // 字体大小
   },
   yAxis: {
     type: 'value',                // 数值轴
     name: '销售额(万元)',       // y 轴名称
     axisLabel: {
       formatter: '{value} 万',    // 格式化 y 轴单位
       fontSize: 14
     }
   },
   series: [
     {
       name: '销售额',
       type: 'line',               // 折线图
       data: yData,                // 销售额数据
       smooth: true,               // 平滑曲线
       areaStyle: {opacity: 0.3},              // 填充面积颜色 → 成为“面积图”,并设置透明度 30%
       symbol: 'circle',           // 折线图上的点形状
       lineStyle: {
         width: 3,
         color: '#2b6cb0'          // 折线颜色
       },
       itemStyle: {
         color: '#2b6cb0'          // 数据点颜色
       },
       label: {
         show: true,               // 显示数据值
         position: 'top'           // 值显示在点上方
       }
     }
   ]
 })
}

// 3.页面加载完成后自动执行渲染图表
onMounted(() => renderChart())
</script>

<style scoped>
.chart-container {
 width: 100%;
 height: 400px;
 min-width: 700px;
 margin: 10px auto;
 background: #fff;
 border-radius: 12px;
 padding: 20px;
 box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08); /* 阴影效果 */
}
</style>


image.png

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Powered By Z-BlogPHP 1.7.3

版权:李翔
备案/许可证编号为:新ICP备2024006115号-1