文件 AWS 開發套件範例 GitHub 儲存庫中有更多可用的 AWS SDK 範例
本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用適用於 Python 的 SDK (Boto3) 的 Amazon Redshift 範例
下列程式碼範例示範如何使用 AWS SDK for Python (Boto3) 搭配 Amazon Redshift 執行動作和實作常見案例。
基本概念是程式碼範例,這些範例說明如何在服務內執行基本操作。
Actions 是大型程式的程式碼摘錄,必須在內容中執行。雖然動作會告訴您如何呼叫個別服務函數,但您可以在其相關情境中查看內容中的動作。
每個範例都包含完整原始程式碼的連結,您可以在其中找到如何在內容中設定和執行程式碼的指示。
開始使用
下列程式碼範例示範如何開始使用 Amazon Redshift。
- SDK for Python (Boto3)
-
注意
GitHub 上提供更多範例。尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫
中設定和執行。 import boto3 def hello_redshift(redshift_client): """ Use the AWS SDK for Python (Boto3) to create an Amazon Redshift client and list the clusters in your account. This list might be empty if you haven't created any clusters. This example uses the default settings specified in your shared credentials and config files. :param redshift_client: A Boto3 Redshift Client object. """ print("Hello, Redshift! Let's list your clusters:") paginator = redshift_client.get_paginator("describe_clusters") clusters = [] for page in paginator.paginate(): clusters.extend(page["Clusters"]) print(f"{len(clusters)} cluster(s) were found.") for cluster in clusters: print(f" {cluster['ClusterIdentifier']}") if __name__ == "__main__": hello_redshift(boto3.client("redshift"))
-
如需 API 詳細資訊,請參閱《適用於 AWS Python (Boto3) 的 SDK API 參考》中的 DescribeClusters。
-
基本概念
以下程式碼範例顯示做法:
建立 Redshift 叢集。
列出叢集中的資料庫。
建立名為電影的資料表。
填入電影資料表。
依年份查詢電影資料表。
修改 Redshift 叢集。
刪除 Amazon Redshift 叢集。
- SDK for Python (Boto3)
-
注意
GitHub 上提供更多範例。尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫
中設定和執行。 class RedshiftScenario: """Runs an interactive scenario that shows how to get started with Redshift.""" def __init__(self, redshift_wrapper, redshift_data_wrapper): self.redshift_wrapper = redshift_wrapper self.redshift_data_wrapper = redshift_data_wrapper def redhift_scenario(self, json_file_path): database_name = "dev" print(DASHES) print("Welcome to the Amazon Redshift SDK Getting Started example.") print( """ This Python program demonstrates how to interact with Amazon Redshift using the AWS SDK for Python (Boto3). Amazon Redshift is a fully managed, petabyte-scale data warehouse service hosted in the cloud. The program's primary functionalities include cluster creation, verification of cluster readiness, listing databases, table creation, populating data within the table, and executing SQL statements. It also demonstrates querying data from the Movies table. Upon completion, all AWS resources are cleaned up. """ ) if not os.path.isfile(json_file_path): logging.error(f"The file {json_file_path} does not exist.") return print("Let's get started...") user_name = q.ask("Please enter your user name (default is awsuser):") user_name = user_name if user_name else "awsuser" print(DASHES) user_password = q.ask( "Please enter your user password (default is AwsUser1000):" ) user_password = user_password if user_password else "AwsUser1000" print(DASHES) print( """A Redshift cluster refers to the collection of computing resources and storage that work together to process and analyze large volumes of data.""" ) cluster_id = q.ask( "Enter a cluster identifier value (default is redshift-cluster-movies): " ) cluster_id = cluster_id if cluster_id else "redshift-cluster-movies" self.redshift_wrapper.create_cluster( cluster_id, "ra3.4xlarge", user_name, user_password, True, 2 ) print(DASHES) print(f"Wait until {cluster_id} is available. This may take a few minutes...") q.ask("Press Enter to continue...") self.wait_cluster_available(cluster_id) print(DASHES) print( f""" When you created {cluster_id}, the dev database is created by default and used in this scenario. To create a custom database, you need to have a CREATEDB privilege. For more information, see the documentation here: https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_DATABASE.html. """ ) q.ask("Press Enter to continue...") print(DASHES) print(DASHES) print(f"List databases in {cluster_id}") q.ask("Press Enter to continue...") databases = self.redshift_data_wrapper.list_databases( cluster_id, database_name, user_name ) print(f"The cluster contains {len(databases)} database(s).") for database in databases: print(f" Database: {database}") print(DASHES) print(DASHES) print("Now you will create a table named Movies.") q.ask("Press Enter to continue...") self.create_table(cluster_id, database_name, user_name) print(DASHES) print("Populate the Movies table using the Movies.json file.") print( "Specify the number of records you would like to add to the Movies Table." ) print("Please enter a value between 50 and 200.") while True: try: num_records = int(q.ask("Enter a value: ", q.is_int)) if 50 <= num_records <= 200: break else: print("Invalid input. Please enter a value between 50 and 200.") except ValueError: print("Invalid input. Please enter a value between 50 and 200.") self.populate_table( cluster_id, database_name, user_name, json_file_path, num_records ) print(DASHES) print("Query the Movies table by year. Enter a value between 2012-2014.") while True: movie_year = int(q.ask("Enter a year: ", q.is_int)) if 2012 <= movie_year <= 2014: break else: print("Invalid input. Please enter a valid year between 2012 and 2014.") # Function to query database sql_id = self.query_movies_by_year( database_name, user_name, movie_year, cluster_id ) print(f"The identifier of the statement is {sql_id}") print("Checking statement status...") self.wait_statement_finished(sql_id) result = self.redshift_data_wrapper.get_statement_result(sql_id) self.display_movies(result) print(DASHES) print(DASHES) print("Now you will modify the Redshift cluster.") q.ask("Press Enter to continue...") preferred_maintenance_window = "wed:07:30-wed:08:00" self.redshift_wrapper.modify_cluster(cluster_id, preferred_maintenance_window) print(DASHES) print(DASHES) delete = q.ask("Do you want to delete the cluster? (y/n) ", q.is_yesno) if delete: print(f"You selected to delete {cluster_id}") q.ask("Press Enter to continue...") self.redshift_wrapper.delete_cluster(cluster_id) else: print(f"Cluster {cluster_id}cluster_id was not deleted") print(DASHES) print("This concludes the Amazon Redshift SDK Getting Started scenario.") print(DASHES) def create_table(self, cluster_id, database, username): self.redshift_data_wrapper.execute_statement( cluster_identifier=cluster_id, database_name=database, user_name=username, sql="CREATE TABLE Movies (statement_id INT PRIMARY KEY, title VARCHAR(100), year INT)", ) print("Table created: Movies") def populate_table(self, cluster_id, database, username, file_name, number): with open(file_name) as f: data = json.load(f) i = 0 for record in data: if i == number: break statement_id = i title = record["title"] year = record["year"] i = i + 1 parameters = [ {"name": "statement_id", "value": str(statement_id)}, {"name": "title", "value": title}, {"name": "year", "value": str(year)}, ] self.redshift_data_wrapper.execute_statement( cluster_identifier=cluster_id, database_name=database, user_name=username, sql="INSERT INTO Movies VALUES(:statement_id, :title, :year)", parameter_list=parameters, ) print(f"{i} records inserted into Movies table") def wait_cluster_available(self, cluster_id): """ Waits for a cluster to be available. :param cluster_id: The cluster identifier. Note: The cluster_available waiter can also be used. It is not used in this case to allow an elapsed time message. """ cluster_ready = False start_time = time.time() while not cluster_ready: time.sleep(30) cluster = self.redshift_wrapper.describe_clusters(cluster_id) status = cluster[0]["ClusterStatus"] if status == "available": cluster_ready = True elif status != "creating": raise Exception( f"Cluster {cluster_id} creation failed with status {status}." ) elapsed_seconds = int(round(time.time() - start_time)) minutes = int(elapsed_seconds // 60) seconds = int(elapsed_seconds % 60) print(f"Elapsed Time: {minutes}:{seconds:02d} - status {status}...") if minutes > 30: raise Exception( f"Cluster {cluster_id} is not available after 30 minutes." ) def query_movies_by_year(self, database, username, year, cluster_id): sql = "SELECT * FROM Movies WHERE year = :year" params = [{"name": "year", "value": str(year)}] response = self.redshift_data_wrapper.execute_statement( cluster_identifier=cluster_id, database_name=database, user_name=username, sql=sql, parameter_list=params, ) return response["Id"] @staticmethod def display_movies(response): metadata = response["ColumnMetadata"] records = response["Records"] title_column_index = None for i in range(len(metadata)): if metadata[i]["name"] == "title": title_column_index = i break if title_column_index is None: print("No title column found.") return print(f"Found {len(records)} movie(s).") for record in records: print(f" {record[title_column_index]['stringValue']}") def wait_statement_finished(self, sql_id): while True: time.sleep(1) response = self.redshift_data_wrapper.describe_statement(sql_id) status = response["Status"] print(f"Statement status is {status}.") if status == "FAILED": print(f"The query failed because {response['Error']}. Ending program") raise Exception("The Query Failed. Ending program") elif status == "FINISHED": break
顯示案例實作的主要函數。
def main(): redshift_client = boto3.client("redshift") redshift_data_client = boto3.client("redshift-data") redshift_wrapper = RedshiftWrapper(redshift_client) redshift_data_wrapper = RedshiftDataWrapper(redshift_data_client) redshift_scenario = RedshiftScenario(redshift_wrapper, redshift_data_wrapper) redshift_scenario.redhift_scenario( f"{os.path.dirname(__file__)}/../../../resources/sample_files/movies.json" )
案例中使用的包裝函式。
def create_cluster( self, cluster_identifier, node_type, master_username, master_user_password, publicly_accessible, number_of_nodes, ): """ Creates a cluster. :param cluster_identifier: The name of the cluster. :param node_type: The type of node in the cluster. :param master_username: The master username. :param master_user_password: The master user password. :param publicly_accessible: Whether the cluster is publicly accessible. :param number_of_nodes: The number of nodes in the cluster. :return: The cluster. """ try: cluster = self.client.create_cluster( ClusterIdentifier=cluster_identifier, NodeType=node_type, MasterUsername=master_username, MasterUserPassword=master_user_password, PubliclyAccessible=publicly_accessible, NumberOfNodes=number_of_nodes, ) return cluster except ClientError as err: logging.error( "Couldn't create a cluster. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def describe_clusters(self, cluster_identifier): """ Describes a cluster. :param cluster_identifier: The cluster identifier. :return: A list of clusters. """ try: kwargs = {} if cluster_identifier: kwargs["ClusterIdentifier"] = cluster_identifier paginator = self.client.get_paginator("describe_clusters") clusters = [] for page in paginator.paginate(**kwargs): clusters.extend(page["Clusters"]) return clusters except ClientError as err: logging.error( "Couldn't describe a cluster. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def execute_statement( self, cluster_identifier, database_name, user_name, sql, parameter_list=None ): """ Executes a SQL statement. :param cluster_identifier: The cluster identifier. :param database_name: The database name. :param user_name: The user's name. :param sql: The SQL statement. :param parameter_list: The optional SQL statement parameters. :return: The SQL statement result. """ try: kwargs = { "ClusterIdentifier": cluster_identifier, "Database": database_name, "DbUser": user_name, "Sql": sql, } if parameter_list: kwargs["Parameters"] = parameter_list response = self.client.execute_statement(**kwargs) return response except ClientError as err: logging.error( "Couldn't execute statement. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def describe_statement(self, statement_id): """ Describes a SQL statement. :param statement_id: The SQL statement identifier. :return: The SQL statement result. """ try: response = self.client.describe_statement(Id=statement_id) return response except ClientError as err: logging.error( "Couldn't describe statement. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def get_statement_result(self, statement_id): """ Gets the result of a SQL statement. :param statement_id: The SQL statement identifier. :return: The SQL statement result. """ try: result = { "Records": [], } paginator = self.client.get_paginator("get_statement_result") for page in paginator.paginate(Id=statement_id): if "ColumnMetadata" not in result: result["ColumnMetadata"] = page["ColumnMetadata"] result["Records"].extend(page["Records"]) return result except ClientError as err: logging.error( "Couldn't get statement result. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def modify_cluster(self, cluster_identifier, preferred_maintenance_window): """ Modifies a cluster. :param cluster_identifier: The cluster identifier. :param preferred_maintenance_window: The preferred maintenance window. """ try: self.client.modify_cluster( ClusterIdentifier=cluster_identifier, PreferredMaintenanceWindow=preferred_maintenance_window, ) except ClientError as err: logging.error( "Couldn't modify a cluster. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def list_databases(self, cluster_identifier, database_name, database_user): """ Lists databases in a cluster. :param cluster_identifier: The cluster identifier. :param database_name: The database name. :param database_user: The database user. :return: The list of databases. """ try: paginator = self.client.get_paginator("list_databases") databases = [] for page in paginator.paginate( ClusterIdentifier=cluster_identifier, Database=database_name, DbUser=database_user, ): databases.extend(page["Databases"]) return databases except ClientError as err: logging.error( "Couldn't list databases. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def delete_cluster(self, cluster_identifier): """ Deletes a cluster. :param cluster_identifier: The cluster identifier. """ try: self.client.delete_cluster( ClusterIdentifier=cluster_identifier, SkipFinalClusterSnapshot=True ) except ClientError as err: logging.error( "Couldn't delete a cluster. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise
-
如需 API 的詳細資訊,請參閱 AWS SDK for Python (Boto3) API Reference 中的下列主題。
-
動作
下列程式碼範例示範如何使用 CreateCluster
。
- SDK for Python (Boto3)
-
注意
GitHub 上提供更多範例。尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫
中設定和執行。 class RedshiftWrapper: """ Encapsulates Amazon Redshift cluster operations. """ def __init__(self, redshift_client): """ :param redshift_client: A Boto3 Redshift client. """ self.client = redshift_client def create_cluster( self, cluster_identifier, node_type, master_username, master_user_password, publicly_accessible, number_of_nodes, ): """ Creates a cluster. :param cluster_identifier: The name of the cluster. :param node_type: The type of node in the cluster. :param master_username: The master username. :param master_user_password: The master user password. :param publicly_accessible: Whether the cluster is publicly accessible. :param number_of_nodes: The number of nodes in the cluster. :return: The cluster. """ try: cluster = self.client.create_cluster( ClusterIdentifier=cluster_identifier, NodeType=node_type, MasterUsername=master_username, MasterUserPassword=master_user_password, PubliclyAccessible=publicly_accessible, NumberOfNodes=number_of_nodes, ) return cluster except ClientError as err: logging.error( "Couldn't create a cluster. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise
下列程式碼會執行個體化 RedshiftWrapper 物件。
client = boto3.client("redshift") redhift_wrapper = RedshiftWrapper(client)
-
如需 API 詳細資訊,請參閱《適用於 AWS Python (Boto3) 的 SDK API 參考》中的 CreateCluster。
-
下列程式碼範例示範如何使用 DeleteCluster
。
- SDK for Python (Boto3)
-
注意
GitHub 上提供更多範例。尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫
中設定和執行。 class RedshiftWrapper: """ Encapsulates Amazon Redshift cluster operations. """ def __init__(self, redshift_client): """ :param redshift_client: A Boto3 Redshift client. """ self.client = redshift_client def delete_cluster(self, cluster_identifier): """ Deletes a cluster. :param cluster_identifier: The cluster identifier. """ try: self.client.delete_cluster( ClusterIdentifier=cluster_identifier, SkipFinalClusterSnapshot=True ) except ClientError as err: logging.error( "Couldn't delete a cluster. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise
下列程式碼會執行個體化 RedshiftWrapper 物件。
client = boto3.client("redshift") redhift_wrapper = RedshiftWrapper(client)
-
如需 API 詳細資訊,請參閱《適用於 AWS Python (Boto3) 的 SDK API 參考》中的 DeleteCluster。
-
下列程式碼範例示範如何使用 DescribeClusters
。
- SDK for Python (Boto3)
-
注意
GitHub 上提供更多範例。尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫
中設定和執行。 class RedshiftWrapper: """ Encapsulates Amazon Redshift cluster operations. """ def __init__(self, redshift_client): """ :param redshift_client: A Boto3 Redshift client. """ self.client = redshift_client def describe_clusters(self, cluster_identifier): """ Describes a cluster. :param cluster_identifier: The cluster identifier. :return: A list of clusters. """ try: kwargs = {} if cluster_identifier: kwargs["ClusterIdentifier"] = cluster_identifier paginator = self.client.get_paginator("describe_clusters") clusters = [] for page in paginator.paginate(**kwargs): clusters.extend(page["Clusters"]) return clusters except ClientError as err: logging.error( "Couldn't describe a cluster. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise
下列程式碼會執行個體化 RedshiftWrapper 物件。
client = boto3.client("redshift") redhift_wrapper = RedshiftWrapper(client)
-
如需 API 詳細資訊,請參閱《適用於 AWS Python (Boto3) 的 SDK API 參考》中的 DescribeClusters。
-
下列程式碼範例示範如何使用 DescribeStatement
。
- SDK for Python (Boto3)
-
注意
GitHub 上提供更多範例。尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫
中設定和執行。 class RedshiftDataWrapper: """Encapsulates Amazon Redshift data.""" def __init__(self, client): """ :param client: A Boto3 RedshiftDataWrapper client. """ self.client = client def describe_statement(self, statement_id): """ Describes a SQL statement. :param statement_id: The SQL statement identifier. :return: The SQL statement result. """ try: response = self.client.describe_statement(Id=statement_id) return response except ClientError as err: logging.error( "Couldn't describe statement. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise
下列程式碼會執行個體化 RedshiftDataWrapper 物件。
client = boto3.client("redshift-data") redshift_data_wrapper = RedshiftDataWrapper(client)
-
如需 API 詳細資訊,請參閱《適用於 AWS Python (Boto3) 的 SDK API 參考》中的 DescribeStatement。
-
下列程式碼範例示範如何使用 GetStatementResult
。
- SDK for Python (Boto3)
-
注意
GitHub 上提供更多範例。尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫
中設定和執行。 class RedshiftDataWrapper: """Encapsulates Amazon Redshift data.""" def __init__(self, client): """ :param client: A Boto3 RedshiftDataWrapper client. """ self.client = client def get_statement_result(self, statement_id): """ Gets the result of a SQL statement. :param statement_id: The SQL statement identifier. :return: The SQL statement result. """ try: result = { "Records": [], } paginator = self.client.get_paginator("get_statement_result") for page in paginator.paginate(Id=statement_id): if "ColumnMetadata" not in result: result["ColumnMetadata"] = page["ColumnMetadata"] result["Records"].extend(page["Records"]) return result except ClientError as err: logging.error( "Couldn't get statement result. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise
下列程式碼會執行個體化 RedshiftDataWrapper 物件。
client = boto3.client("redshift-data") redshift_data_wrapper = RedshiftDataWrapper(client)
-
如需 API 詳細資訊,請參閱《適用於 AWS Python (Boto3) 的 SDK API 參考》中的 GetStatementResult。
-
下列程式碼範例示範如何使用 ModifyCluster
。
- SDK for Python (Boto3)
-
注意
GitHub 上提供更多範例。尋找完整範例,並了解如何在 AWS 程式碼範例儲存庫
中設定和執行。 class RedshiftWrapper: """ Encapsulates Amazon Redshift cluster operations. """ def __init__(self, redshift_client): """ :param redshift_client: A Boto3 Redshift client. """ self.client = redshift_client def modify_cluster(self, cluster_identifier, preferred_maintenance_window): """ Modifies a cluster. :param cluster_identifier: The cluster identifier. :param preferred_maintenance_window: The preferred maintenance window. """ try: self.client.modify_cluster( ClusterIdentifier=cluster_identifier, PreferredMaintenanceWindow=preferred_maintenance_window, ) except ClientError as err: logging.error( "Couldn't modify a cluster. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise
下列程式碼會執行個體化 RedshiftWrapper 物件。
client = boto3.client("redshift") redhift_wrapper = RedshiftWrapper(client)
-
如需 API 詳細資訊,請參閱《適用於 AWS Python (Boto3) 的 SDK API 參考》中的 ModifyCluster。
-