1. 深深深挖简历 -— 答案略
  2. 14亿数据,uid,amt金额,全局排序思路:金额中位数分区,金额分区
  3. 英文文章,统计a的次数
  4. Java exception 见过吗
  5. Hive spark sql语法差别

一、14亿条数据(uid, amt)的全局排序思路:金额中位数分区与金额分区

考察知识点

大数据全局排序的核心挑战(内存限制、并行效率)、分区策略(中位数分区/范围分区的原理)、分布式计算框架的排序实现(Spark的sortBy/orderBy机制)、数据倾斜处理、Shuffle优化、存储与IO效率

参考回答

14亿条数据(每条约20字节,总数据量约28GB)的全局排序需突破单机内存限制,依赖分布式计算框架(如Spark)的并行处理能力,核心思路是“先分区减少数据量,再局部排序+全局合并”,其中金额中位数分区和金额分区是两种高效的分区策略。

(一)整体流程框架

全局排序的核心逻辑可概括为“3步走”:

  1. 数据预处理:清洗异常值(如amt为负数/NULL),转换数据格式(如amt转为Double类型),避免排序错误;
  2. 分区划分:通过采样计算分区边界(中位数或自定义范围),将14亿条数据均匀分配到多个分区;
  3. 两级排序:每个分区内局部排序,最后按分区顺序合并为全局有序结果。

(二)金额中位数分区策略(动态自适应分区)

中位数分区通过“采样-计算中位数-递归分区”实现数据均匀分布,适合amt分布未知的场景,步骤如下:

  1. 数据采样
    • 从14亿条数据中随机采样10万条(采样比例≈0.007%),确保样本具有代表性;
    • 用Spark的sample(withReplacement=false, fraction=0.0001)实现,避免采样偏差。
  2. 计算分区中位数
    • 假设目标分区数为200(每个分区约700万条数据,适合4GB内存Executor处理);
    • 对采样数据按amt排序,取第5万条(10万×50%)作为全局中位数m1,再在m1两侧的子样本中取各自中位数m2、m3,递归生成200个分区边界(如[m0, m1), [m1, m2), ..., [m199, m200])。
  3. 按中位数分区
    • repartitionByRange(200, col("amt"))(Spark SQL)或sortBy(_._2, numPartitions=200)(RDD),根据amt值将数据分配到对应分区;
    • 分区逻辑:若amt ∈ [mi, mi+1),则进入第i个分区,确保每个分区数据量均衡(±10%以内)。
  4. 局部排序与全局合并
    • 每个分区内用sortWithinPartitions(col("amt"))完成局部排序(内存+磁盘溢出排序);
    • 按分区顺序(从m0到m200)拼接各分区结果,得到全局有序数据集(因分区边界有序,局部排序后拼接即全局有序)。

(三)金额分区策略(固定范围分区)

金额分区适合amt分布已知的场景(如amt∈[0, 100万]),通过预设范围划分分区,步骤如下:

  1. 确定金额范围与分区数
    • 假设历史数据显示amt集中在[0, 100万],按每5000元为1个区间划分,总分区数=100万/5000=200(与中位数分区数一致,便于对比);
    • 分区边界为[0,5000), [5000,10000), ..., [995000, 1000000],超出范围的amt(如>100万)单独设1个分区。
  2. 按固定范围分区
    • partition_id重分区(repartition(201, col("partition_id"))),确保每个分区对应一个金额区间。
  3. 局部排序与全局合并
    • 每个分区内按amt升序排序(orderBy(amt));
    • 按分区ID从小到大拼接结果(0→1→...→200),得到全局有序数据。

case when定义分区逻辑:

SELECT uid, amt,
  CASE
    WHEN amt < 5000 THEN 0
    WHEN amt < 10000 THEN 1
    ...
    ELSE 200
  END AS partition_id
FROM data

(四)两种策略的对比与选择

维度 金额中位数分区 金额分区(固定范围)
适用场景 amt分布未知/不均匀(如长尾分布) amt分布已知/均匀(如正态分布)
分区均衡性 高(动态适配数据分布) 可能低(若实际分布与预设范围偏差大)
预处理开销 高(需采样+计算中位数) 低(直接用预设范围)
扩展性 强(新增数据不影响分区逻辑) 弱(amt范围变化需重设分区边界)

补充回答注意要点

  1. 核心得分点
    • 必须强调“分区是解决大数据排序的核心”(单机无法处理14亿条数据的全量排序);
    • 明确中位数分区的“采样-计算边界-分区”逻辑,体现对数据分布的自适应能力;
    • 说明固定范围分区的“预设边界-重分区”步骤,突出场景适配性。
  2. 避免遗漏的关键维度
    • 数据倾斜处理:若某金额区间数据量占比超30%(如amt=0的记录有5亿条),需拆分该分区(如对amt=0的记录按uid哈希再分10个子分区);
    • 分区数设置:太少(如10个)会导致单分区数据量过大(1.4亿条),内存溢出;太多(如1000个)会增加Shuffle开销,建议按“每个分区500万-1000万条数据”设置;
    • 存储优化:排序后的数据建议用Parquet(列式存储)+Snappy压缩,减少IO,且支持按amt快速查询;
    • 框架选择:Spark比MapReduce更优(MapReduce的排序依赖磁盘,Spark支持内存+磁盘混合排序,速度快3-5倍)。
  3. 性能优化细节
    • Shuffle优化:设置spark.shuffle.sort.bypassMergeThreshold=200(当分区数≤阈值时,用bypass机制减少排序开销);
    • 内存配置:Executor内存≥分区数据量的1.5倍(如700万条数据约140MB,Executor内存≥210MB);
    • 并行度:spark.default.parallelism设为Executor核数的2-3倍(如20个Executor×4核=80核,并行度设为160-240)。

二、英文文章中统计“a”的次数

考察知识点

字符串处理(边界判断、大小写转换)、文本分片与并行计算、正则表达式应用、性能优化(避免全量加载)、特殊场景处理(标点符号、缩写词)

参考回答

统计英文文章中“a”的次数需明确“a”的定义(是单个字符、独立单词,还是包含缩写/特殊形式),并根据文章大小(KB级小文件/GB级大文件)选择不同处理方案,核心逻辑是“匹配-计数-聚合”。

(一)明确“a”的统计范围(核心前提)

需先定义统计规则(面试中需主动询问面试官,体现严谨性),常见规则包括:

  1. 作为独立单词:仅统计小写“a”且前后为非字母(如“a cat”中的“a”,排除“apple”中的“a”);
  2. 区分大小写:仅统计小写“a”,排除“A”(如句首“A dog”中的“A”);
  3. 排除特殊形式:排除缩写(如“a.m.”中的“a”)、连字符(如“mother-in-law”中的“a”不单独统计)。

(二)小文件处理(单机方案,适合100MB以内文章)

用Python/Java实现,核心步骤:

  1. 读取文件
  2. 正则匹配“a”作为独立单词
    • 正则表达式:r'\\\\ba\\\\b'\\\\b表示单词边界,匹配前后为非字母的“a”);
    • 排除大写“A”:正则默认区分大小写,直接匹配小写“a”;
    • 处理标点:\\\\b会忽略标点(如“a.”“a,”中的“a”仍会被匹配,因“.”“,”是非字母)。

计数实现

import re
# 匹配独立小写“a”,不包含缩写/句首大写
pattern = re.compile(r'\\\\ba\\\\b')
count = len(pattern.findall(content))
print(f"独立单词'a'的次数:{count}")

用上下文管理器避免资源泄露(Python):

with open("article.txt", "r", encoding="utf-8") as f:
    content = f.read()  # 小文件可全量加载

(三)大文件处理(分布式方案,适合1GB以上文章)

GB级文章无法全量加载到内存,需用Spark分布式处理,步骤:

This post is for subscribers on the 网站会员 and 成为小万的高级会员 tiers only

Subscribe Now

Already have an account?