Utiliser SQL pour générer automatiquement des descriptions d’objets

La fonctionnalité Descriptions d’objets alimentées par Cortex vous permet d’utiliser la fonction Snowflake Cortex COMPLETE pour générer automatiquement des descriptions pour les tables, les vues et les colonnes. Cette fonctionnalité exploite les grands modèles de langage hébergés par Snowflake (LLMs) pour évaluer les métadonnées des objets et, le cas échéant, des échantillons de données afin de générer une description.

Cette rubrique décrit comment utiliser une procédure stockée pour générer des descriptions par programmation. Pour plus d’informations sur l’utilisation de l’Snowsight pour générer les descriptions, consultez Générer des descriptions avec Snowflake Cortex.

Génération d’une description

La procédure stockée AI_GENERATE_TABLE_DESC génère automatiquement une description pour une table et une vue. Elle peut également générer des descriptions pour les colonnes de cette table ou de cette vue.

La procédure stockée AI_GENERATE_TABLE_DESC accepte deux arguments :

  • Le nom de la table ou de la vue pour laquelle vous souhaitez générer une description.

  • Un objet de configuration facultatif qui vous permet d’effectuer les opérations suivantes :

    • Générer des descriptions pour les colonnes de la table ou de la vue spécifiée

    • Utiliser des échantillons de données provenant de la table ou de la vue pour améliorer potentiellement la précision des descriptions de colonnes

Exemple : Générer une description de table
CALL AI_GENERATE_TABLE_DESC( 'my_table');
Copy
Exemple : Générer des descriptions de tables et de colonnes sans utiliser d’échantillons de données
CALL AI_GENERATE_TABLE_DESC(
  'mydb.sch1.hr_data',
  {
    'describe_columns': true,
    'use_table_data': false
  });
Copy
Exemple : Générer des descriptions de vues et de colonnes en utilisant des échantillons de données pour améliorer la précision
CALL AI_GENERATE_TABLE_DESC(
  'mydb.sch1.v1',
  {
    'describe_columns': true,
    'use_table_data': true
  });
Copy

Pour connaître la syntaxe complète de la procédure stockée, consultez AI_GENERATE_TABLE_DESC.

Utilisation de la réponse

La procédure stockée AI_GENERATE_TABLE_DESC renvoie un objet JSON qui contient les descriptions générées ainsi que des informations générales sur la table et les colonnes. Dans cet objet, le champ description contient la description générée.

Supposons que vous ayez créé la table suivante :

CREATE OR REPLACE TABLE mydb.sch1.hr_data (fname VARCHAR, age INTEGER);

INSERT INTO hr_data (fname, age)
    VALUES
        ('Thomas',    44),
        ('Katherine', 29),
        ('Lisa',      29);
Copy

Compte tenu de cette table, ce qui suit est un exemple d’objetJSON renvoyé par AI_GENERATE_TABLE_DESC :

{
  "COLUMNS": [
    {
      "database_name": "mydb",
      "description": "The first name of the employee.",
      "name": "FNAME",
      "schema_name": "sch1",
      "table_name": "hr_data"
    }
    {
      "database_name": "mydb",
      "description": "A column holding data of type DecimalType representing age values.",
      "name": "AGE",
      "schema_name": "sch1",
      "table_name": "hr_data"
    },
  ],
  "TABLE": [
    {
      "database_name": "mydb",
      "description": " The table contains records of employee data, specifically demographic information. Each record includes an employee's age and name.",
      "name": "hr_data",
      "schema_name": "sch1"
    }
  ]
}

Pour plus d’informations sur chaque champ JSON, consultez Renvoie.

Définir les descriptions générées comme commentaires

Pour définir une description générée comme commentaire sur une table, une vue ou une colonne, vous devez exécuter manuellement une instruction SQL qui inclut le paramètre SET COMMENT. Par exemple, pour enregistrer une description générée pour une table t1, exécutez ALTER TABLE t1 SET COMMENT = 'ai generated description';.

Vous pouvez écrire du code personnalisé pour générer et enregistrer automatiquement des descriptions. Pour des exemples de procédures stockées utilisées à cette fin, consultez Exemples.

Exigences en matière de contrôle d’accès

Les utilisateurs doivent disposer des privilèges et des rôles suivants pour appeler la procédure stockée AI_GENERATE_TABLE_DESC :

  • Privilège SELECT sur la table ou la vue

  • Rôle de base de données SNOWFLAKE.CORTEX_USER

Disponibilité de la fonctionnalité

Votre région doit prendre en charge les LLM utilisés par Snowflake Cortex (comme Mistral-7b et Llama 3.1-8b) pour générer les descriptions. Vérifiez la disponibilité de la fonction COMPLETE. Si la fonction COMPLETE n’est pas prise en charge dans votre région, vous devez activer l’inférence interrégionale pour utiliser cette fonctionnalité.

Chargement des échantillons de données

Lorsque vous générez une description pour une colonne, vous pouvez vous baser uniquement sur les métadonnées, ou vous pouvez choisir d’utiliser des échantillons de données pour améliorer la description alimentée par le Snowflake Cortex. Les données d’échantillon font référence aux données d’une colonne particulière qui sont évaluées lorsque vous utilisez Snowflake Cortex pour générer des descriptions. Si vous choisissez d’utiliser des données d’échantillon, Snowflake utilise une partie des données d’échantillon pour générer la description, ce qui permet d’obtenir des descriptions plus précises. Les données d’échantillon ne sont pas stockées par Snowflake en tant que données d’utilisation.

Considérations relatives aux clients

La production de descriptions entraîne les coûts suivants :

  • Crédits consommés par l’entrepôt en service.

  • Frais de crédit pour l’utilisation de Snowflake Cortex avec des LLMs plus petits comme Mistral-7b et Llama 3.1-8b. Ces frais sont facturés sous la forme de Services AI, ce qui inclut toutes les utilisations de Snowflake Cortex.

Limitations

Vous ne pouvez pas générer de descriptions de colonnes pour des objets contenant plus de 1 000 colonnes.

Exemples

Exemple : Générer des descriptions et les définir comme commentaires

Étape 1 : Créer une procédure stockée

La procédure stockée suivante effectue les actions suivantes :

  • Génère automatiquement des descriptions pour toutes les tables (et leurs colonnes) dans un schéma.

  • Définit ces descriptions comme commentaires sur les tables et les colonnes.

CREATE OR REPLACE PROCEDURE DESCRIBE_TABLES_SET_COMMENT (database_name STRING, schema_name STRING,
  set_table_comment BOOLEAN,
  set_column_comment BOOLEAN)
  RETURNS STRING
  LANGUAGE PYTHON
  RUNTIME_VERSION = '3.10'
  PACKAGES=('snowflake-snowpark-python','joblib')
  HANDLER = 'main'
AS
$$
import json
from joblib import Parallel, delayed
import multiprocessing

def generate_descr(session, database_name, schema_name, table, set_table_comment, set_column_comment):
  table_name =  table['TABLE_NAME']
  async_job = session.sql(f"CALL AI_GENERATE_TABLE_DESC( '{database_name}.{schema_name}.{table_name}',{{'describe_columns': true, 'use_table_data': true}})").collect_nowait()
  result = async_job.result()
  output = json.loads(result[0][0])
  columns_ret = output["COLUMNS"]
  table_ret = output["TABLE"][0]

  table_description = table_ret["description"]
  table_name = table_ret["name"]
  database_name = table_ret["database_name"]
  schema_name = table_ret["schema_name"]

  if (set_table_comment):
      table_description = table_description.replace("'", "\\'")
      session.sql(f"""ALTER TABLE {database_name}.{schema_name}.{table_name} SET COMMENT = '{table_description}'""").collect()

  for column in columns_ret:
      column_description = column["description"];
      column_name = column["name"];
      if not column_name.isupper():
        column_name = '"' + column_name + '"'

      if (set_column_comment):
          column_description = column_description.replace("'", "\\'")
          session.sql(f"""ALTER TABLE  {database_name}.{schema_name}.{table_name} MODIFY COLUMN {column_name}  COMMENT '{column_description}'""").collect()

  return 'Success';

def main(session, database_name, schema_name, set_table_comment, set_column_comment):

    schema_name = schema_name.upper()
    database_name = database_name.upper()
    tablenames = session.sql(f"""SELECT table_name
                      FROM {database_name}.information_schema.tables
                      WHERE table_schema = '{schema_name}'
                      AND table_type = 'BASE TABLE'""").collect()
    try:
        Parallel(n_jobs=multiprocessing.cpu_count(), backend="threading")(
                delayed(generate_descr)(
                    session,
                    database_name,
                    schema_name,
                    table,
                    set_table_comment,
                    set_column_comment,
                ) for table in tablenames
            )
        return 'Success'
    except Exception as e:
        # Catch and return the error message
        return f"An error occurred: {str(e)}"
$$;
Copy

Étape 2 : Appeler la procédure stockée

En supposant que votre schéma est nommé my_db.sch1, appelez la procédure stockée comme suit pour générer des descriptions pour les tables et les colonnes :

CALL describe_tables_set_comment('my_db', 'sch1', true, true);
Copy

Vous pouvez exécuter une commande DESC TABLE pour vérifier que les descriptions générées ont été définies comme commentaires sur une table.

Exemple : Générer des descriptions et les enregistrer dans une table de catalogue

Étape 1 : Créer une procédure stockée

La procédure stockée suivante effectue les actions suivantes :

  • Génère automatiquement des descriptions pour toutes les tables (et leurs colonnes) dans un schéma.

  • Renseigne une table de catalogue, où chaque ligne représente une table ou une colonne avec sa description générée.

CREATE OR REPLACE PROCEDURE DESCRIBE_TABLES_SET_CATALOG (database_name string, schema_name string, catalog_table string)
  RETURNS STRING
  LANGUAGE PYTHON
  RUNTIME_VERSION = '3.10'
  PACKAGES=('snowflake-snowpark-python','joblib')
  HANDLER = 'main'
AS
$$
import json
from joblib import Parallel, delayed
import multiprocessing

def generate_descr(session, database_name, schema_name, table, catalog_table):
    table_name =  table['TABLE_NAME']
    async_job = session.sql(f"CALL AI_GENERATE_TABLE_DESC( '{database_name}.{schema_name}.{table_name}',{{'describe_columns': true, 'use_table_data': true}})").collect_nowait()
    result = async_job.result()
    output = json.loads(result[0][0])
    columns_ret = output["COLUMNS"]
    table_ret = output["TABLE"][0]

    table_description = table_ret["description"]
    table_description = table_description.replace("'", "\\'")
    table_name = table_ret["name"]
    database_name = table_ret["database_name"]
    schema_name = table_ret["schema_name"]

    session.sql(f"""INSERT INTO {catalog_table} (domain, description, name, database_name, schema_name, table_name)
                          VALUES ('TABLE', '{table_description}', '{table_name}', '{database_name}', '{schema_name}', null)""").collect()

    for column in columns_ret:
        column_description = column["description"];
        column_description = column_description.replace("'", "\\'")
        column_name = column["name"];
        if not column_name.isupper():
            column_name = '"' + column_name + '"'
        session.sql(f"""INSERT INTO {catalog_table} (domain, description, name, database_name, schema_name, table_name)
                          VALUES ('COLUMN', '{column_description}', '{column_name}', '{database_name}', '{schema_name}', '{table_name}')""").collect()

    return 'Success';

def main(session, database_name, schema_name, catalog_table):

    schema_name = schema_name.upper()
    database_name = database_name.upper()
    catalog_table_upper = catalog_table.upper()
    tablenames = session.sql(f"""SELECT table_name
                      FROM {database_name}.information_schema.tables
                      WHERE table_schema = '{schema_name}'
                      AND table_type = 'BASE TABLE'
                      AND table_name !='{catalog_table_upper}'""").collect()
    try:
        Parallel(n_jobs=multiprocessing.cpu_count(), backend="threading")(
                delayed(generate_descr)(
                    session,
                    database_name,
                    schema_name,
                    table,
                    catalog_table,
                ) for table in tablenames
            )
        return 'Success'
    except Exception as e:
        # Catch and return the error message
        return f"An error occurred: {str(e)}"
$$;
Copy

Étape 2 : Créer la table de catalogue à alimenter

Utilisez le code suivant pour créer la table de catalogue dans laquelle les descriptions des tables et des colonnes sont stockées.

CREATE OR REPLACE TABLE catalog_table (
  domain VARCHAR,
  description VARCHAR,
  name VARCHAR,
  database_name VARCHAR,
  schema_name VARCHAR,
  table_name VARCHAR
  );
Copy

Étape 3 : Appeler la procédure stockée

En supposant que votre schéma est nommé my_db.sch1, appelez la procédure stockée comme suit :

CALL describe_tables_set_catalog('my_db', 'sch1', 'catalog_table');
Copy