web-dev-qa-db-fra.com

Comment écrire dans Redshift des données résultant d'un cadre de données créé en Python?

J'ai un dataframe en Python. Puis-je écrire ces données dans Redshift en tant que nouvelle table? 

12
Sahil

Vous pouvez utiliser to_sql pour transférer des données dans une base de données Redshift. J'ai été capable de faire cela en utilisant une connexion à ma base de données via un moteur SQLAlchemy. Veillez simplement à définir index = False dans votre appel to_sql. La table sera créée si elle n'existe pas et vous pouvez spécifier si vous souhaitez appeler pour remplacer la table, l'ajouter à la table ou échouer si la table existe déjà.

from sqlalchemy import create_engine
import pandas as pd

conn = create_engine('postgresql://username:[email protected]:5439/yourdatabase')

df = pd.DataFrame([{'A': 'foo', 'B': 'green', 'C': 11},{'A':'bar', 'B':'blue', 'C': 20}])

df.to_sql('your_table', conn, index=False, if_exists='replace')

Notez que vous devrez peut-être pip install psycopg2 pour vous connecter à Redshift via SQLAlchemy.

Documentation to_sql

23
Andrew
import pandas_redshift as pr

pr.connect_to_redshift(dbname = <dbname>,
                        Host = <Host>,
                        port = <port>,
                        user = <user>,
                        password = <password>)

pr.connect_to_s3(aws_access_key_id = <aws_access_key_id>,
                aws_secret_access_key = <aws_secret_access_key>,
                bucket = <bucket>,
                subdirectory = <subdirectory>)

# Write the DataFrame to S3 and then to redshift
pr.pandas_to_redshift(data_frame = data_frame,
                        redshift_table_name = 'gawronski.nba_shots_log')

Détails: https://github.com/agawronski/pandas_redshift

4
AidanGawronski

En supposant que vous ayez accès à S3, cette approche devrait fonctionner:

Étape 1: écrivez le DataFrame en tant que csv sur S3 (j’utilise AWS SDK boto3 pour cela)
Étape 2: Vous connaissez les colonnes, les types de données et la clé/index de votre table Redshift à partir de votre DataFrame. Vous devriez donc pouvoir générer un script create table et le transmettre à Redshift pour créer une table vide.
Étape 3: envoyez une commande copy de votre environnement Python à Redshift pour copier les données de S3 dans la table vide créée à l’étape 2.

Fonctionne comme un charme à chaque fois.

Étape 4: Avant que les utilisateurs de votre stockage dans le nuage ne commencent à crier après avoir supprimé le CSV de S3

Si vous vous voyez faire cela plusieurs fois, le fait de regrouper les quatre étapes dans une fonction la maintient propre.

4
BigPanda

J'ai essayé d'utiliser des pandas df.to_sql() mais c'était extrêmement lent. Il me fallait bien plus de 10 minutes pour insérer 50 rangées. Voir this numéro ouvert (en date de l'écriture)

J'ai essayé d'utiliser odo de l'écosystème blaze (conformément aux recommandations de la discussion), mais je me suis heurté à une ProgrammingError que je n'ai pas cherché à explorer.

Enfin ce qui a fonctionné:

import psycopg2

# Fill in the blanks for the conn object
conn = psycopg2.connect(user = 'user',
                              password = 'password',
                              Host = 'Host',
                              dbname = 'db',
                              port = 666)
cursor = conn.cursor()

args_str = b','.join(cursor.mogrify("(%s,%s,...)", x) for x in Tuple(map(Tuple,np_data)))
cursor.execute("insert into table (a,b,...) VALUES "+args_str.decode("utf-8"))

cursor.close()
flexprobi_conn.commit()
flexprobi_conn.close()

Oui, tout simplement psycopg2. C'est pour un tableau numpy mais la conversion d'une df en une ndarray ne devrait pas être trop difficile. Cela m'a donné environ 3k lignes/minute.

Cependant, la solution la plus rapide, conformément aux recommandations d'autres membres de l'équipe, consiste à utiliser la commande COPY après avoir vidé le cadre de données en tant que TSV/CSV dans un cluster S3, puis effectué une copie. Vous devriez vous renseigner à ce sujet si vous copiez des jeux de données vraiment volumineux. (Je mettrai à jour ici si et quand je l'essayerai)

4
Gaurav

J'avais l'habitude de compter sur la fonction to_sql() de pandas, mais elle est trop lente. Je suis récemment passé à faire ce qui suit:

import pandas as pd
import s3fs # great module which allows you to read/write to s3 easily
import sqlalchemy

df = pd.DataFrame([{'A': 'foo', 'B': 'green', 'C': 11},{'A':'bar', 'B':'blue', 'C': 20}])

s3 = s3fs.S3FileSystem(anon=False)
filename = 'my_s3_bucket_name/file.csv'
with s3.open(filename, 'w') as f:
    df.to_csv(f, index=False, header=False)

con = sqlalchemy.create_engine('postgresql://username:[email protected]:5439/yourdatabase')
# make sure the schema for mytable exists

# if you need to delete the table but not the schema leave DELETE mytable
# if you want to only append, I think just removing the DELETE mytable would work

con.execute("""
    DELETE mytable;
    COPY mytable
    from 's3://%s'
    iam_role 'arn:aws:iam::xxxx:role/role_name'
    csv;""" % filename)

le rôle doit permettre l'accès redshift à S3 voir ici pour plus de détails

J'ai constaté que cela prend 4 secondes pour un fichier de 300 Ko (12 000 x 2 images) par rapport aux 8 minutes que je recevais avec la fonction to_sql() de pandas

0
erncyp

Aux fins de la conversation, Postgres = RedShiftVous avez deux options:

Option 1:

De Pandas: http://pandas.pydata.org/pandas-docs/stable/io.html#io-sql

Le module pandas.io.sql fournit une collection de wrappers de requête permettant à la fois de faciliter la récupération des données et de réduire la dépendance vis-à-vis d'une API spécifique à la base de données. L'abstraction de la base de données est fournie par SQLAlchemy si elle est installée. De plus, vous aurez besoin d'une bibliothèque de pilotes pour votre base de données. Psycopg2 pour PostgreSQL ou pymysql pour MySQL sont des exemples de tels pilotes.

Ecriture de DataFrames

En supposant que les données suivantes se trouvent dans des données DataFrame, nous pouvons les insérer dans la base de données à l'aide de to_sql ().

id  Date    Col_1   Col_2   Col_3
26  2012-10-18  X   25.7    True
42  2012-10-19  Y   -12.4   False
63  2012-10-20  Z   5.73    True

In [437]: data.to_sql('data', engine)

Avec certaines bases de données, l'écriture de grandes DataFrames peut entraîner des erreurs en raison du dépassement des limites de taille de paquet. Cela peut être évité en définissant le paramètre chunksize lors de l'appel de to_sql. Par exemple, ce qui suit écrit des données dans la base de données par lots de 1 000 lignes à la fois:

In [438]: data.to_sql('data_chunked', engine, chunksize=1000)

Option 2

Ou vous pouvez simplement faire votre propre Si vous avez un cadre de données appelé données, faites-le simplement en boucle en utilisant iterrows:

for row in data.iterrows():

ajoutez ensuite chaque ligne à votre base de données. J'utiliserais copie au lieu d'insertion pour chaque ligne, car ce sera beaucoup plus rapide.

http://initd.org/psycopg/docs/usage.html#using-copy-to-and-copy-from

0
Michael Robellard