数据仓库系列11:ETL的主要步骤是什么,它们分别有什么作用?

news2024/11/23 19:05:12

你是否曾经感觉被海量数据淹没?是否在寻找一种方法来有效地整合、转换和加载这些数据?如果是,那么你来对地方了。今天,我们将深入探讨ETL(Extract, Transform, Load)过程的三个关键步骤,这是每个大数据开发者都应该掌握的核心技能。准备好踏上成为数据整合大师的旅程了吗?让我们开始吧!
稿定设计-9.png

目录

    • 什么是ETL?
    • ETL的三大步骤
      • 第一步:提取(Extract)
      • 第二步:转换(Transform)
      • 第三步:加载(Load)
    • ETL示例:电商数据分析
      • 步骤1:提取(Extract)
      • 步骤2:转换(Transform)
      • 步骤3:加载(Load)
    • ETL工具与技术
    • ETL最佳实践
    • 结论

什么是ETL?

在深入探讨ETL的具体步骤之前,让我们先来理解什么是ETL。ETL是Extract(提取)、Transform(转换)和Load(加载)的缩写,它是数据仓库中最关键的过程之一。ETL负责将来自不同源系统的数据整合到一个集中的数据仓库中,以便进行后续的分析和报告。

想象一下,你是一位厨师,要准备一道复杂的菜肴。你需要从不同的供应商那里采购原料(提取),然后清洗、切割、调味这些原料(转换),最后将它们放入锅中烹饪(加载)。ETL过程就像这样,只不过我们处理的是数据,而不是食材。
image.png

ETL的三大步骤

现在,让我们详细探讨ETL的三个主要步骤,了解它们各自的作用和重要性。

第一步:提取(Extract)

提取是ETL过程的第一步,也是整个过程的基础。在这一步中,我们从各种数据源中获取所需的数据。这些数据源可能包括:

  • 关系型数据库(如MySQL, Oracle, SQL Server)
  • NoSQL数据库(如MongoDB, Cassandra)
  • 平面文件(如CSV, JSON, XML)
  • API接口
  • 网页爬虫数据

提取步骤的主要作用是:

  1. 数据收集: 从多个异构源系统中收集原始数据。
  2. 数据验证: 确保提取的数据符合预期的格式和质量标准。
  3. 元数据管理: 记录数据的来源、时间戳和其他相关信息。

让我们看一个使用Python从CSV文件中提取数据的简单示例:

import pandas as pd

def extract_data(file_path):
    try:
        # 使用pandas读取CSV文件
        df = pd.read_csv(file_path)
        print(f"Successfully extracted {len(df)} rows from {file_path}")
        return df
    except Exception as e:
        print(f"Error extracting data from {file_path}: {str(e)}")
        return None

# 使用函数
sales_data = extract_data('sales_data.csv')
if sales_data is not None:
    print(sales_data.head())

这个简单的函数演示了如何使用pandas库从CSV文件中提取数据。它不仅读取数据,还进行了基本的错误处理和日志记录,这是生产环境中ETL流程的重要组成部分。

第二步:转换(Transform)

image.png

转换是ETL过程中最复杂和最重要的步骤。在这一阶段,我们对提取的原始数据进行清理、标准化和转换,使其符合目标数据仓库的结构和业务规则。转换步骤的主要作用包括:

  1. 数据清洗: 处理缺失值、去除重复数据、修正错误数据等。
  2. 数据标准化: 统一数据格式,如日期格式、度量单位等。
  3. 数据集成: 合并来自不同源系统的数据。
  4. 数据聚合: 根据业务需求对数据进行汇总或计算。
  5. 数据编码: 将分类数据转换为数值编码,或者反之。
  6. 数据派生: 基于现有数据创建新的字段或指标。

让我们通过一个具体的例子来说明转换步骤。假设我们有一个包含销售数据的DataFrame,我们需要进行以下转换:

  1. 将日期字符串转换为datetime对象
  2. 计算总销售额(数量 * 单价)
  3. 对客户类型进行编码
  4. 处理缺失的邮政编码

以下是实现这些转换的Python代码:

import pandas as pd
import numpy as np

def transform_data(df):
    # 1. 将日期字符串转换为datetime对象
    df['Date'] = pd.to_datetime(df['Date'])
    
    # 2. 计算总销售额
    df['Total_Sales'] = df['Quantity'] * df['Unit_Price']
    
    # 3. 对客户类型进行编码
    customer_type_map = {'Regular': 0, 'VIP': 1, 'New': 2}
    df['Customer_Type_Code'] = df['Customer_Type'].map(customer_type_map)
    
    # 4. 处理缺失的邮政编码
    df['Postal_Code'].fillna('Unknown', inplace=True)
    
    # 5. 创建一个新的字段:月份
    df['Month'] = df['Date'].dt.month
    
    return df

# 假设我们已经有了一个名为sales_data的DataFrame
transformed_data = transform_data(sales_data)
print(transformed_data.head())
print(transformed_data.info())

这个例子展示了几种常见的数据转换操作。在实际的ETL过程中,转换步骤可能会更加复杂,包括多表join、复杂的业务逻辑计算等。

第三步:加载(Load)

加载是ETL过程的最后一步,也是将转换后的数据写入目标系统的过程。这个目标系统通常是一个数据仓库,但也可能是数据集市或其他类型的分析系统。加载步骤的主要作用包括:

  1. 数据写入: 将转换后的数据插入或更新到目标表中。
  2. 索引管理: 创建或更新必要的索引以提高查询性能。
  3. 数据验证: 确保加载的数据符合目标系统的完整性约束。
  4. 历史数据管理: 维护历史数据,支持增量加载和全量加载。

加载过程可以采用不同的策略,主要包括:

  • 完全刷新: 每次ETL运行时都删除目标表中的所有现有数据,然后插入新数据。
  • 增量更新: 只加载自上次ETL运行以来发生变化的数据。
  • 合并更新: 将新数据与现有数据合并,更新已存在的记录并插入新记录。
    image.png

以下是一个使用SQLAlchemy将转换后的数据加载到PostgreSQL数据库的示例:

from sqlalchemy import create_engine
from sqlalchemy.types import Integer, Float, String, DateTime

def load_data(df, table_name, db_connection_string):
    try:
        # 创建数据库连接
        engine = create_engine(db_connection_string)
        
        # 定义列的数据类型
        dtype = {
            'Date': DateTime,
            'Product_ID': String(50),
            'Quantity': Integer,
            'Unit_Price': Float,
            'Total_Sales': Float,
            'Customer_Type': String(20),
            'Customer_Type_Code': Integer,
            'Postal_Code': String(10),
            'Month': Integer
        }
        
        # 将数据写入数据库
        df.to_sql(table_name, engine, if_exists='replace', index=False, dtype=dtype)
        
        print(f"Successfully loaded {len(df)} rows into {table_name}")
    except Exception as e:
        print(f"Error loading data into {table_name}: {str(e)}")

# 使用函数
db_connection_string = "postgresql://username:password@localhost:5432/mydatabase"
load_data(transformed_data, 'sales_fact', db_connection_string)

这个例子展示了如何将转换后的数据加载到PostgreSQL数据库中。它使用SQLAlchemy ORM来处理数据库连接和数据类型映射,这是一种流行的处理数据库操作的Python库。

ETL示例:电商数据分析

为了更好地理解ETL过程,让我们通过一个完整的电商数据分析场景来演示整个ETL流程。

假设我们是一家电子商务公司的数据分析师,需要整合来自不同系统的数据以生成销售报告。我们有以下数据源:

  1. 订单数据(CSV文件)
  2. 产品信息(JSON文件)
  3. 客户数据(关系型数据库)

我们的目标是创建一个集成的销售事实表,用于后续的分析和报告生成。

步骤1:提取(Extract)

首先,我们需要从各个数据源提取数据:

import pandas as pd
import json
import sqlite3

def extract_order_data(file_path):
    return pd.read_csv(file_path)

def extract_product_data(file_path):
    with open(file_path, 'r') as f:
        return pd.DataFrame(json.load(f))

def extract_customer_data(db_path):
    conn = sqlite3.connect(db_path)
    query = "SELECT * FROM customers"
    return pd.read_sql(query, conn)

# 提取数据
orders = extract_order_data('orders.csv')
products = extract_product_data('products.json')
customers = extract_customer_data('customers.db')

print("Extracted data:")
print("Orders shape:", orders.shape)
print("Products shape:", products.shape)
print("Customers shape:", customers.shape)

步骤2:转换(Transform)

接下来,我们需要清理、集成和转换提取的数据:

def transform_data(orders, products, customers):
    # 合并订单和产品数据
    merged_data = pd.merge(orders, products, on='product_id', how='left')
    
    # 合并客户数据
    merged_data = pd.merge(merged_data, customers, on='customer_id', how='left')
    
    # 计算总销售额
    merged_data['total_sales'] = merged_data['quantity'] * merged_data['price']
    
    # 转换日期格式
    merged_data['order_date'] = pd.to_datetime(merged_data['order_date'])
    
    # 提取年份和月份
    merged_data['year'] = merged_data['order_date'].dt.year
    merged_data['month'] = merged_data['order_date'].dt.month
    
    # 客户分类编码
    customer_type_map = {'Regular': 0, 'VIP': 1, 'New': 2}
    merged_data['customer_type_code'] = merged_data['customer_type'].map(customer_type_map)
    
    # 处理缺失值
    merged_data['category'].fillna('Unknown', inplace=True)
    
    return merged_data

# 转换数据
transformed_data = transform_data(orders, products, customers)

print("\nTransformed data:")
print(transformed_data.head())
print(transformed_data.info())

步骤3:加载(Load)

最后,我们将转换后的数据加载到数据仓库中:

from sqlalchemy import create_engine

def load_data(df, table_name, db_connection_string):
    engine = create_engine(db_connection_string)
    df.to_sql(table_name, engine, if_exists='replace', index=False)
    print(f"Successfully loaded {len(df)} rows into {table_name}")

# 加载数据
db_connection_string = "postgresql://username:password@localhost:5432/data_warehouse"
load_data(transformed_data, 'sales_fact', db_connection_string)

这个完整的ETL示例展示了如何从多个数据源提取数据,对数据进行清理和转换,然后将结果加载到数据仓库中。这种集成的销售事实表可以用于各种分析,如销售趋势分析、客户行为分析、产品性能评估等。

ETL工具与技术

虽然我们在上面的例子中使用了Python来实现ETL过程,但在实际的企业环境中,通常会使用专门的ETL工具或框架来处理大规模的数据集成任务。以下是一些流行的ETL工具和技术:

  1. Apache Spark: 一个强大的大数据处理框架,适用于大规模数据处理和ETL任务。

  2. Apache NiFi: 一个易用的、基于Web的数据流管理和ETL工具。

  3. Talend: 一个开源的ETL工具,提供图形化界面和代码生成功能。

  4. Informatica PowerCenter: 企业级的ETL平台,广泛应用于大型企业。

  5. AWS Glue: 亚马逊提供的全托管式ETL服务,与其他AWS服务集成良好。

  6. Airflow: 一个用于编排复杂数据管道的开源平台,由Airbnb开发。

  7. Pentaho Data Integration (Kettle): 一个功能强大的开源ETL工具,提供图形化设计器。

每个工具都有其优缺点,选择哪一个取决于你的具体需求、预算和技术栈。对于大数据开发者来说,熟悉至少一两种主流ETL工具是非常有必要的。

ETL最佳实践

image.png

无论你使用哪种工具或技术来实现ETL,以下是一些值得遵循的最佳实践:

  1. 数据质量优先: 在转换步骤中实施严格的数据质量检查和清理程序。垃圾进,垃圾出 - 确保你的数据仓库中只有高质量的数据。

    def validate_data(df):
        # 检查必填字段
        assert df['order_id'].notnull().all(), "存在缺失的订单ID"
        
        # 检查数值范围
        assert (df['quantity'] > 0).all(), "存在无效的订单数量"
        
        # 检查日期有效性
        assert (df['order_date'] <= pd.Timestamp.now()).all(), "存在未来日期的订单"
        
        print("数据验证通过")
    
    # 在转换步骤中调用
    validate_data(transformed_data)
    
  2. 增量加载: 对于大型数据集,考虑实施增量加载策略,只处理新的或更改的数据,而不是每次都完全重新加载。

    def incremental_load(new_data, existing_data, key_column):
        # 找出新数据中的新记录和更新记录
        merged = pd.merge(new_data, existing_data[[key_column]], on=key_column, how='left', indicator=True)
        to_insert = merged[merged['_merge'] == 'left_only'].drop('_merge', axis=1)
        to_update = merged[merged['_merge'] == 'both'].drop('_merge', axis=1)
        
        return to_insert, to_update
    
    # 使用示例
    new_records, updated_records = incremental_load(new_sales_data, existing_sales_data, 'order_id')
    
  3. 错误处理和日志记录: 实施全面的错误处理和日志记录机制,以便快速识别和解决问题。

    import logging
    
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
    
    def safe_transform(func):
        def wrapper(*args, **kwargs):
            try:
                result = func(*args, **kwargs)
                logging.info(f"Successfully executed {func.__name__}")
                return result
            except Exception as e:
                logging.error(f"Error in {func.__name__}: {str(e)}")
                raise
        return wrapper
    
    @safe_transform
    def transform_data(df):
        # 转换逻辑
        pass
    
  4. 并行处理: 利用并行处理技术来提高ETL过程的效率,特别是对于大型数据集。

    from multiprocessing import Pool
    
    def process_chunk(chunk):
        # 处理数据块的逻辑
        return transformed_chunk
    
    def parallel_transform(data, num_processes=4):
        chunks = np.array_split(data, num_processes)
        with Pool(num_processes) as p:
            results = p.map(process_chunk, chunks)
        return pd.concat(results)
    
    # 使用示例
    transformed_data = parallel_transform(large_dataset)
    
  5. 版本控制和文档: 对ETL脚本和配置进行版本控制,并保持文档的更新。这对于长期维护和团队协作至关重要。

  6. 测试: 为ETL过程编写单元测试和集成测试,确保数据转换的正确性和一致性。

    import unittest
    
    class TestETLProcess(unittest.TestCase):
        def setUp(self):
            self.sample_data = pd.DataFrame({
                'order_id': [1, 2, 3],
                'product_id': ['A', 'B', 'C'],
                'quantity': [2, 3, 1],
                'price': [10.0, 15.0, 20.0]
            })
    
        def test_total_sales_calculation(self):
            result = transform_data(self.sample_data)
            expected_total_sales = [20.0, 45.0, 20.0]
            self.assertTrue(np.allclose(result['total_sales'], expected_total_sales))
    
    if __name__ == '__main__':
        unittest.main()
    
  7. 监控和警报: 实施监控系统来跟踪ETL作业的性能和状态,并在出现问题时发送警报。

  8. 数据隐私和安全: 确保ETL过程符合数据隐私法规(如GDPR),并实施适当的数据安全措施。

    from cryptography.fernet import Fernet
    
    def encrypt_sensitive_data(df, sensitive_columns, key):
        f = Fernet(key)
        for col in sensitive_columns:
            df[col] = df[col].apply(lambda x: f.encrypt(str(x).encode()).decode())
        return df
    
    # 使用示例
    key = Fernet.generate_key()
    encrypted_data = encrypt_sensitive_data(customer_data, ['email', 'phone'], key)
    

结论

ETL是数据仓库和大数据项目中不可或缺的一部分。通过掌握提取、转换和加载这三个关键步骤,你可以有效地整合来自不同源系统的数据,为后续的数据分析和商业智能提供坚实的基础。

在本文中,我们深入探讨了ETL的每个步骤,提供了实际的代码示例,并讨论了一些常用的工具和最佳实践。记住,成功的ETL过程不仅需要技术技能,还需要对业务需求的深入理解和对数据质量的不懈追求。

作为一名大数据开发者,持续学习和实践ETL技术将使你在竞争激烈的数据科学领域中脱颖而出。无论你是在构建数据湖、实施实时分析系统,还是开发机器学习模型,扎实的ETL技能都将是你的强大武器。

最后,我想强调的是,ETL不仅仅是一个技术过程,它是连接原始数据和有价值洞察之间的桥梁。通过精心设计和实施ETL流程,你可以将杂乱无章的数据转化为结构化的、可操作的信息,为企业决策提供强有力的支持。

你准备好接受ETL的挑战了吗?开始实践吧,让数据为你所用!

数据仓库.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2082933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Dubbo源码解析之@DubboService、@DubboReference(Dubbo源码一)

更好的阅读体验&#xff1a;Dubbo源码解析之DubboService、DubboReference&#xff08;Dubbo源码一&#xff09; 视频讲解&#xff1a;https://www.bilibili.com/video/BV1nBsMejEbL 对于Dubbo用的最多的就是DubboService、DubboReference&#xff0c;与之对应的就是服务的提供…

diskgenuis打开vmdk文件提示读扇区错误

使用DiskGenius_V5_2_x86打开iKuai-0.vmdk 读扇区错误&#xff01; 磁盘: 起始于 0 扇区 共 1 个扇区。 (Err:0) 读扇区错误&#xff01; 磁盘: VD0:iKuai-0.vmdk(2GB) 起始于 0 扇区 共 2 个扇区。 (Err:0) 更换官网最新版本 https://www.diskgenius.cn/download.php 可…

一个PPT做3天?有这3个AI做PPT工具再也不发愁!

ppt是什么东西&#xff1f; ppt是英文Powerpoint的缩写&#xff0c;它是微软出品的演示文稿软件&#xff0c;因为其在演示领域的领导地位&#xff0c;也让它成为幻灯片或演示文稿的代名词。 一个完整的ppt&#xff0c;通常包含很多要素&#xff0c;如ppt封面页、ppt目录页、p…

解决Java中Long类型的序列化与JDK8时间的序列化

1.背景 SpringBoot与前端交互 这个场景下Long类型与前端JS交互时会存在精度丢失&#xff0c;根本原因是JS的Number支持不到19位&#xff0c;所以需要后端将Long类型的值转为StringJDK8的时间类 JDK8的时间类比如LocalDateTime、LocalDate 在交互时序列化默认格式是 “yyyy-MM-…

LLM 应用开发入门 - 实现 langchain.js ChatModel 接入火山引擎大模型和实现一个 CLI 聊天机器人(上)

前言 Langchain 是一个大语言模型(LLM)应用开发的框架,提供了 LLM 开发中各个阶段很多非常强大的辅助工具支持。对于进行 LLM 开发是必不可少的工具库。 本文将通过一个实际的开发例子来入门 LLM 开发基础工具链,并实现 langchain.js ChatModel 接入火山引擎大模型和基于…

【Python入门】第4节 函数

&#x1f4d6;第4节 函数 ✅函数介绍✅函数的定义✅函数的参数✅函数的返回值&#x1f9ca;None类型的应用场景 ✅函数说明文档✅函数的嵌套调用✅变量的作用域 ✅函数介绍 函数是&#xff1a; 组织好的、可重复使用的、用来实现特定功能的代码段使用函数的好处是&#xff1a;…

erlang学习:用OTP构建系统1

书上案例学习并测试 23.1 通用事件处理 -module(event_handler). %% API -export([make/1, add_handler/2, event/2]).%% 制作一个“什么都不干”的事件处理器Name&#xff08;一个原子&#xff09;。这样消息就有地方发送了。 make(Name) ->register(Name, spawn(fun() -…

SpringSpring搭建SpringJdbcTemplateSpring Bean管理Spring结合Mybatis

Spring基础 Spring是什么 Spring是一个轻量级的IOC和AOP的一站式Java开发框架,是为了简化企业级开发而生的 轻量级 框架体积小(核心模块) IOC Inversion Of Control (控制反转)缩写为IOC,是由Spring管理对象,而非传统实现中由程序代码直接操控,将创建对象的控制权反转给s…

8月28日

思维导图 作业&#xff1a; 使用C手动封装一个顺序表&#xff0c;包含成员数组一个&#xff0c;成员变量N个 代码&#xff1a; #include <iostream>using namespace std;using datatype int; #define MAX 30struct SeqList {private:datatype *data;int size 0;int l…

Kafka3.x 使用 KRaft 模式部署 不依赖 ZooKeeper

前言 Kafka 从 2.8.0 版本开始引入了 Kafka Raft Metadata Mode&#xff08;KRaft 模式&#xff09;&#xff0c;这个模式允许 Kafka 在不依赖 ZooKeeper 的情况下进行元数据管理。KRaft 模式在 Kafka 3.0.0 中进入了稳定版本,本文部署的 Kafka_2.12-3.6.0 单机模式 环境 Ce…

Android插件化技术之加载未安装APK

目录 1、概述2、HOOK技术2.1、根据Android9.0系统源码&#xff0c;查看Activity.startActivity(intent,...)的调用流程2.2、根据Android9.0系统源码&#xff0c;查看Context.startActivity(intent,...)的调用流程 3、最终解决方案3.1、实现思路3.2、演示效果 4、最终代码实现4.…

Codeforces Round 968 (Div. 2)

前言 掉大分的一场比赛aaa 原因是 D1 看错条件了一直在想 D2 最后还没想出来。 Standings&#xff1a;6922 题目链接&#xff1a;Dashboard - Codeforces Round 968 (Div. 2) - Codeforces A. Turtle and Good Strings 题意&#xff1a; 给一个字符串&#xff0c;判断是否能把…

AWS CodeCommit 停服,欢迎大家使用极狐GitLab!

2024 年 7 月 25 日&#xff0c;AWS 官方发布公告称&#xff0c;旗下的代码托管服务 AWS CodeCommit 不再接受新用户的注册。这也就意味着用户不得不选择其他同类型产品。 极狐GitLab 为 GitLab 的中国发行版&#xff0c;可以一键私有化部署&#xff0c;详情可查看官网指南。 A…

超实用的8个无版权、免费、高清图片素材网站整理

不管是设计、文章配图&#xff0c;还是视频制作&#xff0c;图片都至关重要。但是图片版权一直都是困扰很多设计、自媒体以及企业的大问题。现在&#xff0c;因为图片侵权被告的案例已经是司空见惯了&#xff0c;有的公众号甚至因为图片版权问题遭受致命打击。 1. Pexels Pexe…

2 Python开发工具:PyCharm的安装和使用

本文是 Python 系列教程第 2 篇&#xff0c;完整系列请查看 Python 专栏。 1 安装 官网下载地址https://www.jetbrains.com.cn/pycharm/&#xff0c;文件比较大&#xff08;约861MB&#xff09;请耐心等待 双击exe安装 安装成功后会有一个30天的试用期。。。本来想放鸡火教程&…

Elastic日志分析

目录 介绍步骤 介绍 Elasticsearch 是在 Apache Lucene 上构建的分布式搜索和分析引擎。Elasticsearch常用于日志分析、全文搜索、安全智能、业务分析和运维智能使用案例。 可以使用 JSON 文档形式或通过 API 等将数据发送到 Elasticsearch。 Elasticsearch 自动存储原始文档…

免杀笔记 ---> CS特性角度看Veh免杀

前一段时间在玩WBGlIl大佬以前发的一篇过卡巴的思路&#xff08;虽然现在不过了&#xff09;&#xff0c;但是在研究的时候发现如果我们我们在没有CS的特性基础下直接看这篇文章&#xff0c;或者说你去魔改他的脚本是不太可能的&#xff0c;刚好就来普及一下这个CS的一些简单特…

胃癌TMEscore的前瞻性临床研究(TME)

目录 ①关于胃癌TME分型介绍 ②TMEscore计算-TMEscore包 ③关于TMEscore的前瞻性研究 ①关于胃癌TME分型介绍 Tumor Microenvironment Characterization in Gastric Cancer Identifies Prognostic and Immunotherapeutically Relevant Gene Signatures - PubMed (nih.gov) …

【Linux —— POSIX信号量 - 基于环形队列的生产消费模型】

Linux —— POSIX信号量 - 基于环形队列的生产消费模型 POSIX信号量信号量的概念POSIX信号量的类型信号量的操作 POSIX信号量函数基于环形队列的生产消费模型设计思路同步和安全性代码 POSIX信号量 信号量的概念 POSIX信号量是一种用于进程和线程之间同步的机制&#xff0c;主…

【网络】网络层协议——IP协议

目录 1.TCP和IP的关系 2.IP协议报文 2.1. 4位首部长度&#xff0c;16位总长度&#xff0c;8位协议 2.2. 8位生存时间 &#xff0c;32位源IP地址和32位目的IP地址 3.IP地址的划分 3.1.IP地址的表现形式 3.2.旧版IP地址的划分 3.2.1.旧版IP地址的划分思路 3.2.2.分类划…