はじめに
Python3上でSQLを書き、awswranglerを使用してデータを取得する方法を紹介します。
タイトルの「高速に取得する v2」ですが、以前書いた記事
【AWS Athena】クエリ実行結果のデータを高速にPandas.DataFrameとして取得する
の続編的な形になるため、そのように書いています。
Python3上でSQLを書いてデータを取得するときは、pyathenaよりawswranglerのほうが圧倒的に早いよ ということを書きたいというのが趣旨です。
環境・使用ライブラリ
2種類あります
それぞれ箇条書きのリンク先は実際に計測したcolaboratoryとなっています
colaboratory (Python 3.7.12)
-
- pyathena==2.3.0
- pandas==1.3.4
-
- awswrangler==2.12.1
- pandas==1.3.4
- boto3==1.20.13
結果
500万行10列のデータを50.8秒(ctas_approach=True)で展開することができました
ctas_approach=Falseの場合でも1分26秒でした
pyathenaライブラリを使用した場合、24分38秒もかかってしまいました
データ取得方法
環境・使用ライブラリにも実際のcolaboratoryリンクを貼っていますが、awswranglerでのデータ取得方法をこちらにも記載します
boto3.SessionにAWSの秘密鍵やリージョン情報を記載して、awswranglerを動かします
import awswrangler as wr
import boto3
import pandas as pd
# boto3.Sessionへ秘密鍵とリージョンを記載する
session = boto3.Session(
aws_access_key_id=access,
aws_secret_access_key=secret,
region_name = 'ap-northeast-1'
)
# データを取得する(ctas_approach = True)
df = wr.athena.read_sql_query("SELECT * FROM big_parquet_data", database="main_data", boto3_session=session)
# データを取得する(ctas_approach = False)
df = wr.athena.read_sql_query("SELECT * FROM big_parquet_data", database="main_data", boto3_session=session, ctas_approach=False)
# データを取得する s3出力先やワークグループがある場合
df = wr.athena.read_sql_query(
"SELECT * FROM big_parquet_data", database="main_data",
boto3_session=session, workgroup='workgroup', s3_output='s3://*******'
)
read_sql_queryのその他引数についてはこちらに記載されています
https://aws-data-wrangler.readthedocs.io/en/stable/stubs/awswrangler.athena.read_sql_query.html
ctas_approachについて
Trueにすると、s3からparquetとして読み込むため大規模なデータのダウンロードスピードが速くなります。
ただし、AWS Glueでテーブルの作成/削除権限が別途必要です。その分料金も別で掛かります。
Falseにすると、単一のcsvから読み込むためTrueの時よりは大規模なデータのダウンロードスピードが遅くなります。(それでも速い)
AWS Glueの権限は必要ありません。
Windows環境での文字化け対処
文字エンコードの関係で、ctas_approach=False
の状態でcsvを読み込むと、文字化けしたり
'cp932' codec can't decode byte 0x86 in position 29: illegal multibyte sequence
等と、エラーが出ることがあります。
pyathenaと違い、データを取得する際にpandasを使用しないので、エンコード方法を指定することができません。
そこで、実行前に以下のコードを実行すると、WindowsがデフォルトでUTF-8エンコードとなり、文字化けやエラーを回避することができます。
import os
if os.name == 'nt':
import _locale
_locale._getdefaultlocale_backup = _locale._getdefaultlocale
_locale._getdefaultlocale = (lambda *args: (_locale._getdefaultlocale_backup()[0], 'UTF-8'))
対処例
日本語の入ったデータを作って、比較してみます
CREATE TABLE main_data.name_list AS
SELECT * FROM (
VALUES
(1, '田中'),
(2, '佐藤'),
(3, '大森')
) AS t (id, name)
display(wr.athena.read_sql_query("SELECT * FROM name_list", database="main_data", boto3_session=session, ctas_approach=False))
id | name | |
---|---|---|
0 | 1 | 逕ー荳ュ |
1 | 2 | 菴占陸 |
2 | 3 | 螟ァ譽ョ |
import os
if os.name == 'nt':
import _locale
_locale._getdefaultlocale_backup = _locale._getdefaultlocale
_locale._getdefaultlocale = (lambda *args: (_locale._getdefaultlocale_backup()[0], 'UTF-8'))
display(wr.athena.read_sql_query("SELECT * FROM name_list", database="main_data", boto3_session=session, ctas_approach=False))
id | name | |
---|---|---|
0 | 1 | 田中 |
1 | 2 | 佐藤 |
2 | 3 | 大森 |
文字化けを解消することができました!
最後に
大規模データのダウンロードもこれで快適です!
更に改善点などあれば教えていただけると助かりますm(__)m