AWS Glue Python Shell任务中读取Athena数据库

问题

怎样在AWS Glue Python Shell任务中读取Athena数据库中的数据

通过awswrangler读取

Python

python 复制代码
import pandas as pd
import boto3
import awswrangler as wr

....
def read_data_via_athena(database, table_name, start_ts, end_ts):
    """
    使用 Athena 解决大数据量下的内存问题
    """
    # 1. 编写 SQL。在服务端完成过滤,只拉取需要的列和行
    # 建议显式写出需要的列名,如 SELECT id, created_at, user_id ... 替代 SELECT *
    sql = f"""
    SELECT * FROM "{table_name}"
    WHERE created_at >= {start_ts} 
      AND created_at < {end_ts}
    """
    
    logger.info(f"正在执行 Athena 查询,筛选表 {table_name} 的数据...")
    
    try:
        # 2. 执行查询并直接获取 DataFrame
        batch_iterator = wr.athena.read_sql_query(
            sql=sql,
            database=database,
            ctas_approach=False,
            chunksize=5000,
            keep_files=False # 查询完自动清理临时文件
        )
        return batch_iterator

    except Exception as e:
        logger.error(f"Athena 查询异常: {str(e)}")
        raise

调用使用代码(这里就通过aw从数据湖里面读出了pandas数据):

python 复制代码
# 从 Glue Catalog 读取三个表的数据(表名完全由参数控制)
    tables = {
        table_summit: 'summit',
        table_summit_device: 'summit_device',
        table_summit_user: 'summit_user'
    }
    total_pushed_count = 0
    batch_size_push = 100  # API 每次接收的记录数
    
    for glue_table, type_name in tables.items():
        logger.info(f"开始处理表: {glue_table}")
        
        # 1. 获取 Athena 迭代器 (每批从 Athena 取 50000 行)
        batch_iterator = read_data_via_athena(database_name, glue_table, start_ts, end_ts)
        
        for idx, df_chunk in enumerate(batch_iterator, start=1):
            if df_chunk.empty:
                continue
                
            logger.info(f"表 {glue_table} - 正在处理 Athena 第 {idx} 批数据,行数:{len(df_chunk)}")
            
            # 2. 将这 5000 行转换为记录列表
            chunk_records = convert_dataframe_to_records(df_chunk, type_name)


            # --- 💡 新增:打印前 10 条数据进行查看 ---
            if idx == 1:  # 只在每个表的第一批次打印,避免日志刷屏
                logger.info(f"🔍 检查表 {glue_table} 的前 10 条数据样本:")
                sample_data = chunk_records[:10]
                # 使用 json.dumps 让打印出的 JSON 格式更漂亮(缩进2格)
                print(json.dumps(sample_data, indent=2, ensure_ascii=False))
            # ---------------------------------------
            
            # 3. 针对这一批记录,再切分成 100 条一组的小批次推送到 API
            for i in range(0, len(chunk_records), batch_size_push):
                mini_batch = chunk_records[i : i + batch_size_push]
                # 计算当前进度
                current_batch_end = i + len(mini_batch)
                
                try:
                    # TODO 此处模拟推送数据到第三方系统
                     logger.info(f"[{glue_table}] 正在处理 Athena 第 {idx} 块: 进度 {current_batch_end}/{len(chunk_records)} 条 | 总计已推送: {total_pushed_count + len(mini_batch)}")
                    total_pushed_count += len(mini_batch)
                    
                    # 控制推送频率
                    if send_delay > 0:
                        time.sleep(send_delay)
                except Exception as e:
                    logger.error(f"表 {glue_table} 数据推送失败: {e}")
                    raise # 根据业务需求决定是跳过还是中断
            
            # 💡 重要:手动清理当前 chunk 占用的内存(可选,但推荐)
            del chunk_records
            del df_chunk

    elapsed = (datetime.now() - start_time).total_seconds()
    logger.info(f"作业全部完成!总计成功推送: {total_pushed_count} 条,总耗时 {elapsed:.2f} 秒")

数据处理函数(这部分代码根据你的业务来处理):

python 复制代码
import datetime
import decimal

def convert_dataframe_to_records(df: pd.DataFrame, table_type: str) -> List[dict]:
    """将 DataFrame 转换为字典列表,处理所有不可 JSON 序列化的类型"""
    records = df.to_dict(orient='records')
    for rec in records:
        rec['add_table'] = table_type
        for k, v in list(rec.items()):
            if pd.isna(v):
                rec[k] = None
            # 💡 增加对 datetime.date 和 datetime.datetime 的统一处理
            elif isinstance(v, (pd.Timestamp, datetime.datetime, datetime.date)):
                rec[k] = v.isoformat()
            # 💡 针对 Decimal 类型(如 gps_latitude)也建议处理一下,防止后续报错
            elif hasattr(v, 'to_eng_string'): 
                rec[k] = float(v)
    return records
相关推荐
zhangchaoxies2 小时前
Golang怎么用K8s Secret管理密钥_Golang如何从K8s Secret安全读取密码和证书【操作】
jvm·数据库·python
2402_854808372 小时前
JavaScript中模块化在游戏引擎开发中的资源调度作用
jvm·数据库·python
生信研究猿2 小时前
第2题-模型推理量化加速优化问题
python·算法
看海的四叔2 小时前
【Python】阿里云 DataWorks + ODPS + 钉钉联动实战:配合[特殊字符]全搞定
python·阿里云·api·odps·requests·openclaw
SeaTunnel3 小时前
深度解析 Apache SeaTunnel 核心引擎三大技术创新:高可靠异步持久化与 CDC 架构优化实战
大数据·数据库·架构·apache·seatunnel
2401_865439634 小时前
HTML函数在低温环境下启动慢吗_温度对硬件启动影响【方法】
jvm·数据库·python
NotFound4864 小时前
分享实战心得PostgreSQL 主从复制:告别单点故障,附主从切换与延迟监控命令
数据库·postgresql
minebmw710 小时前
Oracle 19.29 中 ORA-00600 [4193] 错误完全解析与恢复指南
数据库·oracle
m0_3776182310 小时前
Golang怎么连接MySQL数据库_Golang MySQL连接教程【总结】
jvm·数据库·python