Simpan dan ambil objek python acar ke / dari kepingan salju

Sep 20 2020

sesuai pertanyaan, saya mencoba menyimpan objek python yang dipetik ke kepingan salju, untuk mendapatkannya kembali di kemudian hari. Bantuan dalam hal ini akan sangat dihargai:

Definisi tabel kepingan salju:

CREATE OR REPLACE TABLE <db>.<schema>.TESTING_MEMORY (
    MODEL_DATETIME DATETIME,
    SCALARS VARIANT
;

Kode Python:

import numpy as np
import pandas as pd
import pickle
from datetime import datetime
import snowflake.connector
from snowflake.connector.pandas_tools import write_pandas
from sklearn.preprocessing import StandardScaler

def create_snowflake_connection():
    conn = snowflake.connector.connect(
        user='<username>',
        account='<account>',
        password = '<password>',
        warehouse='<wh>',
        database='<db>',
        role='<role>',
        schema='<schema>'
    )
    
    return conn

memory = {}

np.random.seed(78)
df = pd.DataFrame({
    'x1': np.random.normal(0, 2, 10000),
    'x2': np.random.normal(5, 3, 10000),
    'x3': np.random.normal(-5, 5, 10000)
})

scaler = StandardScaler()
scaler.fit(df)

scaled_df = scaler.transform(df)
scaled_df = pd.DataFrame(scaled_df, columns=['x1', 'x2', 'x3'])


memory['SCALARS'] = pickle.dumps(scaler)
    

ctx = create_snowflake_connection()


# Write to snowflake
db_dat = pd.DataFrame([list(memory.values())], columns=list(memory.keys()))
db_dat.insert(0, 'MODEL_DATETIME', datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"))
success, nchunks, nrows, _ = write_pandas(conn=ctx, df = db_dat, table_name = 'TESTING_MEMORY')
  
# retreive from snowflake
cur = ctx.cursor()
sql = """
        SELECT hex_encode(SCALARS)
        FROM <db>.<schema>.TESTING_MEMORY
        QUALIFY ROW_NUMBER() OVER (ORDER BY MODEL_DATETIME DESC) = 1
"""
cur.execute(sql) 
returned = cur.fetch_pandas_all() 


cur.close()
ctx.close()

Jawaban

1 SimonD Sep 21 2020 at 16:42

Sepertinya Anda mencoba memasukkan byteobjek python ke dalam Snowflake variantyang tidak akan berhasil untuk Anda.

Jawaban ini agak mirip dengan yang disarankan oleh jawaban lain di sini kecuali, daripada menggunakan varcharbidang untuk menyimpan biner berenkode base64, gunakan binarytipe sebagai gantinya. pengkodean base64 sekitar 30% lebih besar dari biner dari apa yang saya baca di suatu tempat.

Buat tabel dengan tipe data biner:

create or replace table testdb.public.test_table (obj binary);

Hex menyandikan objek yang diawetkan, menulisnya, membacanya kembali dan memanggil metode di atasnya:

import pickle
import snowflake.connector

# This is the object we're going to store in Snowflake as binary
class PickleMe:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def say_hello(self):
        print(f'Hi there, {self.first_name} {self.last_name}')

# Create the object and store it as hex in the 'hex_person' variable
person = PickleMe('John', 'Doe')
hex_person = pickle.dumps(person).hex()

with snowflake.connector.connect(
    user="username",
    password="password",
    account="snowflake_account_deets",
    warehouse="warehouse_name",
) as con:
    # Write pickled object into table as binary
    con.cursor().execute(f"INSERT INTO testdb.public.test_table values(to_binary('{hex_person}', 'HEX'))")

    # Now get the object back and put it into the 'obj' variable
    (obj,) = con.cursor().execute(f"select obj from testdb.public.test_table").fetchone()

    # Deserialise object and call method on it
    person_obj = pickle.loads(obj, encoding='HEX')
    person_obj.say_hello()

Output di atas adalah

Halo, John Doe

1 user1420372 Sep 21 2020 at 04:17

Mungkin ada cara yang lebih baik untuk melakukan ini (penafian: Saya baru mengenal Python), tetapi ini sepertinya berhasil dan didasarkan pada jawaban di sini: Bagaimana saya bisa mengawetkan objek python ke dalam file csv?

  1. Ubah definisi tabel sql

    CREATE OR REPLACE TABLE db.schema.TESTING_MEMORY (
    MODEL_DATETIME DATETIME,
    SCALARS VARCHAR
    );
    

2 Perubahan ke Kode Python - umum

import base64

3 Perubahan pada kode Python (tulis ke bagian kepingan salju di atas)

# Write to snowflake
db_dat = pd.DataFrame([list(memory.values())], columns=list(memory.keys()))
db_dat.insert(0, 'MODEL_DATETIME', datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"))

pickled_columns = ['SCALARS']
for column in pickled_columns:
    b64_bytes = base64.b64encode(db_dat[column].values[0])  
    db_dat[column] = b64_bytes.decode('utf8')
success, nchunks, nrows, _ = write_pandas(conn=ctx, df = db_dat, table_name = 'TESTING_MEMORY')
  1. Perubahan pada kode Python - ambil dari kepingan salju

    cur = ctx.cursor() 
    
    sql = """
         SELECT *
         FROM db.schema.TESTING_MEMORY
         QUALIFY ROW_NUMBER() OVER (ORDER BY MODEL_DATETIME DESC) = 1
    """
    
    cur.execute(sql) 
    returned = cur.fetch_pandas_all() 
    
    for column in pickled_columns:
        returned[column] =  base64.b64decode(returned[column].values[0])
    
    
    new_dict = returned.to_dict('list')
    for key,val in new_dict.items():
        new_dict[key] = val[0]