基于Hive的大数据分析系统

1.概述

在构建大数据分析系统的过程中,我们面对着海量、多源的数据挑战,如何有效地解决这些零散数据的分析问题一直是大数据领域研究的核心关注点。大数据分析处理平台作为应对这一挑战的利器,致力于整合当前主流的各种大数据处理分析框架和工具,以实现对数据的全面挖掘和深入分析。本篇博客笔者将为大家介绍如何构建一个大数据分析平台,来实现对复杂数据环境中的有价值信息的精准提取和深度分析。

2.内容

构建一个完善的大数据分析平台涉及众多组件,这些组件往往具有不同的侧重点和功能特性。从数据的采集、存储,到处理和分析的各个环节,每个组件都扮演着关键的角色。如何在这种复杂的组件体系中实现协同,将它们有机地结合起来,成为了一项非常复杂而关键的工作。
这个过程需要考虑到数据的规模、种类以及处理的实时性等方面的要求。同时,为了达到挖掘海量数据的目标,还需要考虑分布式计算、存储优化、以及高效的算法设计等方面的技术挑战。只有通过精心设计和整合这些组件,才能够完成对海量数据的深度挖掘,从而获得对业务和决策有价值的信息。

2.1 了解大数据分析系统

在构建大数据分析平台之前,我们必须首先站在业务需求的前沿,深刻理解用户的期望与场景。大数据分析平台不仅仅是一个技术堆栈的堆砌,更是一个服务业务的智能引擎。明确业务需求场景和用户期望,了解在这个数据的海洋中,我们追求哪些有价值的信息,是构建大数据分析系统的关键起点。

2.1.1 了解大数据分析系统的价值

建设一个完善的大数据分析系统,不仅为企业构建了基础数据中心,还为企业提供了一个统一的数据存储体系,通过数据建模奠定了数据的价值呈现的坚实基础。

1.构建基础数据中心

大数据分析系统的第一项价值体现在建设企业的基础数据中心上。通过统一的数据存储体系,企业能够有效地管理、存储和检索海量的数据,包括来自不同业务部门和多源的数据。这种集中化的数据管理不仅提高了数据的可靠性和一致性,还降低了数据管理的复杂性和成本。

2.统一数据建模

通过对数据的统一建模,大数据分析系统为企业提供了一种标准化的数据表示方式,使得不同部门和业务能够使用相同的数据模型进行工作。这种一致的数据模型有助于消除数据孤岛,促进跨部门和跨系统的数据共享和协同工作,从而提高了企业整体的工作效率和决策水平。

3.数据处理能力下沉

大数据分析系统将数据处理能力下沉,建设了集中的数据处理中心,为企业提供了强大的数据处理能力。这意味着企业能够更加高效地进行数据的清洗、转换和分析,从而更好地挖掘数据潜在的价值。同时,这种集中化的处理模式有助于提高处理效率和降低处理成本。

4.统一数据管理监控体系

为了保障大数据分析系统的稳定运行,建设了统一的数据管理监控体系。这包括对数据质量、安全性和可用性的全面监控,以及对系统性能和故障的实时监测。通过这种全面的监控体系,企业能够及时发现和解决潜在的问题,确保系统的稳定和可靠运行。

5.构建统一的应用中心

最终,大数据分析系统通过构建统一的应用中心,满足企业业务需求,真正体现了数据的价值。通过应用中心,企业能够基于大数据分析系统提供的数据和分析结果,开发各种智能应用,为业务提供更有力的支持。这使得数据不再是一种被动的资源,而是能够主动为业务创造价值的动力源。
综合而言,大数据分析系统的价值不仅仅在于处理和分析海量的数据,更在于为企业建设了一个统一、高效的数据基础设施,为业务创新提供了强大的支持。

2.1.2 了解大数据分析系统的目的

在当今数字化浪潮中,大数据不再只是庞大的信息堆积,而是成为驱动企业智能决策和业务创新的核心资源。了解大数据分析系统的目的,远不仅仅是追逐技术的潮流,更是深刻洞察数据对业务行动的引导作用。

1. 数据度量:洞察业务趋势

大数据分析系统的首要目的之一是帮助企业洞察业务趋势。通过分析海量数据,系统能够识别并理解市场的动向、消费者的行为以及竞争对手的策略。这种深度洞察有助于企业预测未来趋势,制定战略计划,并做出敏锐的业务决策。

2. 数据理解:改进决策制定过程

大数据分析系统的另一个关键目标是改进决策制定过程。通过提供实时、准确的数据分析,系统可以帮助管理层更好地理解当前业务状况,减少决策的盲目性。这种数据驱动的决策制定能够降低风险,提高成功的概率,并在竞争激烈的市场中保持灵活性。

3.数据驱动:优化运营效率

大数据分析系统的目的还在于优化企业的运营效率。通过对业务流程的深入分析,系统可以识别出潜在的优化点,提高生产效率,减少资源浪费。这种优化不仅带来成本的降低,还可以加速业务运营,提高客户满意度。

4.数据预测:实现个性化营销

大数据分析系统有助于企业实现更个性化的营销策略。通过深入了解客户行为和偏好,系统能够生成精准的用户画像,为企业提供更具针对性的市场营销方案。这种个性化营销不仅提高了市场推广的效果,还加强了客户关系,提升了品牌忠诚度。

5.数据安全:增强安全性和合规性

大数据分析系统的另一个重要目标是增强企业的安全性和合规性。通过对数据进行监控和分析,系统能够及时发现异常活动和潜在的安全威胁。同时,它也有助于确保企业遵循法规和行业标准,降低法律风险。

2.1.3 了解大数据分析系统的应用场景

在信息时代的今天,大数据正成为推动科技和商业发展的关键力量。随着技术的不断进步,大数据分析系统的应用场景也越来越广泛。这些系统不仅仅是企业决策的得力助手,还在医疗、城市规划、金融等多个领域展现出强大的应用潜力。

1.企业决策优化

大数据分析系统在企业营销与销售中的应用早已不再是新鲜事物。通过分析大规模的市场数据,企业可以更好地了解消费者行为、趋势和喜好。基于这些分析结果,企业可以优化广告策略、制定个性化的市场推广计划,并更精准地锁定潜在客户。同时,在销售过程中,大数据分析系统也能够帮助企业实时监控库存、调整价格策略,提高销售效益。

2.金融风控与反欺诈

在金融领域,大数据分析系统为风险管理和反欺诈提供了有力的支持。通过分析用户的交易历史、行为模式和其他多维数据,金融机构可以更准确地评估信用风险,及时发现异常交易行为,从而提高风险控制的水平。大数据分析系统还能够构建复杂的欺诈检测模型,识别潜在的欺诈活动,保护用户的资产安全。

3.医疗健康管理

在医疗领域,大数据分析系统为健康管理和医疗决策提供了前所未有的支持。通过分析患者的病历数据、医疗记录和生命体征等信息,医疗机构可以更好地了解患者的健康状况,预测慢性病的风险,制定个性化的治疗方案。大数据分析系统还能够协助医学研究,加速新药研发和临床试验的进程。

4.智慧城市建设

在城市管理中,大数据分析系统为智慧城市的建设提供了有力的支持。通过收集和分析城市各个方面的数据,包括交通流量、环境污染、能源消耗等,城市管理者可以更好地规划城市发展、优化交通流动,提高城市的整体运行效率。

5.制造业智能生产

在制造业中,大数据分析系统为智能生产提供了关键支持。通过监控生产线上的大量传感器数据,企业可以实时了解生产状态、预测设备故障,从而进行及时维护,提高生产效率。大数据分析系统还能够优化供应链管理,降低库存成本,提高生产计划的精准度。
总的来说,大数据分析系统的应用场景越来越广泛,其在不同领域的作用不可忽视。通过深度挖掘和分析数据,我们能够更全面、更准确地理解复杂的系统和现象,从而为决策、创新和发展提供有力支持。

2.2 从架构上了解大数据分析系统

大数据分析系统扮演着集成、整理和分析庞大数据集的角色,它不仅仅是一个简单的数据仓库,更是一个复杂的系统,涵盖了系统数据、业务数据等多个维度的信息。
大数据分析系统的核心任务是在统一的数据框架下实现对数据的挖掘和分析。这意味着涉及到众多组件和复杂的功能,因此在系统的建设过程中,如何巧妙地将这些组件有机地结合起来成为至关重要的环节。本小节将探讨大数据分析系统的组成结构,分析各个组件之间的协同作用,以及在这个多层次、多功能的系统中如何实现高效的数据处理和可视化展示。

2.2.1 了解大数据分析系统的体系架构

随着数据规模的急剧膨胀和多样性的增加,构建一个高效、可扩展的大数据分析系统变得至关重要。为了深入理解这一庞杂系统的运作,本节将引领读者一同探索其体系架构,从数据采集到最终的洞察展示,揭示大数据分析系统如何在庞大而多元的数据海洋中发现有价值的信息。如图所示。

 

1. 数据采集层:连接多样化的数据源

数据采集层是大数据分析平台的基础,它直接涉及到数据的获取和整合。底层是各类数据源,包括各种业务数据、用户数据、日志数据等。为了确保全面性,常常采用传统的ETL离线采集和实时采集两种方式。这一层的目标是将零散的数据从各个角落整合起来,形成一个全面而连贯的数据集。

2. 数据储存和处理层:为数据提供强有力的支持

有了底层数据后,下一步是将数据储存到合适的持久化储存层中(比如Hive数据仓库),并根据不同的需求和场景进行数据预处理。这包括OLAP、机器学习等多种形式。在这一层次,数据得到了进一步的加工,确保了数据的质量、可用性和安全性,为后续的深层次分析提供了坚实的基础。

3. 数据分析层:挖掘数据的深层次价值

在数据分析层,报表系统和BI分析系统扮演着关键角色。数据在这个阶段经过简单加工后,进行深层次的分析和挖掘。这一层的任务是从庞大的数据中提取有价值的信息,为企业决策提供有力支持。在这个阶段,数据变得更加智能化和易于理解。

4. 数据应用层:将数据转化为业务洞察

最终,根据业务需求,数据被分为不同的类别应用。这包括了数据报表、仪表板、数字大屏、及时查询等形式。数据应用层是整个数据分析过程的输出,也是对外展示数据价值的关键。通过可视化手段,将分析结果生动地呈现给最终用户,助力业务决策。
深入了解系统的体系架构不仅仅是技术的问题,更需要对业务需求和用户期望的深刻理解。只有通过合理设计的体系架构,从数据的采集到最终的应用,才能实现对数据的全面挖掘和深度分析。

2.2.2 设计大数据分析系统的核心模块

设计大数据分析系统的核心模块涵盖了数据采集、数据存储、数据分析以及数据服务等,这些关键模块协同工作,构建了一个完整而高效的大数据分析系统。如图所示。

1.数据采集

作为系统的第一步,数据采集模块承担了从各业务自系统中汇集信息数据的任务。系统选择支撑Kafka、Flume及传统的ETL采集工具,以确保对多样化数据源的高效处理和集成。

2.数据存储

数据存储模块采用了一体化的存储方案,结合了Hive、HBase、Redis及MySQL,形成了支持海量数据的分布式存储体系。这种综合性的存储模式保证了对大规模数据的高效管理和检索。

3.数据分析

数据分析模块是系统的核心引擎,支持传统的OLAP分析和基于Spark的常规机器学习算法。这使得系统能够对庞大的数据集进行深入挖掘,发现潜在的价值和趋势,为决策提供强有力的支持。

4.数据服务

数据服务模块是系统的枢纽,提供对数据资源的统一管理和调度。通过数据服务,系统实现了对数据的整体治理,使得数据的流动、存储和分析能够有序而高效地进行。同时,它向外提供数据服务,为其他系统和应用提供了规范的接口和访问方式。
这些核心模块的协同作用,使得大数据分析系统能够从数据的采集到存储、再到分析,最终向外提供服务,形成了一个有机而完善的体系结构。通过整合各个模块的功能,系统能够应对多变的数据环境,为用户提供高效、可靠、灵活的大数据分析解决方案。

2.3 实现大数据分析系统

大数据分析系统的实现流程主要涵盖以下关键步骤,包括数据采集、数据整合、数据加工以及数据可视化等环节。这一系列步骤构成了通常所称的一站式大数据分析平台。
在这个平台上,数据采集负责从多源获取原始数据,而后的数据整合将这些数据汇聚并确保格式一致性。接下来,数据加工阶段进行数据清理、转换和处理,以使数据达到可分析的标准。
最终,通过数据可视化,用户能够以直观的方式理解和探索数据,为决策提供有力支持。这个标准流程为设计和实施大数据分析系统提供了基本框架,使其能够高效处理庞大的数据集,满足多样化的分析需求。

2.3.1 数据采集

数据采集是大数据分析系统中至关重要的第一步,它扮演着系统获取信息源头的关键角色。在这个阶段,系统通过各种渠道和技术,广泛而高效地搜集原始数据,为后续的分析和处理奠定基础。数据采集的过程涵盖了从传感器、日志、外部数据库到在线平台等多样化的数据来源,确保系统能够获得全面而多维度的信息。
在本小节中,我们为了模拟数据采集场景,特别设计了一个应用程序,其主要功能是生成模拟数据作为原始数据,并将这些数据发送到Kafka消息中间件。
下面是一个使用Java编写的简单应用程序,用于生成模拟电影数据并发送到Kafka。在这个示例中,我们使用了Apache Kafka的Java客户端库。具体依赖见代码所示。

<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka_2.13</artifactId>
    <version>3.4.0</version>
</dependency>

实现将模拟数据发送到Kafka的详细步骤在代码中展示。以下是一些关键实现细节:

  • Kafka配置:在代码中,你需要配置Kafka的服务器地址(bootstrap.servers)、key和value的序列化器等参数,以便建立与Kafka集群的连接。
  • 创建KafkaProducer:使用配置信息创建KafkaProducer对象,该对象负责将数据发送到Kafka集群。
  • 生成模拟数据:在一个循环中,使用你的数据生成逻辑生成模拟数据。这可能包括创建JSON格式的数据、设置数据字段、模拟日期等。
  • 构建ProducerRecord:使用生成的模拟数据构建ProducerRecord对象,其中包括目标主题、key(如果有的话)、以及待发送的数据。
  • 发送数据: 使用KafkaProducer的send方法将ProducerRecord发送到Kafka主题。
  • 控制发送速率(可选):在循环中,你可以通过Thread.sleep等方法控制数据生成和发送的速率,以避免发送过于频繁。

具体实现见代码所示。

@Slf4j
public class MovieDataProducer {
    public static void main(String[] args) {
        sendRawData();
    }

    private static void sendRawData() {
        // Kafka 服务器地址
        String kafkaBootstrapServers = "localhost:9092";

        // Kafka 主题
        String kafkaTopic = "ods_movie_data";

        // 创建 Kafka 生产者配置
        Properties properties = new Properties();
        properties.put("bootstrap.servers", kafkaBootstrapServers);
        properties.put("key.serializer", 
        "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("value.serializer", 
        "org.apache.kafka.common.serialization.StringSerializer");

        // 创建 Kafka 生产者
        try {
            Producer<String, String> producer 
            = new KafkaProducer<>(properties)
            // 生成并发送模拟电影数据
            for (int i = 1; i <= 1000; i++) {
                String movieData = generateMovieData(i);
                producer.send(new ProducerRecord<>(kafkaTopic, 
                Integer.toString(i), movieData));

                // 打印发送的数据信息(可选)
                System.out.println("发送数据到 Kafka: " + movieData);

                // 控制数据生成的速率,例如每秒发送一次
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            log.error("发送数据到 Kafka 出现异常:{}", e);
        }
    }

    // 生成模拟电影数据
    private static String generateMovieData(int rank) {
        String[] countries = {"美国", "中国", "印度", "英国", "日本"};
        String[] genres = {"动作", "剧情", "喜剧", "科幻", "冒险"};

        LocalDate releaseDate = LocalDate.now()
        .minusDays(new Random().nextInt(180));
        DateTimeFormatter formatter = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd");

        MovieData movieData = new MovieData(
                rank,
                "Movie" + rank,
                releaseDate.format(formatter),
                countries[new Random().nextInt(countries.length)],
                genres[new Random().nextInt(genres.length)],
                5 + 5 * Math.random(),
                new Random().nextInt(1000000)
        );

        // 返回字符串结果
        String result = "";

        // 使用 Jackson 库将对象转为 JSON 字符串
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            result = objectMapper.writeValueAsString(movieData);
        } catch (Exception e) {
            log.error("转换 JSON 字符串出现异常:{}", e);
        }
        return result;

    }

    // 电影数据类
    @Data
    private static class MovieData {
        private int rank;
        private String name;
        private String releaseDate;
        private String country;
        private String genre;
        private double rating;
        private int playCount;

        public MovieData(int rank, String name, String releaseDate
        , String country, String genre
        , double rating, int playCount) {
            this.rank = rank;
            this.name = name;
            this.releaseDate = releaseDate;
            this.country = country;
            this.genre = genre;
            this.rating = rating;
            this.playCount = playCount;
        }
    }
}

请确保替换localhost:9092和ods_movie_data为你实际使用的Kafka服务器地址和主题名称。这个简单的Java应用程序会生成包含电影排名、电影名称、上映日期、制作国家、类型、评分、播放次数等字段的模拟电影数据,并将其发送到指定的Kafka主题。

2.3.2 数据存储

数据存储在大数据分析系统中扮演着关键的角色,它不仅需要提供高度可靠性的存储机制,还需要根据业务需求进行智能分区,以便后续的离线分析和查询。在当前场景中,我们面对的是一批不断涌入的实时流数据,这些数据经过实时处理后需要被有效地存储到Hive中,以满足后续的离线分析需求。
为了保证数据的时效性,我们计划将每隔5分钟的数据作为一个时间窗口进行存储,这不仅有助于提高查询效率,还能够更好地支持基于时间的分析。为了实现这一目标,我们将使用Apache Flink作为我们的流处理引擎,通过其与Kafka的集成,实时地消费并处理Kafka Topic中的数据。具体实现流程如图所示。

1.环境依赖

Flink在消费Kafka集群中的数据时,需要引入一系列依赖项以确保系统的顺利运行。
为了实现对Kafka集群中数据的高效消费,我们需要引入Flink相关的依赖项。这些依赖项不仅包括Flink核心库,还涉及到与Kafka连接和交互的库。具体依赖见代码所示。

<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-connector-filesystem_2.12</artifactId>
    <version>${flink.connector.version}</version>
 </dependency>
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-connector-kafka-0.11_2.12</artifactId>
    <version>${flink.kafka.version}</version>
 </dependency>
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-streaming-java_2.12</artifactId>
    <version>${flink.streaming.version}</version>
 </dependency>

2.读取数据

编写Flink代码来消费Kafka Topic并将数据直接存储到HDFS,无需进行额外的逻辑处理,以备后续使用MapReduce进行数据预处理。具体实现见代码所示。

@Slf4j
public class FlinkTemplateTask {

    public static void main(String[] args) {
        // 检查输入参数是否满足要求
        if (args.length != 3) {
            log.error("kafka(server01:9092), 
            hdfs(hdfs://cluster01/data/), 
            flink(parallelism=2) must be exist.");
            return;
        }
        String bootStrapServer = args[0];
        String hdfsPath = args[1];
        int parallelism = Integer.parseInt(args[2]);

        // 创建 Flink 流处理环境
        StreamExecutionEnvironment env = 
        StreamExecutionEnvironment.getExecutionEnvironment();
        env.enableCheckpointing(5000);
        env.setParallelism(parallelism);
        env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);

        // 从 Kafka 中读取数据
        DataStream<String> transction = 
        env.addSource(new FlinkKafkaConsumer010<>("ods_movie_data"
        , new SimpleStringSchema(), configByKafkaServer(bootStrapServer)));

        // 存储到 HDFS
        BucketingSink<String> sink = new BucketingSink<>(hdfsPath);

        // 自定义存储到HDFS上的文件名,用小时和分钟来命名,方便后面计算策略
        sink.setBucketer(new JDateTimeBucketer<String>("HH-mm"));

        sink.setBatchSize(1024 * 1024 * 4); // 大小为 5MB
        sink.setBatchRolloverInterval(1000 * 30); // 时间 30s
        transction.addSink(sink);
        
        // 执行 Flink 任务
        env.execute("Kafka2Hdfs");
    }

    // 设置Kafka消费者的配置
    private static Object configByKafkaServer(String bootStrapServer) {
        Properties props = new Properties();
        props.setProperty("bootstrap.servers", bootStrapServer);
        props.setProperty("group.id", "test_bll_group");
        props.put("enable.auto.commit", "true");
        props.put("auto.commit.interval.ms", "1000");
        props.put("key.deserializer", 
        "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", 
        "org.apache.kafka.common.serialization.StringDeserializer");
        return props;
    }

}

在这里需要特别注意,我们将时间窗口设置得较短,每隔30秒进行一次检查。如果在该批次的时间窗口内没有数据到达,我们将生成一个文件并保存到HDFS上。
此外,我们对DateTimeBucketer进行了重写,创建了JDateTimeBucketer。这一调整的逻辑并不复杂,只是在原有的方法基础上增加了一个年-月-日/时-分的文件生成路径。举例来说,在HDFS上生成的路径可能是:xxxx/2023-10-10/00-00。这个调整有助于更好地组织和管理生成的文件,使其更符合时间和日期的结构。

3.文件命名策略

在这个步骤中,我们需要对已经存储到HDFS上的文件进行预处理。处理逻辑如下:例如,当前时间是2023-10-10 14:00,我们需要将当天的13:55、13:56、13:57、13:58、13:59这最近5分钟的数据处理到一起,并加载到Hive的最近5分钟的一个分区中。为了实现这一目标,我们需要生成一个逻辑策略集合,其中以HH-mm作为key,与之最近的5个文件作为value。这个集合将被用于数据预处理和合并。具体实现见代码所示。

public class DateRangeStrategy {
    public static void main(String[] args) {
        getFileNameStrategy();
    }

    // 生成策略
    private static void getFileNameStrategy() {
        for (int i = 0; i < 24; i++) {
            for (int j = 0; j < 60; j++) {
                if (j % 5 == 0) {
                    if (j < 10) {
                        if (i < 10) {
                            if (i == 0 && j == 0) {
                                System.out.println
                                ("0" + i + "-0" + j 
                                + "=>23-59,23-58,23-57,23-56,23-55");
                            } else {
                                if (j == 0) {
                                    String tmp = "";
                                    for (int k = 1; k <= 5; k++) {
                                        tmp += "0" + (i - 1) + "-" 
                                        + (60 - k) + ",";
                                    }
                                    System.out.println
                                    ("0" + i + "-0" + j 
                                    + "=>" + tmp.substring(0, 
                                    tmp.length() - 1));
                                } else {
                                    String tmp = "";
                                    for (int k = 1; k <= 5; k++) {
                                        if (j - k < 10) {
                                            tmp += "0" + i + "-0" 
                                            + (j - k) + ",";
                                        } else {
                                            tmp += "0" + i + "-" 
                                            + (j - k) + ",";
                                        }
                                    }
                                    System.out.println("0" + i + "-0" + j 
                                    + "=>" + tmp.substring(0, tmp.length() - 1));
                                }
                            }
                        } else {
                            if (j == 0) {
                                String tmp = "";
                                for (int k = 1; k <= 5; k++) {
                                    if (i - 1 < 10) {
                                        tmp += "0" + (i - 1) + "-" + (60 - k) + ",";
                                    } else {
                                        tmp += (i - 1) + "-" + (60 - k) + ",";
                                    }
                                }
                                System.out.println(i + "-0" + j + "=>" 
                                + tmp.substring(0, tmp.length() - 1));
                            } else {
                                String tmp = "";
                                for (int k = 1; k <= 5; k++) {
                                    if (j - k < 10) {
                                        tmp += i + "-0" + (j - k) + ",";
                                    } else {
                                        tmp += i + "-" + (j - k) + ",";
                                    }
                                }
                                System.out.println(i + "-0" + j 
                                + "=>" + tmp.substring(0, tmp.length() - 1));
                            }
                        }
                    } else {
                        if (i < 10) {
                            String tmp = "";
                            for (int k = 1; k <= 5; k++) {
                                if (j - k < 10) {
                                    tmp += "0" + i + "-0" 
                                    + (j - k) + ",";
                                } else {
                                    tmp += "0" + i + "-" 
                                    + (j - k) + ",";
                                }
                            }
                            System.out.println("0" + i + "-" 
                            + j + "=>" + tmp.substring(0, tmp.length() - 1));
                        } else {
                            String tmp = "";
                            for (int k = 1; k <= 5; k++) {
                                if (j - 1 < 10) {
                                    tmp += i + "-0" + (j - k) + ",";
                                } else {
                                    tmp += i + "-" + (j - k) + ",";
                                }
                            }
                            System.out.println(i + "-" + j 
                            + "=>" + tmp.substring(0, tmp.length() - 1));
                        }
                    }
                }
            }
        }
    }
}

4.数据加载

当数据准备完毕后,我们可以借助Hive的LOAD命令直接将HDFS上预处理的文件加载到相应的表中。具体实现见代码所示。

LOAD DATA INPATH '/data/hive/hfile/data/min/2023-10-10/14-05/' 
OVERWRITE INTO TABLE 
game_user_db.ods_movie_data PARTITION(day='2023-10-10',hour='14',min='05');

在执行命令时,如果文件不存在可能导致加载出错。因此,在加载 HDFS 路径之前,我们可以先判断一下路径是否存在。具体实现见代码所示。

#!/bin/bash

# HDFS 数据路径
hdfs_path='/data/hive/hfile/data/min/2023-10-10/14-05/'

# 检查 HDFS 路径是否存在
if hdfs dfs -test -e "$hdfs_path"; then
    # 如果存在,则执行加载操作
    echo "执行 Hive 数据加载操作"
    hive -e "LOAD DATA INPATH 
        '$hdfs_path' 
        OVERWRITE INTO TABLE 
        game_user_db.ods_movie_data 
        PARTITION(day='2023-10-10',hour='14',min='05');"
else
    echo "HDFS路径: ['$hdfs_path'] 不存在"
fi

这里需要注意的是,这个脚本先检查 HDFS 路径是否存在,如果存在则执行加载操作,否则输出错误信息。这样可以避免因文件不存在而导致的加载错误。

2.3.3 数据分析

数据分析是一门科学,通过对数据的整理、清洗和分析,我们能够从中挖掘出隐藏在庞大数据背后的规律和趋势。数据分析工具的不断发展使得这一过程变得更加高效。统计学、机器学习、人工智能等技术的应用,使得我们能够更深入地理解数据中的信息。通过数据可视化技术,我们能够将抽象的数据变成直观的图表和图像,更容易理解和传达数据所蕴含的含义。

1.分析电影年份柱状图

为了生成电影年份的柱状图,我们可以通过对电影年份数据进行聚合。具体实现见代码所示。

-- 电影年份
SELECT release_date, COUNT(1) AS pv
FROM ods_movie_data
WHERE day = '2023-10-10'
GROUP BY release_date;

执行上述代码,分析结果如图所示。

2.分析电影类型扇形图

为了生成电影类型的扇形图,我们可以通过对电影类型数据进行聚合。具体实现见代码所示。

-- 电影类型
SELECT genre, COUNT(1) AS pv
FROM ods_movie_data
WHERE day = '2023-10-10'
GROUP BY genre;

执行上述代码,分析结果如图所示。

 

3.分析电影评分散点图

为了生成电影评分的散点图,我们可以通过对电影评分数据进行聚合。具体实现见代码所示。

-- 电影评分
SELECT rating, COUNT(1) AS pv
FROM ods_movie_data
WHERE day = '2023-10-10'
GROUP BY rating;

执行上述代码,分析结果如图所示。

3.总结

本篇聚焦于构建大数据分析系统,全面介绍了该系统的架构设计,并深入探讨了各个模块的实现细节。通过循序渐进的方式,读者能够逐步了解大数据分析系统的构建过程,从而更好地理解其运作机制。
总体而言,本篇内容旨在为读者提供一个全面而深入的大数据分析系统实现指南,通过理论和实践相结合的方式,帮助读者更好地掌握大数据分析的核心概念和技术,为实际项目应用打下坚实基础。

4.结束语

这篇博客就和大家分享到这里,如果大家在研究学习的过程当中有什么问题,可以加群进行讨论或发送邮件给我,我会尽我所能为您解答,与君共勉!

另外,博主出新书了《深入理解Hive》、同时已出版的《Kafka并不难学》和《Hadoop大数据挖掘从入门到进阶实战》也可以和新书配套使用,喜欢的朋友或同学, 可以在公告栏那里点击购买链接购买博主的书进行学习,在此感谢大家的支持。关注下面公众号,根据提示,可免费获取书籍的教学视频。

 

posted @ 2024-07-28 15:15  哥不是小萝莉  阅读(527)  评论(1编辑  收藏  举报