Executar um notebook Databricks a partir de outro notebook
Importante
Para a orquestração de notebooks, use Databricks Jobs. Para cenários de modularização de código, use os arquivos workspace. O senhor só deve usar as técnicas descritas neste artigo quando o seu caso de uso não puder ser implementado com o uso de um Databricks Job, como, por exemplo, para repetir o Notebook em um conjunto dinâmico de parâmetros, ou se não tiver acesso aos arquivosworkspace . Para obter mais informações, consulte programar e orquestrar fluxo de trabalho e compartilhar código.
Comparação de %run
e dbutils.notebook.run()
O comando %run
permite incluir outro Notebook em um Notebook. Você pode usar %run
para modularizar seu código, por exemplo, colocando funções de suporte em um Notebook separado. Você também pode usá-lo para concatenar Notebook que implementam os passos em uma análise. Quando você usa %run
, o Notebook chamado é executado imediatamente e as funções e variáveis definidas nele ficam disponíveis no Notebook chamador.
A API do dbutils.notebook
é um complemento do %run
porque permite a você transmitir parâmetros e retornar valores de um notebook. Isso permite que você crie fluxos de trabalho e pipelines complexos com dependências. Por exemplo, você pode obter uma lista de arquivos em um diretório e passar os nomes para outro notebook, que não é possível com %run
. Também é possível criar fluxos de trabalho de if-then-else com base em valores de retorno ou chamar outros notebooks usando caminhos relativos.
Ao contrário do %run
, o método dbutils.notebook.run()
inicia um novo trabalho para executar o notebook.
Esses métodos, como todas as APIs dbutils
, estão disponíveis apenas em Python e Scala. No entanto, você pode usar dbutils.notebook.run()
para invocar um notebook R.
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 os dois notebooks estão no mesmo diretório no 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. Você pode organizar notebooks 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 você usa
%run
para executar um Notebook que contém widgets, por default a execução Notebook especificada com os valores default do widget. Você também pode passar valores para widgets; consulte Usar widgets do Databricks com %run.
dbutils.notebook
API
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
Executa um notebook e retorna seu valor de saída. O método inicia um trabalho curto que é executado imediatamente.
O parâmetro timeout_seconds
controla o tempo limite da execução (0 significa sem tempo limite): a chamada para run
lança uma exceção se não for concluída dentro do tempo especificado. Se o Databricks estiver 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.
run
Uso
dbutils.notebook.run("notebook-name", 60, {"argument": "data", "argument2": "data2", ...})
dbutils.notebook.run("notebook-name", 60, Map("argument" -> "data", "argument2" -> "data2", ...))
run
Exemplo
Suponha que você tenha um bloco de anotações chamado workflows
com um widget chamado foo
que imprima o valor do widget:
dbutils.widgets.text("foo", "fooDefault", "fooEmptyLabel")
print(dbutils.widgets.get("foo"))
A execução dbutils.notebook.run("workflows", 60, {"foo": "bar"})
produz o seguinte resultado:
O widget tinha o valor que você passou usando dbutils.notebook.run()
, "bar"
, em vez do padrão.
exit(value: String): void
Saia de um notebook com um valor. Se você chamar um notebook utilizando o método run
, este é o valor retornado.
dbutils.notebook.exit("returnValue")
Chamar dbutils.notebook.exit
em um trabalho faz com que o notebook seja concluído com sucesso. Se você quiser causar falha no trabalho, lance uma exceção.
Exemplo
No exemplo a seguir, você passa argumentos para DataImportNotebook
e executa notebooks diferentes (DataCleaningNotebook
ou ErrorHandlingNotebook
) com base no resultado de DataImportNotebook
.
Quando o código é executado, aparece uma tabela com um link para o site Notebook:
Para view os detalhes da execução, clique no link começar time na tabela. Se a execução estiver concluída, o senhor também pode view os detalhes da execução clicando no link End time.
Passe dados estruturados
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, you can 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 4 notebooks a seguir. Os notebooks são gravados em Scala.
Importe os cadernos em uma única pasta no workspace.
Execute o notebook Executar simultaneamente.