Orquestrar o Notebook e modularizar o código no Notebook
Saiba como orquestrar o Notebook e modularizar o código no Notebook. Veja exemplos e entenda quando usar métodos alternativos para a orquestração do Notebook.
Métodos de orquestração e modularização de código
A tabela a seguir compara os métodos disponíveis para orquestrar o Notebook e modularizar o código no Notebook.
Método |
Caso de uso |
Notas |
---|---|---|
Notebook orquestração (recomendado) |
Método recomendado para orquestrar o Notebook. Suporta fluxos de trabalho complexos com dependências de tarefas, programar e acionadores. Fornece uma abordagem robusta e escalável para cargas de trabalho de produção, mas requer instalação e configuração. |
|
Notebook orquestração |
Use o site começar um novo Job efêmero para cada chamada, o que pode aumentar a sobrecarga e carece de recurso avançado de programação. |
|
Modularização de código (recomendada) |
Método recomendado para modularizar o código. Modularize o código em arquivos de código reutilizáveis armazenados no site workspace. Oferece suporte ao controle de versão com repositórios e integração com IDEs para melhorar a depuração e os testes de unidade. Requer configuração adicional para gerenciar caminhos de arquivos e dependências. |
|
Modularização de código |
Use Basta importar funções ou variáveis de outro Notebook, executando-as em linha. Útil para prototipagem, mas pode levar a um código fortemente acoplado que é mais difícil de manter. Não suporta passagem de parâmetros ou controle de versão. |
%run
versus dbutils.notebook.run()
O comando %run
permite que o senhor inclua outro Notebook dentro de um Notebook. O senhor pode usar o site %run
para modularizar seu código, colocando as funções de suporte em um Notebook separado. O senhor também pode usá-lo para concatenar o Notebook que implementa as etapas de uma análise. Quando o senhor usa %run
, o Notebook chamado é imediatamente executado e as funções e variáveis definidas nele ficam disponíveis no Notebook de chamada.
O dbutils.notebook
API complementa o %run
porque permite que o senhor passe parâmetros e retorne valores de um Notebook. Isso permite que o senhor crie fluxos de trabalho complexos e pipelines com dependências. Por exemplo, o senhor pode obter uma lista de arquivos em um diretório e passar os nomes para outro Notebook, o que é impossível com %run
. O senhor também pode criar fluxos de trabalho if-then-else com base em valores de retorno.
Ao contrário do %run
, o método dbutils.notebook.run()
inicia um novo trabalho para executar o notebook.
Como todas as APIs do site dbutils
, esses métodos estão disponíveis somente em Python e Scala. No entanto, o senhor pode usar dbutils.notebook.run()
para chamar um R Notebook.
Usar %run
para importar um notebooks
Neste exemplo, o primeiro notebook define uma função, reverse
, que fica disponível no segundo notebook depois que você usa mágica %run
para executar shared-code-notebook
.
Como ambos os Notebooks estão no mesmo diretório em workspace, use o prefixo ./
em ./shared-code-notebook
para indicar que o caminho deve ser resolvido em relação ao Notebook em execução no momento. O senhor pode organizar o Notebook em diretórios, como %run ./dir/notebook
, ou usar um caminho absoluto, como %run /Users/username@organization.com/directory/notebook
.
Observação
%run
deve estar em uma célula própria, pois executa todo o notebook em linha.Você não pode usar
%run
para executar um arquivo Python eimport
as entidades definidas nesse arquivo em um Notebook. Para importar de um arquivo Python, consulte Modularizar seu código usando arquivos. Ou, empacote o arquivo em uma biblioteca Python, crie uma biblioteca Databricks dessa biblioteca Python e instale a biblioteca nos clusters que você usa para executar seu Notebook.Quando o senhor usa
%run
para executar um Notebook que contém widgets, default a execução do Notebook especificado com os valores default do widget. O senhor também pode passar valores para widgets; consulte Usar widgets do Databricks com %run.
Use dbutils.notebook.run
para começar um novo trabalho
Executa um notebook e retorna seu valor de saída. O método inicia um trabalho curto que é executado imediatamente.
Os métodos disponíveis na API do dbutils.notebook
são run
e exit
. Ambos os parâmetros e valores de retorno devem ser strings.
run(path: String, timeout_seconds: int, arguments: Map): String
O parâmetro timeout_seconds
controla o tempo limite da execução (0 significa que não há tempo limite). A chamada para run
lançará uma exceção se não for concluída dentro do tempo especificado. Se o site Databricks ficar inativo por mais de 10 minutos, a execução do Notebook falhará independentemente de timeout_seconds
.
O parâmetro arguments
define valores de widget do notebook de destino. Especificamente, se o notebook que você está executando tiver um widget chamado A
e você passar um par key-value ("A": "B")
como parte do parâmetro de argumentos para a chamada run()
, a recuperação do valor do widget A
será retornar "B"
. Você pode encontrar as instruções para criar e trabalhar com widgets no artigo Widgets do Databricks .
Observação
O parâmetro
arguments
aceita apenas caracteres latinos (conjunto de caracteres ASCII). Usar caracteres não ASCII retorna um erro.Os trabalhos criados usando a API
dbutils.notebook
devem ser concluídos em 30 dias ou menos.
Passar dados estruturados entre o Notebook
Esta seção ilustra como passar dados estruturados entre notebooks.
# Example 1 - returning data through temporary views.
# You can only return one string using dbutils.notebook.exit(), but since called notebooks reside in the same JVM, you can
# return a name referencing data stored in a temporary view.
## In callee notebook
spark.range(5).toDF("value").createOrReplaceGlobalTempView("my_data")
dbutils.notebook.exit("my_data")
## In caller notebook
returned_table = dbutils.notebook.run("LOCATION_OF_CALLEE_NOTEBOOK", 60)
global_temp_db = spark.conf.get("spark.sql.globalTempDatabase")
display(table(global_temp_db + "." + returned_table))
# Example 2 - returning data through DBFS.
# For larger datasets, you can write the results to DBFS and then return the DBFS path of the stored data.
## In callee notebook
dbutils.fs.rm("/tmp/results/my_data", recurse=True)
spark.range(5).toDF("value").write.format("parquet").save("dbfs:/tmp/results/my_data")
dbutils.notebook.exit("dbfs:/tmp/results/my_data")
## In caller notebook
returned_table = dbutils.notebook.run("LOCATION_OF_CALLEE_NOTEBOOK", 60)
display(spark.read.format("parquet").load(returned_table))
# Example 3 - returning JSON data.
# To return multiple values, you can use standard JSON libraries to serialize and deserialize results.
## In callee notebook
import json
dbutils.notebook.exit(json.dumps({
"status": "OK",
"table": "my_data"
}))
## In caller notebook
import json
result = dbutils.notebook.run("LOCATION_OF_CALLEE_NOTEBOOK", 60)
print(json.loads(result))
// Example 1 - returning data through temporary views.
// You can only return one string using dbutils.notebook.exit(), but since called notebooks reside in the same JVM, you can
// return a name referencing data stored in a temporary view.
/** In callee notebook */
sc.parallelize(1 to 5).toDF().createOrReplaceGlobalTempView("my_data")
dbutils.notebook.exit("my_data")
/** In caller notebook */
val returned_table = dbutils.notebook.run("LOCATION_OF_CALLEE_NOTEBOOK", 60)
val global_temp_db = spark.conf.get("spark.sql.globalTempDatabase")
display(table(global_temp_db + "." + returned_table))
// Example 2 - returning data through DBFS.
// For larger datasets, you can write the results to DBFS and then return the DBFS path of the stored data.
/** In callee notebook */
dbutils.fs.rm("/tmp/results/my_data", recurse=true)
sc.parallelize(1 to 5).toDF().write.format("parquet").save("dbfs:/tmp/results/my_data")
dbutils.notebook.exit("dbfs:/tmp/results/my_data")
/** In caller notebook */
val returned_table = dbutils.notebook.run("LOCATION_OF_CALLEE_NOTEBOOK", 60)
display(sqlContext.read.format("parquet").load(returned_table))
// Example 3 - returning JSON data.
// To return multiple values, use standard JSON libraries to serialize and deserialize results.
/** In callee notebook */
// Import jackson json libraries
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
import com.fasterxml.jackson.databind.ObjectMapper
// Create a json serializer
val jsonMapper = new ObjectMapper with ScalaObjectMapper
jsonMapper.registerModule(DefaultScalaModule)
// Exit with json
dbutils.notebook.exit(jsonMapper.writeValueAsString(Map("status" -> "OK", "table" -> "my_data")))
/** In caller notebook */
// Import jackson json libraries
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
import com.fasterxml.jackson.databind.ObjectMapper
// Create a json serializer
val jsonMapper = new ObjectMapper with ScalaObjectMapper
jsonMapper.registerModule(DefaultScalaModule)
val result = dbutils.notebook.run("LOCATION_OF_CALLEE_NOTEBOOK", 60)
println(jsonMapper.readValue[Map[String, String]](result))
Trabalhando com erros
Esta seção ilustra como lidar com erros.
# Errors throw a WorkflowException.
def run_with_retry(notebook, timeout, args = {}, max_retries = 3):
num_retries = 0
while True:
try:
return dbutils.notebook.run(notebook, timeout, args)
except Exception as e:
if num_retries > max_retries:
raise e
else:
print("Retrying error", e)
num_retries += 1
run_with_retry("LOCATION_OF_CALLEE_NOTEBOOK", 60, max_retries = 5)
// Errors throw a WorkflowException.
import com.databricks.WorkflowException
// Since dbutils.notebook.run() is just a function call, you can retry failures using standard Scala try-catch
// control flow. Here, we show an example of retrying a notebook a number of times.
def runRetry(notebook: String, timeout: Int, args: Map[String, String] = Map.empty, maxTries: Int = 3): String = {
var numTries = 0
while (true) {
try {
return dbutils.notebook.run(notebook, timeout, args)
} catch {
case e: WorkflowException if numTries < maxTries =>
println("Error, retrying: " + e)
}
numTries += 1
}
"" // not reached
}
runRetry("LOCATION_OF_CALLEE_NOTEBOOK", timeout = 60, maxTries = 5)
Execute vários notebooks simultaneamente
Você pode executar vários Notebook ao mesmo tempo usando construções padrão Scala e Python, como Threads (Scala, Python) e Futures (Scala, Python). O exemplo Notebook demonstra como usar essas construções.
Faça o download dos quatro Notebooks a seguir. O Notebook está escrito em Scala.
Importe os cadernos em uma única pasta no workspace.
Execute o notebook Executar simultaneamente.