Loading......

文章背景图

📌 字节跳动大数据开发面经 3️⃣

2025-12-24
15
-
- 分钟

一、核心面试问题集锦 🎯

1. 项目是根据什么业务场景来划分的

🔍 考察重点:项目规划逻辑、业务与数据的关联能力、数仓 / 大数据项目的划分思路

📌 核心解答:

大数据项目的业务场景划分,核心是 “以业务需求为导向,结合数据产生的源头和用途”,常见划分维度及落地逻辑如下:

① 按核心业务域划分(最主流):

根据企业核心业务板块拆分,比如视频平台可划分为 “用户行为域”(观看、点赞、评论)、“内容运营域”(视频上传、审核、推荐)、“用户管理域”(注册、登录、画像)、“商业化域”(广告投放、充值)等。

逻辑:每个业务域对应一套完整的业务流程,数据需求和加工逻辑相对独立,便于团队分工和数据管理。

② 按业务目标划分:

围绕具体业务目标拆分场景,比如 “用户增长场景”(统计新增用户、留存率)、“内容优化场景”(视频完播率、热门视频分析)、“风控场景”(异常观看行为检测)等。

逻辑:直接对齐业务决策需求,确保数据产出能直接支撑业务目标达成。

③ 按数据来源 / 形态划分:

比如 “日志数据场景”(用户行为埋点日志)、“业务数据库同步场景”(用户信息、视频元数据)、“实时监控场景”(实时在线人数、实时播放量)等。

逻辑:不同来源 / 形态的数据,处理技术(批处理 / 流处理)和存储方式不同,按此划分可提升技术选型的针对性。

💡 示例(视频平台场景):

若需做 “视频内容优化” 相关项目,会划分到 “内容运营域 - 内容效果分析场景”,核心处理视频观看日志、完播数据,支撑运营同学调整视频推荐策略。

2. 对 Hadoop 的理解

🔍 考察重点:Hadoop 核心组件、核心思想、适用场景、行业价值

📌 核心解答:

Hadoop 是开源的分布式大数据处理框架,核心解决 “海量数据的存储和并行计算” 问题,是大数据生态的基础,主要包含三大核心组件及周边生态工具。

① 核心组件(Hadoop 2.x + 核心架构):

  • HDFS(分布式文件系统):负责海量数据的分布式存储,采用 “主从架构”——NameNode(主节点)管理元数据(文件名、路径、Block 位置),DataNode(从节点)存储实际数据块(默认 128MB / 块),通过多副本(默认 3 份)保证数据可靠性。

  • YARN(资源管理框架):负责集群资源(CPU、内存)的调度和管理,接收计算任务请求,分配资源给任务节点,监控任务执行状态。

  • MapReduce(分布式计算框架):基于 “分而治之” 思想,实现海量数据的并行计算,分为 Map(映射)和 Reduce(归约)两个核心阶段,依赖 YARN 调度资源、HDFS 存储数据。

    ② 核心思想:

  • 分布式存储:将大文件拆分为多个小数据块,分散存储在多个节点,突破单节点存储上限;

  • 并行计算:将大任务拆分为多个小任务,在多个节点同时执行,提升计算效率;

  • 容错性:通过数据多副本、节点故障自动切换(如 NameNode HA),保证集群稳定运行。

    ③ 适用场景:

    批处理海量数据(如日志分析、离线报表统计),不适合实时计算(如毫秒级响应)、小数据量计算场景。

    ④ 生态周边:

    Hive(基于 Hadoop 的数据仓库工具,将 SQL 转为 MapReduce 任务)、Spark(基于内存的计算框架,兼容 Hadoop 生态)、HBase(分布式列式数据库)等,共同构成大数据处理生态。

3. 讲一下 MapReduce 的执行过程

🔍 考察重点:MapReduce 核心执行流程、各阶段关键操作、数据流转逻辑

📌 核心解答:

MapReduce 执行过程分为 “输入→Map 阶段→Shuffle 阶段→Reduce 阶段→输出”5 个核心步骤,全程由 YARN 调度资源、HDFS 提供数据存储,具体流程如下:

① 输入阶段(Input):

  • 读取 HDFS 上的原始数据,由 InputFormat(默认 TextInputFormat)将数据拆分为多个 InputSplit(输入分片),每个 InputSplit 对应一个 Map 任务;

  • 注意:InputSplit 不是实际数据块,而是数据的逻辑分片,默认与 HDFS Block 大小一致(128MB),确保数据本地性(Map 任务优先在数据所在节点执行,减少网络传输)。

    ② Map 阶段(映射):

  • Map 任务接收 InputSplit 数据,通过 RecordReader 解析为 <key,value> 键值对(如文本数据默认 < 行号,行内容 >);

  • 执行用户自定义的 map () 函数,对键值对进行处理(如过滤、转换),输出中间键值对 < k1, v1>;

  • 中间结果先写入内存缓冲区(默认 100MB),当缓冲区达到阈值(默认 80%),会触发溢写(Spill),将数据排序(Sort)后写入本地磁盘临时文件。

    ③ Shuffle 阶段(洗牌,核心桥梁):

    Map 输出到 Reduce 输入的中间数据流转阶段,核心是 “数据分区、排序、合并”,确保相同 key 的数据集被分发到同一个 Reduce 任务,具体步骤:

  • 分区(Partition):Map 阶段溢写前,按 Reduce 任务数量对中间键值对分区(默认 HashPartition),相同 key 落在同一分区;

  • 排序(Sort):溢写时对每个分区内的键值对按 key 排序;

  • 合并(Combine+Merge):Map 端可通过自定义 Combine 函数(可选)对同一分区的相同 key 数据预聚合(减少数据量);之后 Reduce 端通过 Shuffle Fetcher 线程拉取所有 Map 节点对应分区的临时文件,再进行合并(Merge)和二次排序,得到有序的 <k1, list (v1)>。

    ④ Reduce 阶段(归约):

  • Reduce 任务接收 Shuffle 阶段传来的 <k1, list (v1)>,执行用户自定义的 reduce () 函数(如聚合、统计),输出最终键值对 < k2, v2>;

  • 若有多个 Reduce 任务,输出结果分别写入 HDFS 的不同文件(最终可通过合并工具合并为一个文件)。

    ⑤ 输出阶段(Output):

    由 OutputFormat(默认 TextOutputFormat)将 Reduce 输出的 <k2, v2> 写入 HDFS,完成整个计算流程。

4. Shuffle 的必要性

🔍 考察重点:Shuffle 在 MapReduce 中的核心作用、无 Shuffle 的问题

📌 核心解答:

Shuffle 是 MapReduce 中连接 Map 和 Reduce 的核心桥梁,其必要性源于 “Map 任务并行执行的分散性” 与 “Reduce 任务聚合需求的集中性” 的矛盾,具体作用如下:

① 实现数据的 “分区分发”:

Map 任务是并行执行的,每个 Map 只处理部分数据,而 Reduce 任务需要对 “相同 key 的全量数据” 进行聚合(如统计每个视频的总观看次数,需收集所有 Map 输出的该视频 key 数据)。Shuffle 通过分区机制,确保同一 key 的所有数据精准分发到同一个 Reduce 任务,为聚合提供数据基础。

② 保证数据有序性,提升计算效率:

Shuffle 过程中会对数据进行排序(Map 端溢写排序、Reduce 端合并排序),有序的数据可减少 Reduce 阶段的计算开销(如无需再对相同 key 的数据重新排序),同时支持后续的分组(Group)操作。

③ 减少数据传输量,优化性能:

Shuffle 的 Combine(Map 端预聚合)和 Merge(Reduce 端合并)操作,可将相同 key 的重复数据提前合并,减少从 Map 端到 Reduce 端的网络传输量,降低集群网络压力,提升整体任务执行效率。

💡 反证:若无 Shuffle,Map 输出的分散数据无法按 key 聚合到 Reduce 任务,Reduce 无法完成全局计算(如无法统计全量的 key 对应的结果),MapReduce 的 “分而治之” 思想无法落地,海量数据的并行聚合计算也就无法实现。

5. 维度建模是怎么建模的,事实表和维度表有什么区别

🔍 考察重点:维度建模流程、事实表与维度表的核心差异、落地逻辑

📌 核心解答:

一、维度建模流程

维度建模是以 “分析需求” 为核心,围绕 “事实” 和 “维度” 构建数据模型的方法,核心流程为 “确定业务过程→识别事实→识别维度→构建模型(星型 / 雪花)→加载数据”:

  1. 确定业务过程:明确要分析的核心业务场景(如视频观看、订单支付、用户注册);

  2. 识别事实:提取业务过程中可量化、可统计的核心指标(如观看次数、支付金额、注册人数),形成事实表;

  3. 识别维度:提取描述事实的上下文信息(如观看时间、视频分类、用户性别),形成维度表;

  4. 构建模型:根据维度表的规范化程度,选择星型模型或雪花模型;

  5. 加载数据:将 ODS 层数据清洗转换后,加载到事实表和维度表。

二、事实表和维度表的区别(对比梳理)

对比维度

事实表

维度表

核心定义

记录业务过程中可量化的事实(指标)数据

记录描述事实的上下文信息(属性)

数据特征

数据量大、粒度细、更新频繁(如每笔观看行为都记录)

数据量小、粒度粗、更新不频繁(如视频分类基本稳定)

核心字段

事实指标(如观看时长、完播标记)、维度外键(如 user_id、video_id、time_id)

维度主键(如 user_id)、维度属性(如用户性别、视频类型、时间维度的年 / 月 / 日)

作用

存储核心统计数据,支撑指标计算(如完播率、观看量)

提供筛选、分组、描述维度,支撑多维度分析(如按性别统计完播率)

示例(视频场景)

video_watch_fact(user_id、video_id、watch_time、is_complete、watch_date)

user_dim(user_id、gender、age)、video_dim(video_id、category、duration)

6. 星型模型和雪花模型区别

🔍 考察重点:两种维度建模模型的结构差异、优缺点、适用场景

📌 核心解答:

星型模型和雪花模型的核心差异在于 “维度表的规范化程度”,均以事实表为中心,维度表围绕事实表关联,具体区别如下:

对比维度

星型模型

雪花模型

结构特点

事实表位于中心,所有维度表直接与事实表关联,维度表为 “非规范化” 设计(无维度表之间的关联)

事实表位于中心,部分维度表会进一步拆分为子维度表(规范化设计),子维度表与主维度表关联,再间接关联事实表

维度表数量

较少,仅核心维度表

较多,包含主维度表和子维度表

查询效率

高:关联层级少(仅事实表 - 维度表),减少表连接开销;非规范化设计减少查询时的计算量

低:关联层级多(事实表 - 主维度表 - 子维度表),表连接开销大;规范化设计可能需要更多计算

数据冗余

较高:维度表非规范化,可能存在重复属性(如视频维度表同时存储 category_name 和 category_desc,无单独分类表)

较低:维度表规范化拆分,属性仅存储一次(如单独的 category_dim 表存储分类信息,视频维度表仅存 category_id)

维护成本

低:维度表结构简单,新增 / 修改属性直接操作核心维度表,无需联动

高:维度表拆分后,新增 / 修改属性可能需要联动主维度表和子维度表,维护复杂

适用场景

业务简单、需求明确的离线分析场景(如常规报表、简单多维度统计),优先选星型模型(大厂数仓常用)

业务复杂、数据冗余敏感、需要严格规范化的场景(如数据一致性要求极高的金融场景),较少使用

💡 示例(视频场景):

  • 星型模型:事实表(video_watch_fact)直接关联 user_dim(用户)、video_dim(视频)、time_dim(时间);

  • 雪花模型:video_dim 拆分为 video_main_dim(视频基本信息,含 category_id)和 category_dim(分类信息),事实表→video_main_dim→category_dim 关联。

7. 讲一下对维度的理解,如果从视频和观看时间来看,会怎么去区分事实和维度

🔍 考察重点:维度的核心定义、事实与维度的区分逻辑、业务场景落地能力

📌 核心解答:

一、对维度的理解

维度是 “描述事实的上下文信息”,核心作用是为事实数据提供 “筛选、分组、聚合的分析视角”,是维度建模的核心组成部分。

  • 本质:回答 “谁、何时、何地、什么、如何” 等分析问题的属性集合(如分析视频观看事实,可通过 “用户维度” 回答 “谁看的”,“时间维度” 回答 “何时看的”);

  • 特点:数据相对稳定、可重复复用,粒度可粗可细(如时间维度可分为年、月、日、时);

  • 常见类型:时间维度、用户维度、商品 / 内容维度(如视频)、地域维度等。

二、视频和观看时间场景下的事实与维度区分

区分核心原则:

  • 事实:可量化、记录业务过程发生的 “行为 / 指标”(是 “动作” 或 “结果”);

  • 维度:描述事实的 “属性 / 上下文”(是 “描述信息”,用于分析筛选)。

具体区分(视频观看场景):

  1. 维度识别:

  • 视频维度:属于 “内容维度”,描述视频本身的属性,如视频 ID(video_id)、视频分类(category)、视频时长(duration)、上传者(uploader_id)等;

  • 观看时间维度:属于 “时间维度”,描述观看行为发生的时间上下文,如观看日期(watch_date)、观看小时(watch_hour)、是否周末(is_weekend)等;

  • 补充维度:用户维度(user_id、gender)、设备维度(device_type)等也属于描述观看事实的维度。

  1. 事实识别:

  • 核心事实:观看行为本身及可量化指标,如是否观看(watch_flag)、观看时长(watch_duration)、是否完播(is_complete)、观看次数(watch_count)等;

  • 事实表示例:video_watch_fact(user_id、video_id、watch_date、watch_duration、is_complete),其中 user_id、video_id、watch_date 是维度外键,watch_duration、is_complete 是事实指标。

    💡 总结:视频和观看时间的 “属性信息” 是维度,基于视频发生的 “观看动作及量化结果” 是事实。

8. 数据去重的方法;count distinct 和 group by 区别

🔍 考察重点:数据去重的实际落地方法、两种计数方式的核心差异与适用场景

📌 核心解答:

一、数据去重的方法(按场景分类)

  1. 单字段去重:

  • 用 DISTINCT 关键字:适用于简单的单字段去重查询(如 SELECT DISTINCT user_id FROM video_watch_log);

  • 用 GROUP BY 分组:通过分组实现单字段去重(如 SELECT user_id FROM video_watch_log GROUP BY user_id),效果与 DISTINCT 一致。

  1. 多字段去重(按组合维度去重):

  • 用 DISTINCT 多字段:SELECT DISTINCT user_id, video_id FROM video_watch_log(去重 “同一用户观看同一视频” 的重复记录);

  • 用 GROUP BY 多字段:SELECT user_id, video_id FROM video_watch_log GROUP BY user_id, video_id,与 DISTINCT 多字段效果一致。

  1. 窗口函数去重(保留其他字段):

    当需要去重同时保留其他字段时,用 ROW_NUMBER () 开窗排序去重,如去重同一用户同一视频的重复观看记录,保留最新一条:

sql

WITH ranked_log AS (
  SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY user_id, video_id ORDER BY watch_time DESC) AS rn
  FROM video_watch_log
)
SELECT * FROM ranked_log WHERE rn = 1;
  1. 存储层去重:

  • 写入数据时去重:用 INSERT OVERWRITE + DISTINCT/GROUP BY 覆盖写入,避免重复数据累积;

  • 用主键约束:如 Hive 中无严格主键,但可通过业务主键(如 user_id+video_id+watch_date)在加工时保证唯一性。

二、count distinct 和 group by 区别

对比维度

count distinct

group by + count

核心功能

直接统计某字段的不重复值个数(如 count (distinct user_id) 统计独立用户数)

先按字段分组(去重),再统计每组的记录数(默认 count (*)),可间接实现去重计数

使用场景

简单的独立值计数(无需关注分组后的其他信息)

需要分组后统计计数,或需同时获取分组字段信息(如统计每个视频的独立观看用户数)

性能表现

大数据量下性能较差:会将所有去重字段数据汇总到少数 Reduce 任务,易发生数据倾斜

性能更优:分组后并行计数,可通过调整并行度优化;若需全局计数,可二次聚合(group by null)

结果形态

返回单个值(全局计数)或按其他字段


评论交流