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
相关推荐
明月_清风4 分钟前
DuckDB:一个正在改变数据分析方式的数据库
数据库·数据分析·ai编程
学也学不废4 分钟前
论文阅读:Advancing Semantic Textual Similarity Modeling
python
风早爽太20 分钟前
Python 开发笔记:配置生产环境中 Celery Worker 的独立进程启动方式
python·fastapi
打工仔折腾 AI34 分钟前
飞牛OS上用Docker Compose部署ExerciseDiary运动记录并配置远程访问
运维·人工智能·后端·python·docker·容器·ai agent 实战
CoLiuRs42 分钟前
电商价格是怎样算出来的
数据库·redis·缓存
小蒜学长1 小时前
基于Python的动物救助站管理系统的设计与实现(代码+数据库+LW)
数据库·后端·python·django·动物救助
小小张说故事1 小时前
Python 中 __new__ 和 __init__ 到底谁才是构造函数?一文讲透区别与 5 个坑
后端·python
言乐61 小时前
Python实现关税自动计算模型
开发语言·python·django·virtualenv·pygame
伞伞悦读1 小时前
从零打通 Hermes Agent:Windows + WSL2 + Clash 全链路安装、认证与首次实战
python·语言模型
happylifetree1 小时前
Python17:核心语法-数据存储与运算-输入与输出
python