Databricks里用PySpark统计指定表和字段中各字段的空值、空字符串或零值比例

python 复制代码
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, coalesce, trim, when, lit, sum
from pyspark.sql.types import StringType, NumericType

# 在 Databricks 中,spark 会话通常已经存在,无需重新创建
# 如果需要显式创建,使用:
# spark = SparkSession.builder.getOrCreate()

# 配置参数
database_name = "your_database"  # 替换为实际数据库名
result_list = []

# 获取数据库中的所有表和视图(包括 Delta 表)
tables = spark.catalog.listTables(database_name)

for table in tables:
    table_name = table.name
    full_table_name = f"{database_name}.{table_name}"
    
    try:
        # 读取表或视图(Delta 表和普通表均可)
        df = spark.table(full_table_name)
        
        # 快速判断是否为空表,避免不必要的缓存
        total_count = df.count()
        if total_count == 0:
            continue
        
        # 缓存数据以便多次引用(实际上我们只需扫描一次,缓存并非必需)
        df.cache()
        
        # 构建所有字段的聚合表达式(一次性计算)
        agg_exprs = []
        field_meta = []  # 用于记录每个字段的类型和名称
        
        for field in df.schema.fields:
            col_name = field.name
            col_type = field.dataType
            
            if isinstance(col_type, StringType):
                # 字符串类型:统计 null 或 trim 后为空字符串
                modified_col = trim(coalesce(col(col_name), lit("")))
                condition = (modified_col == lit(""))
                count_expr = sum(when(condition, 1).otherwise(0)).alias(f"cnt_{col_name}")
            elif isinstance(col_type, NumericType):
                # 数值类型:统计 null 或零值
                modified_col = coalesce(col(col_name), lit(0))
                condition = (modified_col == lit(0))
                count_expr = sum(when(condition, 1).otherwise(0)).alias(f"cnt_{col_name}")
            else:
                # 其他类型:仅统计 null
                condition = col(col_name).isNull()
                count_expr = sum(when(condition, 1).otherwise(0)).alias(f"cnt_{col_name}")
            
            agg_exprs.append(count_expr)
            field_meta.append((col_name, str(col_type)))
        
        # 执行一次聚合,获取所有字段的统计值
        stats_row = df.agg(*agg_exprs).collect()[0]
        
        # 整理结果
        for col_name, col_type in field_meta:
            stat_count = stats_row[f"cnt_{col_name}"]
            percentage = round((stat_count / total_count) * 100, 2) if total_count > 0 else 0.0
            result_list.append((
                database_name,
                table_name,
                col_name,
                col_type,
                stat_count,
                total_count,
                float(percentage)
            ))
        
        df.unpersist()  # 释放缓存
        
    except Exception as e:
        print(f"Error processing table {table_name}: {str(e)}")
        continue

# 创建结果 DataFrame
result_columns = [
    "database_name",
    "table_name",
    "column_name",
    "column_type",
    "stat_count",
    "total_rows",
    "percentage"
]

result_df = spark.createDataFrame(result_list, result_columns)

# 显示结果
result_df.show(truncate=False)

# 可选:将结果保存到 Delta 表
# result_df.write.format("delta").mode("overwrite").saveAsTable("your_audit_table")

主要改动说明

原代码 修改后 原因
显式创建 SparkSession 并启用 Hive 直接使用 Databricks 内置 spark Databricks 已预配置,无需额外初始化
对每个字段分别执行 df.agg() 构建所有字段聚合表达式,一次 df.agg() 减少表扫描次数,大幅提高性能
缓存 df 后多次扫描 缓存后仅一次聚合扫描 配合优化,降低缓存开销
spark.catalog.listTables() 同样使用,能返回表和视图 无需修改,原生支持 Delta 表和视图
异常处理与结果收集 保持不变 逻辑通用

注意事项

  • 数据库名称 :根据实际环境修改 database_name,如果使用默认数据库,可设为 "default"。
  • 视图 :spark.table() 可以读取持久化视图,但临时视图不会出现在 listTables 中。如需处理临时视图,可额外指定名称列表。
  • 性能 :对于大型表,df.count() 和聚合仍会触发一次完整扫描,这是必要的。如果表极大,可考虑分批处理或使用抽样估算。
  • Delta 表:Delta 表在 Catalog 中通常显示为普通表名,读取方式与 Hive 表一致,无需特殊处理。
相关推荐
实名上网宋凯宣7 小时前
Django
后端·python·django
镜子AI7 小时前
镜子AI 技术复盘:三条自动化链路上的“停止条件“设计
运维·人工智能·自动化
tianyuanwo8 小时前
NetBox 数据库详解:当“关系型数据库”被装进一个网络运维的领域模型里
运维·数据库·netbox
如若1238 小时前
【论文复现】CoFailMed:从零复现医学图像分割的共享失败审计,含完整代码流程与科研绘图
人工智能·python
砚底藏山河9 小时前
python量化自定义周期 K 线合成
java·开发语言·数据库·python·金融
视觉小萌新10 小时前
AI Class 3 · Chapter 1:变量、字符串、list/dict、if/for(python学习-小白版-有经验可跳过)
python·学习·list
知已难寻10 小时前
03 · OpenStack的计算管理 Nova
运维·服务器·开发语言·云原生·云计算·openstack·开源软件
薛定谔的猫-菜鸟程序员10 小时前
软件架构设计师开发资料大全(从入门到精通)
后端·python·系统架构·flask·架构设计师
huainingning10 小时前
Windows syslog日志服务器搭建与模拟器对接
运维·服务器·智能路由器
say_fall11 小时前
【Linux系统编程】Ext 文件系统:磁盘与存储、文件与目录、现代计算机究竟如何寻找文件
linux·运维·服务器·数据库·c++