大数据开发学习Day7

一、Linux / Shell

任务:sort / uniq 日志去重统计(sort 负责排序使相同行相邻,uniq 负责去重统计,两者组合是日志分析的黄金搭档,这是大数据 “UV/PV 统计” 的 Linux 最简实现)

对 access.log 执行:
1.取出所有 IP(第 1 列)
2.排序
3.去重并统计每个 IP 出现次数
4.按出现次数倒序排列

awk '{print $1}' access.log | sort | uniq -c | sort -nr
  • sort

语法:

sort [选项] [文件...]

-n	按数值排序	   	    sort -n file
-r	反向排序	     	    sort -r file
-k	指定排序字段	  	    sort -k 2 file
-t	指定字段分隔符	   	sort -t ':' -k 3 file
-u	去重排序	     	    sort -u file
-o	输出到文件	        sort -o output.txt file
-h	人类可读数值(1K,2M)	sort -h file
-V	版本号排序           sort -V file

示例:

# 按第二列排序(默认空格分隔)
sort -k 2 access.log

# 按IP地址排序(点分隔)
sort -t '.' -k 1,1n -k 2,2n -k 3,3n -k 4,4n ips.txt

# 按多个字段排序
sort -k1,1 -k2,2n file  # 先按字段1,再按字段2数值

# 去重排序
sort -u access.log > unique.log
  • uniq

语法:

uniq [选项] [输入文件] [输出文件]

-c		统计重复次数		uniq -c file
-d		只显示重复行		uniq -d file
-u		只显示唯一行		uniq -u file
-i		忽略大小写		uniq -i file
-f n	跳过前n个字段	uniq -f 1 file
-s n	跳过前n个字符	uniq -s 2 file

注意:uniq只处理相邻重复行,必须先排序!

# 错误示例 - 不会去重
uniq file.txt

# 正确示例
sort file.txt | uniq

组合场景:

统计日志中IP访问次数

# 提取IP,排序,去重统计,按次数倒序
awk '{print $1}' access.log | sort | uniq -c | sort -rn

# 只显示前10个
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

统计HTTP状态码

awk '{print $9}' access.log | sort | uniq -c | sort -rn

# 输出示例:
#   543 200
#    89 404
#    23 500

统计特定时间段

# 统计每小时请求数
awk '{print $4}' access.log | cut -d: -f2 | sort | uniq -c

# 统计每天请求数
awk '{print $4}' access.log | cut -d/ -f1-3 | sort | uniq -c

查找高频错误

# 统计错误日志中的错误类型
grep "ERROR" app.log | awk -F']' '{print $2}' | sort | uniq -c | sort -rn

多字段组合统计

# 统计每个IP访问每个URL的次数
awk '{print $1, $7}' access.log | sort | uniq -c | sort -rn

# 统计每小时每个状态码的数量
awk '{print $4, $9}' access.log | cut -d: -f2 | sort | uniq -c

二、SQL

今日方向:中位数 + 多表复杂统计 + 区间判断

569. 员工薪水中位数(窗口函数 + 计数,极高频)

WITH ranked AS (
    SELECT
        Id,
        Company,
        Salary,
        ROW_NUMBER() OVER (PARTITION BY Company ORDER BY Salary) AS rn,
        COUNT(*) OVER (PARTITION BY Company) AS cnt
    FROM Employee
)
SELECT
    Id,
    Company,
    Salary
FROM ranked
WHERE rn IN (FLOOR((cnt + 1) / 2), CEIL((cnt + 1) / 2));

中位数通用解法
奇数:取中间一条 偶数:
取中间两条
公式:rn IN ( (cnt+1)/2, (cnt+2)/2 )

窗口函数 COUNT () OVER (PARTITION BY)
不改变行数,直接获取每组总条数
避免子查询嵌套,性能更高*

FLOOR / CEIL
向下取整 / 向上取整
用于兼容奇偶两种情况

1321. 餐馆营业额计算(滑动窗口 / 累计求和)

SELECT distinct t1.visited_on,
sum(t2.amount) as amount,
round(sum(t2.amount)/7, 2) as average_amount
from customer t1 join customer t2 
on datediff(t1.visited_on, t2.visited_on) between 0 and 6
group by t1.visited_on, t1.customer_id
having count(distinct t2.visited_on) = 7
order by visited_on

滑动窗口(7 日滑动求和 / 均值)
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
表示:当前行 + 前 6 行,共 7 行

OVER (ORDER BY) 无 PARTITION
全局按时间排序,实现连续日期滑动计算

先按天聚合再滑动
同一天可能有多条记录,必须先 SUM 再做窗口

1454. 每位用户的活跃天数

SELECT
    user_id,
    COUNT(DISTINCT DATE(activity_time)) AS active_days
FROM Activity
GROUP BY user_id
HAVING active_days >= 3;

COUNT(DISTINCT DATE(…))
同一天多次行为只算 1 天活跃
是 DAU / 活跃用户统计标准写法

DATE()
截取datetime 的日期部分,忽略时分秒

HAVING 过滤分组结果
不能用 WHERE,因为是聚合后过滤

三、PySpark 核心新内容

缺失值处理 + 多字段聚合 + 写入文件 + 简单性能调优
直接在 PyCharm 运行:

from pyspark.sql import SparkSession
from pyspark.sql import functions as F
from pyspark.sql.types import IntegerType

spark = SparkSession.builder \
    .master("local[*]") \
    .appName("day7") \
    .getOrCreate()

# 构造含缺失值的数据
data = [
    (1, "click", 10, None),
    (1, "click", 20, "2025-01-01"),
    (2, "view", None, "2025-01-01"),
    (3, "buy", 50, "2025-01-02")
]
df = spark.createDataFrame(data, ["uid", "event", "cost", "dt"])

# ==================== 新知识点1:缺失值处理 ====================
# 查看缺失
df.select([F.count(F.when(F.isnull(c), c)).alias(c) for c in df.columns]).show()

# 填充缺失值
df = df.fillna({"cost": 0, "dt": "2025-01-01"})

# ==================== 新知识点2:多维度聚合 ====================
df.groupBy("uid", "event") \
  .agg(
      F.sum("cost").alias("total_cost"),
      F.avg("cost").alias("avg_cost"),
      F.count("*").alias("cnt")
  ).show()

# ==================== 新知识点3:过滤 + 排序 ====================
df.filter(F.col("total_cost") > 0) \
  .orderBy(F.desc("total_cost")) \
  .show()

# ==================== 新知识点4:写入CSV(实战必备) ====================
# df.write.mode("overwrite").option("header", True).csv("./day7_output")

spark.stop()
+---+-----+----+----------+
|uid|event|cost|        dt|
+---+-----+----+----------+
|  1|click|  10|2025-01-01|
|  1|click|  20|2025-01-01|
|  2| view|   0|2025-01-01|
|  3|  buy|  50|2025-01-02|
+---+-----+----+----------+

1.缺失值统计 isnull

df.select([F.count(F.when(F.isnull(c), c)).alias(c) for c in df.columns])

知识点:isnull() 判断空值
作用:快速查看每列缺失率,数据开发第一步

2.fillna 按列填充

df.fillna({"cost": 0, "dt": "2025-01-01"})

知识点:不同列用不同填充策略
cost 数值型 → 填 0
dt 日期型 → 填默认日期

3.多列聚合 agg

.agg(
    F.sum("cost").alias("total_cost"),
    F.avg("cost").alias("avg_cost"),
    F.count("*").alias("cnt")
)

知识点:一次 groupBy 做多个聚合
企业级数仓最常用写法

4.写出文件模式 overwrite/append

overwrite:覆盖
append:追加
ignore:存在则不写
面试高频:生产环境严禁随意 overwrite

小知识点:
大数据表90% 场景都要处理缺失值,面试必问

四、算法

560.和为 K 的子数组(哈希表 + 前缀和)

要求:
理解前缀和思想
能写出 O (n) 最优解
知道暴力解法为什么超时

def subarraySum(nums, k):
    pre_sum = {0: 1}
    cur = 0
    res = 0
    for num in nums:
        cur += num
        # 找 cur - k 出现过几次
        res += pre_sum.get(cur - k, 0)
        pre_sum[cur] = pre_sum.get(cur, 0) + 1
    return res

前缀和公式
sum(i~j) = prefix[j] - prefix[i-1]
要求 sum = k → prefix[j] - prefix[i-1] = k
→ prefix[i-1] = prefix[j] - k

哈希表记录前缀和出现次数
O (n) 时间复杂度
空间 O (n)

为什么初始 {0:1}
处理从第 0 位开始的子数组
例如 nums [0] 直接等于 k 的情况

暴力解法 O (n²)
两层循环枚举所有区间
数据量大必超时,面试不接受

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值