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
相关推荐
风吹夏回6 分钟前
Python 全局异常处理:从“满屏 try-except”到优雅兜底
开发语言·python
小熊Coding32 分钟前
Python爬取当当网二手图书项目实战!
开发语言·爬虫·python·beautifulsoup·requests·二手图书
企服AI产品测评局32 分钟前
Agent适配信创环境实测:企业级自动化如何实现国产操作系统与数据库全兼容?
运维·数据库·人工智能·ai·chatgpt·自动化
秋936 分钟前
Java项目运行5天左右自动宕机:系统性定位与解决方案
java·开发语言·python
小江的记录本41 分钟前
【JVM虚拟机】垃圾回收GC:垃圾收集器:CMS:核心原理、回收流程、优缺点、废弃原因(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·spring·面试·maven
cfm_29141 小时前
Redis数据安全性解析
数据库·redis·缓存
DIY源码阁1 小时前
JavaSwing学生成绩管理系统 - MySQL版
java·数据库·mysql·eclipse
田里的水稻2 小时前
OE_ubuntu26.04与宿主机之间复制粘贴内容
人工智能·python·机器人
jiayong232 小时前
02 创建虚拟环境
python
NiceCloud喜云2 小时前
Claude Code Routines 实战:三种触发器跑通云端自动化编码
android·运维·数据库·人工智能·自动化·json·飞书