Interroger les données dans Azure Synapse Analytics
Vous pouvez accéder à Azure Synapse depuis Databricks à l'aide du connecteur Azure Synapse, qui utilise l'instruction COPY dans Azure Synapse pour transférer efficacement de grands volumes de données entre un cluster Databricks et une instance Azure Synapse en utilisant un compte de stockage Azure Data Lake Storage pour la mise en scène temporaire.
Expérimental
La documentation sur la fédération des query héritées a été retirée et pourrait ne pas être mise à jour. Les configurations mentionnées dans ce contenu ne sont ni officiellement approuvées ni testées par Databricks. Si la Lakehouse Federation prend en charge votre base de données source, Databricks recommande d'utiliser cette dernière.
Azure Synapse Analytics est un data warehouse d'entreprise basé sur le cloud qui exploite le traitement massivement parallèle (MPP) pour exécuter rapidement des queries complexes sur des pétaoctets de données.
Ce connecteur est destiné à être utilisé uniquement avec des instances de pool dédié Synapse et n'est pas compatible avec d'autres composants Synapse.
COPY est disponible uniquement sur les instances d'Azure Data Lake Storage. Si vous recherchez des détails sur l'utilisation de PolyBase, consultez Connexion de Databricks et Azure Synapse avec PolyBase (hérité).
Exemple de syntaxe pour Synapse
Vous pouvez query Synapse en Scala, Python, SQL et R. Les exemples de code suivants utilisent des clés de compte de stockage et transfèrent les informations d'identification de stockage de Databricks vers Synapse.
Utilisez la chaîne de connexion fournie par le portail Azure, qui active le chiffrement Secure Sockets Layer (SSL) pour toutes les données envoyées entre le Driver Spark et l'instance Azure Synapse via la connexion JDBC. Pour vérifier que le chiffrement SSL est activé, vous pouvez rechercher encrypt=true dans la chaîne de connexion.
Les emplacements externes définis dans Unity Catalog ne sont pas pris en charge en tant qu'emplacements tempDir.
Databricks vous recommande d'utiliser le flux d'authentification le plus sécurisé disponible. Le flux d'authentification décrit dans cet exemple comporte des risques qui ne sont pas présents dans d'autres flux. Vous ne devriez utiliser ce flux que lorsque d'autres flux plus sécurisés, tels que les identités gérées, ne sont pas viables.
- Scala
- Python
- SQL
- R
// Set up the storage account access key in the notebook session conf.
spark.conf.set(
"fs.azure.account.key.<your-storage-account-name>.dfs.core.windows.net",
"<your-storage-account-access-key>")
// Get some data from an Azure Synapse table. The following example applies to Databricks Runtime 11.3 LTS and above.
val df: DataFrame = spark.read
.format("sqldw")
.option("host", "hostname")
.option("port", "port") /* Optional - will use default port 1433 if not specified. */
.option("user", "username")
.option("password", "password")
.option("database", "database-name")
.option("dbtable", "schema-name.table-name") /* If schemaName not provided, default to "dbo". */
.option("tempDir", "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>")
.option("forwardSparkAzureStorageCredentials", "true")
.load()
// Get some data from an Azure Synapse table. The following example applies to Databricks Runtime 10.4 LTS and below.
val df: DataFrame = spark.read
.format("com.databricks.spark.sqldw")
.option("url", "jdbc:sqlserver://<the-rest-of-the-connection-string>")
.option("tempDir", "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>")
.option("forwardSparkAzureStorageCredentials", "true")
.option("dbTable", "<your-table-name>")
.load()
// Load data from an Azure Synapse query.
val df: DataFrame = spark.read
.format("com.databricks.spark.sqldw")
.option("url", "jdbc:sqlserver://<the-rest-of-the-connection-string>")
.option("tempDir", "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>")
.option("forwardSparkAzureStorageCredentials", "true")
.option("query", "select x, count(*) as cnt from table group by x")
.load()
// Apply some transformations to the data, then use the
// Data Source API to write the data back to another table in Azure Synapse.
df.write
.format("com.databricks.spark.sqldw")
.option("url", "jdbc:sqlserver://<the-rest-of-the-connection-string>")
.option("forwardSparkAzureStorageCredentials", "true")
.option("dbTable", "<your-table-name>")
.option("tempDir", "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>")
.save()
# Set up the storage account access key in the notebook session conf.
spark.conf.set(
"fs.azure.account.key.<your-storage-account-name>.dfs.core.windows.net",
"<your-storage-account-access-key>")
# Get some data from an Azure Synapse table. The following example applies to Databricks Runtime 11.3 LTS and above.
df = spark.read
.format("sqldw")
.option("host", "hostname")
.option("port", "port") # Optional - will use default port 1433 if not specified.
.option("user", "username")
.option("password", "password")
.option("database", "database-name")
.option("dbtable", "schema-name.table-name") # If schemaName not provided, default to "dbo".
.option("tempDir", "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>")
.option("forwardSparkAzureStorageCredentials", "true")
.load()
# Get some data from an Azure Synapse table. The following example applies to Databricks Runtime 10.4 LTS and below.
df = spark.read \
.format("com.databricks.spark.sqldw") \
.option("url", "jdbc:sqlserver://<the-rest-of-the-connection-string>") \
.option("tempDir", "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>") \
.option("forwardSparkAzureStorageCredentials", "true") \
.option("dbTable", "<your-table-name>") \
.load()
# Load data from an Azure Synapse query.
df = spark.read \
.format("com.databricks.spark.sqldw") \
.option("url", "jdbc:sqlserver://<the-rest-of-the-connection-string>") \
.option("tempDir", "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>") \
.option("forwardSparkAzureStorageCredentials", "true") \
.option("query", "select x, count(*) as cnt from table group by x") \
.load()
# Apply some transformations to the data, then use the
# Data Source API to write the data back to another table in Azure Synapse.
df.write \
.format("com.databricks.spark.sqldw") \
.option("url", "jdbc:sqlserver://<the-rest-of-the-connection-string>") \
.option("forwardSparkAzureStorageCredentials", "true") \
.option("dbTable", "<your-table-name>") \
.option("tempDir", "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>") \
.save()
-- Set up the storage account access key in the notebook session conf.
SET fs.azure.account.key.<your-storage-account-name>.dfs.core.windows.net=<your-storage-account-access-key>;
-- Read data using SQL. The following example applies to Databricks Runtime 11.3 LTS and above.
CREATE TABLE example_table_in_spark_read
USING sqldw
OPTIONS (
host '<hostname>',
port '<port>' /* Optional - will use default port 1433 if not specified. */
user '<username>',
password '<password>',
database '<database-name>'
dbtable '<schema-name>.<table-name>', /* If schemaName not provided, default to "dbo". */
forwardSparkAzureStorageCredentials 'true',
tempDir 'abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>'
);
-- Read data using SQL. The following example applies to Databricks Runtime 10.4 LTS and below.
CREATE TABLE example_table_in_spark_read
USING com.databricks.spark.sqldw
OPTIONS (
url 'jdbc:sqlserver://<the-rest-of-the-connection-string>',
forwardSparkAzureStorageCredentials 'true',
dbtable '<your-table-name>',
tempDir 'abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>'
);
-- Write data using SQL.
-- Create a new table, throwing an error if a table with the same name already exists:
CREATE TABLE example_table_in_spark_write
USING com.databricks.spark.sqldw
OPTIONS (
url 'jdbc:sqlserver://<the-rest-of-the-connection-string>',
forwardSparkAzureStorageCredentials 'true',
dbTable '<your-table-name>',
tempDir 'abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>'
)
AS SELECT * FROM table_to_save_in_spark;
# Load SparkR
library(SparkR)
# Set up the storage account access key in the notebook session conf.
conf <- sparkR.callJMethod(sparkR.session(), "conf")
sparkR.callJMethod(conf, "set", "fs.azure.account.key.<your-storage-account-name>.dfs.core.windows.net", "<your-storage-account-access-key>")
# Get some data from an Azure Synapse table.
df <- read.df(
source = "com.databricks.spark.sqldw",
url = "jdbc:sqlserver://<the-rest-of-the-connection-string>",
forward_spark_azure_storage_credentials = "true",
dbTable = "<your-table-name>",
tempDir = "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>")
# Load data from an Azure Synapse query.
df <- read.df(
source = "com.databricks.spark.sqldw",
url = "jdbc:sqlserver://<the-rest-of-the-connection-string>",
forward_spark_azure_storage_credentials = "true",
query = "select x, count(*) as cnt from table group by x",
tempDir = "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>")
# Apply some transformations to the data, then use the
# Data Source API to write the data back to another table in Azure Synapse.
write.df(
df,
source = "com.databricks.spark.sqldw",
url = "jdbc:sqlserver://<the-rest-of-the-connection-string>",
forward_spark_azure_storage_credentials = "true",
dbTable = "<your-table-name>",
tempDir = "abfss://<your-container-name>@<your-storage-account-name>.dfs.core.windows.net/<your-directory-name>")
Comment fonctionne l'authentification entre Databricks et Synapse ?
Le connecteur Azure Synapse utilise trois types de connexions réseau :
- Driver Spark vers Azure Synapse
- Cluster Spark vers un compte de stockage Azure
- Compte de stockage Azure Synapse vers Azure
Configuration de l'accès au stockage Azure
Databricks et Synapse ont tous deux besoin d'un accès privilégié à un compte de stockage Azure à utiliser pour le stockage temporaire des données.
Azure Synapse ne prend pas en charge l'utilisation de SAS pour l'accès aux comptes de stockage. Vous pouvez configurer l'accès pour les deux services en effectuant l'une des opérations suivantes :
- Utilisez la clé de compte et le secret pour le compte de stockage et définissez
forwardSparkAzureStorageCredentialssurtrue. Consultez Définir les propriétés Spark pour configurer les informations d'identification Azure. - Utilisez Azure Data Lake Storage avec l'authentification OAuth 2.0 et définissez
enableServicePrincipalAuthsurtrue. Consultez Configurer la connexion de Databricks à Synapse avec OAuth 2.0 avec un Service Principal. - Configurez votre instance Azure Synapse pour qu'elle ait une Identité de Service Géré et définissez
useAzureMSIsurtrue.
Autorisations Azure Synapse requises
Parce qu'il utilise COPY en arrière-plan, le connecteur Azure Synapse exige que l'utilisateur de la connexion JDBC ait l'autorisation d'exécuter les commandes suivantes dans l'instance Azure Synapse connectée :
Si la table de destination n'existe pas dans Azure Synapse, une autorisation d'exécution de la commande suivante est requise en plus de la commande ci-dessus :
Le tableau suivant résume les autorisations requises pour les écritures avec COPY:
Permissions (insérer dans une table existante) | Autorisations (insérer dans une nouvelle table) |
|---|---|
Administrer les opérations en bloc de la base de données INSÉRER | Administrer les opérations en bloc de la base de données INSÉRER Créer une table ALTER ON SCHEMA :: dbo |
Configurer la connexion de Databricks à Synapse avec OAuth 2.0 avec un Service Principal
Vous pouvez vous authentifier auprès d'Azure Synapse Analytics à l'aide d'un service principal ayant accès au compte de stockage sous-jacent. Pour plus d'informations sur l'utilisation des identifiants de Service Principal pour accéder à un compte de stockage Azure, consultez Se connecter à Azure Data Lake Storage et Blob Storage. Vous devez définir l'option enableServicePrincipalAuth sur true dans la configuration de la connexion référence des options du connecteur Databricks Synapse pour permettre au connecteur de s'authentifier avec un Service Principal.
Vous pouvez éventuellement utiliser un autre service principal pour la connexion Azure Synapse Analytics. L'exemple suivant configure les identifiants du service principal pour le compte de stockage et les identifiants facultatifs du service principal pour Synapse :
- ini
- Scala
- Python
- R
; Defining the Service Principal credentials for the Azure storage account
fs.azure.account.auth.type OAuth
fs.azure.account.oauth.provider.type org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider
fs.azure.account.oauth2.client.id <application-id>
fs.azure.account.oauth2.client.secret <service-credential>
fs.azure.account.oauth2.client.endpoint https://login.microsoftonline.com/<directory-id>/oauth2/token
; Defining a separate set of service principal credentials for Azure Synapse Analytics (If not defined, the connector will use the Azure storage account credentials)
spark.databricks.sqldw.jdbc.service.principal.client.id <application-id>
spark.databricks.sqldw.jdbc.service.principal.client.secret <service-credential>
// Defining the Service Principal credentials for the Azure storage account
spark.conf.set("fs.azure.account.auth.type", "OAuth")
spark.conf.set("fs.azure.account.oauth.provider.type", "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider")
spark.conf.set("fs.azure.account.oauth2.client.id", "<application-id>")
spark.conf.set("fs.azure.account.oauth2.client.secret", "<service-credential>")
spark.conf.set("fs.azure.account.oauth2.client.endpoint", "https://login.microsoftonline.com/<directory-id>/oauth2/token")
// Defining a separate set of service principal credentials for Azure Synapse Analytics (If not defined, the connector will use the Azure storage account credentials)
spark.conf.set("spark.databricks.sqldw.jdbc.service.principal.client.id", "<application-id>")
spark.conf.set("spark.databricks.sqldw.jdbc.service.principal.client.secret", "<service-credential>")
# Defining the service principal credentials for the Azure storage account
spark.conf.set("fs.azure.account.auth.type", "OAuth")
spark.conf.set("fs.azure.account.oauth.provider.type", "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider")
spark.conf.set("fs.azure.account.oauth2.client.id", "<application-id>")
spark.conf.set("fs.azure.account.oauth2.client.secret", "<service-credential>")
spark.conf.set("fs.azure.account.oauth2.client.endpoint", "https://login.microsoftonline.com/<directory-id>/oauth2/token")
# Defining a separate set of service principal credentials for Azure Synapse Analytics (If not defined, the connector will use the Azure storage account credentials)
spark.conf.set("spark.databricks.sqldw.jdbc.service.principal.client.id", "<application-id>")
spark.conf.set("spark.databricks.sqldw.jdbc.service.principal.client.secret", "<service-credential>")
# Load SparkR
library(SparkR)
conf <- sparkR.callJMethod(sparkR.session(), "conf")
# Defining the service principal credentials for the Azure storage account
sparkR.callJMethod(conf, "set", "fs.azure.account.auth.type", "OAuth")
sparkR.callJMethod(conf, "set", "fs.azure.account.oauth.provider.type", "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider")
sparkR.callJMethod(conf, "set", "fs.azure.account.oauth2.client.id", "<application-id>")
sparkR.callJMethod(conf, "set", "fs.azure.account.oauth2.client.secret", "<service-credential>")
sparkR.callJMethod(conf, "set", "fs.azure.account.oauth2.client.endpoint", "https://login.microsoftonline.com/<directory-id>/oauth2/token")
# Defining a separate set of service principal credentials for Azure Synapse Analytics (If not defined, the connector will use the Azure storage account credentials)
sparkR.callJMethod(conf, "set", "spark.databricks.sqldw.jdbc.service.principal.client.id", "<application-id>")
sparkR.callJMethod(conf, "set", "spark.databricks.sqldw.jdbc.service.principal.client.secret", "<service-credential>")
Modes de sauvegarde pris en charge pour les écritures par batch
Le connecteur Azure Synapse prend en charge les modes de sauvegarde ErrorIfExists, Ignore, Append et Overwrite, le mode default étant ErrorIfExists. Pour plus d'information sur les modes de sauvegarde pris en charge dans Apache Spark, consultez la documentation Spark SQL sur les modes de sauvegarde.
Référence des options de connecteur Databricks Synapse
Les OPTIONS fournis dans Spark SQL prennent en charge les paramètres suivants :
parameter | Obligatoire | Par défaut | Notes |
|---|---|---|---|
| Oui, sauf si | No default | La table à créer ou à lire dans Azure Synapse. Ce paramètre est requis lors de la sauvegarde des données vers Azure Synapse. Vous pouvez également utiliser La variante |
| Oui, sauf si | No default | La query à lire dans Azure Synapse. Pour les tables référencées dans la requête, vous pouvez également utiliser |
| Non | No default | Le nom d'utilisateur Azure Synapse. Doit être utilisé conjointement avec l'option |
| Non | No default | Le mot de passe Azure Synapse. Doit être utilisé conjointement avec l'option |
| Oui | No default | Une URL JDBC avec |
| Non | Déterminé par le sous-protocole de l'URL JDBC. | Le nom de classe du Driver JDBC à utiliser. Cette classe doit se trouver dans le classpath. Dans la plupart des cas, il ne devrait pas être nécessaire de spécifier cette option, car le nom de classe du Driver approprié devrait être automatiquement déterminé par le sous-protocole de l'URL JDBC. La variante |
| Oui | No default | Un URI La variante Vous ne pouvez pas utiliser un emplacement externe défini dans Unity Catalog comme emplacement |
| Non |
| L'algorithme de compression à utiliser pour encoder/décoder temporairement par Spark et Azure Synapse. Les valeurs actuellement prises en charge sont : |
| Non | false | Si Lors de la configuration de l'authentification du stockage, vous devez définir exactement l'un de La variante |
| Non | false | Si Lors de la configuration de l'authentification du stockage, vous devez définir exactement l'un de |
| Non | false | Si Si |
| Non |
| Une chaîne utilisée pour spécifier les options de table lors de la création de l'ensemble de tables Azure Synapse via La variante |
| Non | Aucune valeur par default (chaîne vide) | Une liste de commandes SQL séparées par Si l'une de ces commandes échoue, elle est traitée comme une erreur et l'opération d'écriture n'est pas exécutée. |
| Non | Aucune valeur par default (chaîne vide) | Liste séparée par Si l'une de ces commandes échoue, elle est traitée comme une erreur et vous obtiendrez une exception après que les données aient été écrites avec succès dans l'instance Azure Synapse. |
| Non | 256 |
La variante |
| Non |
| L'étiquette de la connexion pour chaque query. Si elle n'est pas spécifiée ou si la valeur est une chaîne vide, la valeur default du tag est ajoutée à l'URL JDBC. La valeur default empêche l'outil de monitoring Azure DB de déclencher des alertes d'injection SQL erronées contre les query. |
| Non | No default | Contrôlez la longueur des |
| Non | false | Le réglage sur Consultez Insertion explicite de valeurs dans une colonne d'identité. |
| Non | No default | Une source de données externe pré-provisionnée pour lire les données d'Azure Synapse. Une source de données externe ne peut être utilisée qu'avec PolyBase et supprime l'exigence d'autorisation CONTROL, car le connecteur n'a pas besoin de créer d'informations d'identification étendues ni de source de données externe pour charger des données. Pour un exemple d'utilisation et la liste des autorisations requises lors de l'utilisation d'une source de données externe, consultez Autorisations Azure Synapse requises pour PolyBase avec l'option de source de données externe. |
| Non | 0 | Le nombre maximal de lignes pouvant être rejetées pendant les lectures et les écritures avant l'annulation de l'opération de chargement. Les lignes rejetées seront ignorées. Par exemple, si deux enregistrements sur dix comportent des erreurs, seuls huit enregistrements seront traités. Consultez la documentation REJECT_VALUE dans CREATE EXTERNAL TABLE et la documentation MAXERRORS dans COPY. |
| Non | false | Si |
tableOptions,preActions,postActionsetmaxStrLengthsont pertinents uniquement lors de l'écriture de données de Databricks vers une nouvelle table dans Azure Synapse.- Même si tous les noms d'options de source de données ne sont pas sensibles à la casse, nous vous recommandons de les spécifier en « camel case » pour plus de clarté.
Pushdown de la query vers Azure Synapse
Le connecteur Azure Synapse implémente un ensemble de règles d’optimisation pour pousser les opérateurs suivants vers Azure Synapse :
FilterProjectLimit
Les opérateurs Project et Filter prennent en charge les expressions suivantes :
- La plupart des opérateurs logiques booléens
- Comparaisons
- Opérations arithmétiques de base
- Conversions numériques et de chaînes
Pour l'opérateur Limit, le pushdown n'est pris en charge que lorsqu'aucun ordre n'est spécifié. Par exemple :
SELECT TOP(10) * FROM table, mais pas SELECT TOP(10) * FROM table ORDER BY col.
Le connecteur Azure Synapse ne transmet pas les expressions fonctionnant sur des chaînes, des dates ou des horodatages.
La poussée de requêtes construite avec le connecteur Azure Synapse est activée par default. Vous pouvez le désactiver en définissant spark.databricks.sqldw.pushdown sur false.
Gestion temporaire des données
Le connecteur Azure Synapse *ne supprime pas* les fichiers temporaires qu'il crée dans le conteneur de stockage Azure. Databricks vous recommande de supprimer périodiquement les fichiers temporaires sous l'emplacement tempDir fourni par l'utilisateur.
Pour faciliter le nettoyage des données, le connecteur Azure Synapse ne stocke pas les fichiers de données directement sous tempDir, mais crée plutôt un sous-répertoire de la forme : <tempDir>/<yyyy-MM-dd>/<HH-mm-ss-SSS>/<randomUUID>/. Vous pouvez mettre en place des jobs périodiques (en utilisant la fonctionnalité Lakeflow Jobs ou autrement) pour supprimer récursivement tout sous-répertoire plus ancien qu'un threshold donné (par exemple, 2 jours), en supposant qu'il ne peut pas y avoir de jobs Spark s'exécutant plus longtemps que ce threshold.
Une alternative plus simple consiste à supprimer périodiquement l'intégralité du conteneur et à en créer un nouveau avec le même nom. Cela nécessite l'utilisation d'un conteneur dédié pour les données temporaires produites par le connecteur Azure Synapse et que vous puissiez trouver une fenêtre de temps dans laquelle vous pouvez garantir qu'aucune requête impliquant le connecteur n'est en cours d'exécution.
Gestion des objets temporaires
Le connecteur Azure Synapse automatise le transfert de données entre un cluster Databricks et une instance Azure Synapse. Pour la lecture de données depuis une table ou une requête Azure Synapse, ou l'écriture de données vers une table Azure Synapse, le connecteur Azure Synapse crée des objets temporaires, y compris DATABASE SCOPED CREDENTIAL, EXTERNAL DATA SOURCE, EXTERNAL FILE FORMAT et EXTERNAL TABLE en arrière-plan. Ces objets existent uniquement pendant la durée du Job Spark correspondant et sont automatiquement supprimés.
Lorsqu'un cluster exécute une requête à l'aide du connecteur Azure Synapse, si le processus du Driver Spark plante ou est redémarré de force, ou si le cluster est arrêté ou redémarré de force, les objets temporaires risquent de ne pas être supprimés. Pour faciliter l'identification et la suppression manuelle de ces objets, le connecteur Azure Synapse préfixe les noms de tous les objets temporaires intermédiaires créés dans l'instance Azure Synapse avec une balise de la forme : tmp_databricks_<yyyy_MM_dd_HH_mm_ss_SSS>_<randomUUID>_<internalObject>.
Nous vous recommandons de rechercher périodiquement les objets divulgués à l’aide de queries telles que les suivantes :
SELECT * FROM sys.database_scoped_credentials WHERE name LIKE 'tmp_databricks_%'SELECT * FROM sys.external_data_sources WHERE name LIKE 'tmp_databricks_%'SELECT * FROM sys.external_file_formats WHERE name LIKE 'tmp_databricks_%'SELECT * FROM sys.external_tables WHERE name LIKE 'tmp_databricks_%'