Köra en Databricks-anteckningsbok från en annan notebook-fil

Viktigt!

För orkestrering av notebook-filer använder du Databricks-jobb. För scenarier med kod modularisering använder du arbetsytefiler. Du bör bara använda de tekniker som beskrivs i den här artikeln när ditt användningsfall inte kan implementeras med ett Databricks-jobb, till exempel för att loopa notebook-filer över en dynamisk uppsättning parametrar eller om du inte har åtkomst till arbetsytefiler. Mer information finns i Databricks-jobb och dela kod.

Jämförelse av %run och dbutils.notebook.run()

Med %run kommandot kan du inkludera en annan notebook-fil i en notebook-fil. Du kan använda %run för att modularisera koden, till exempel genom att placera stödfunktioner i en separat notebook-fil. Du kan också använda den för att sammanfoga notebook-filer som implementerar stegen i en analys. När du använder %runkörs den anropade notebook-filen omedelbart och de funktioner och variabler som definieras i den blir tillgängliga i den anropande notebook-filen.

API:et dbutils.notebook är ett komplement till %run eftersom du kan skicka parametrar till och returnera värden från en notebook-fil. På så sätt kan du skapa komplexa arbetsflöden och pipelines med beroenden. Du kan till exempel hämta en lista över filer i en katalog och skicka namnen till en annan notebook-fil, vilket inte är möjligt med %run. Du kan också skapa if-then-else-arbetsflöden baserat på returvärden eller anropa andra notebook-filer med hjälp av relativa sökvägar.

dbutils.notebook.run() Till skillnad från %runstartar metoden ett nytt jobb för att köra notebook-filen.

Dessa metoder, liksom alla dbutils API:er, är endast tillgängliga i Python och Scala. Du kan dock använda dbutils.notebook.run() för att anropa en R-notebook-fil.

Använd %run för att importera en notebook-fil

I det här exemplet definierar den första notebook-filen en funktion, reverse, som är tillgänglig i den andra notebook-filen när du använder magin %run för att köra shared-code-notebook.

Shared code notebook

Notebook import example

Eftersom båda dessa notebook-filer finns i samma katalog på arbetsytan använder du prefixet ./ i ./shared-code-notebook för att ange att sökvägen ska matchas i förhållande till den notebook-fil som körs. Du kan ordna notebook-filer i kataloger, till exempel %run ./dir/notebook, eller använda en absolut sökväg som %run /Users/username@organization.com/directory/notebook.

Kommentar

  • %run måste vara i en cell av sig själv, eftersom den kör hela notebook-filen infogad.
  • Du kan inte använda %run för att köra en Python-fil och import de entiteter som definierats i filen i en notebook-fil. Information om hur du importerar från en Python-fil finns i Modularisera koden med hjälp av filer. Eller paketera filen i ett Python-bibliotek, skapa ett Azure Databricks-bibliotek från Python-biblioteket och installera biblioteket i klustret som du använder för att köra anteckningsboken.
  • När du använder %run för att köra en notebook-fil som innehåller widgetar körs som standard den angivna notebook-filen med widgetens standardvärden. Du kan också skicka in värden till widgetar. se Använda Databricks-widgetar med %run.

dbutils.notebook API

De metoder som är tillgängliga i API:et dbutils.notebook är run och exit. Både parametrar och returvärden måste vara strängar.

run(path: String, timeout_seconds: int, arguments: Map): String

Kör en notebook-fil och returnera dess slutvärde. Metoden startar ett tillfälliga jobb som körs omedelbart.

Parametern timeout_seconds styr tidsgränsen för körningen (0 innebär ingen timeout): anropet till run utlöser ett undantag om det inte slutförs inom den angivna tiden. Om Azure Databricks är nere i mer än 10 minuter misslyckas notebook-körningen oavsett timeout_seconds.

Parametern arguments anger widgetvärden för målanteckningsboken. Mer specifikt, om notebook-filen som du kör har en widget med namnet A, och du skickar ett nyckel/värde-par ("A": "B") som en del av argumentparet till anropet, returneras "B"värdet för widgeten run()A. Du hittar instruktionerna för att skapa och arbeta med widgetar i artikeln Databricks-widgetar .

Kommentar

  • Parametern arguments accepterar endast latinska tecken (ASCII-teckenuppsättning). Om du använder icke-ASCII-tecken returneras ett fel.
  • Jobb som skapas med hjälp av API:et dbutils.notebook måste slutföras om 30 dagar eller mindre.

run Användning

Python

dbutils.notebook.run("notebook-name", 60, {"argument": "data", "argument2": "data2", ...})

Scala

dbutils.notebook.run("notebook-name", 60, Map("argument" -> "data", "argument2" -> "data2", ...))

run Exempel

Anta att du har en notebook-fil med namnet workflows med en widget med namnet foo som skriver ut widgetens värde:

dbutils.widgets.text("foo", "fooDefault", "fooEmptyLabel")
print(dbutils.widgets.get("foo"))

Körning dbutils.notebook.run("workflows", 60, {"foo": "bar"}) ger följande resultat:

Notebook with widget

Widgeten hade det värde som du skickade med hjälp av dbutils.notebook.run(), "bar"i stället för standardvärdet.

exit(value: String): void Avsluta en notebook-fil med ett värde. Om du anropar en notebook-fil med hjälp av run metoden är det här värdet som returneras.

dbutils.notebook.exit("returnValue")

När du anropar dbutils.notebook.exit ett jobb slutförs notebook-filen. Om du vill att jobbet ska misslyckas utlöser du ett undantag.

Exempel

I följande exempel skickar du argument till DataImportNotebook och kör olika notebook-filer (DataCleaningNotebook eller ErrorHandlingNotebook) baserat på resultatet från DataImportNotebook.

if-else example

När koden körs visas en länk till den notebook-fil som körs:

Link to running notebook

Om du vill visa information om körningen klickar du på notebook-länken Notebook-jobb #xxxx.

Result of ephemeral notebook run

Skicka strukturerade data

Det här avsnittet visar hur du skickar strukturerade data mellan notebook-filer.

Python

# 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))

Scala

// 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))

Hantera fel

Det här avsnittet visar hur du hanterar fel.

Python

# 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)

Scala

// 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)

Köra flera notebook-filer samtidigt

Du kan köra flera notebook-filer samtidigt med hjälp av standardkonstruktioner för Scala och Python, till exempel Trådar (Scala, Python) och Futures (Scala, Python). Exempelanteckningsböckerna visar hur du använder dessa konstruktioner.

  1. Ladda ned följande 4 notebook-filer. Notebook-filerna är skrivna i Scala.
  2. Importera anteckningsböckerna till en enda mapp på arbetsytan.
  3. Kör anteckningsboken Kör samtidigt .

Kör samtidigt notebook-fil

Hämta notebook-fil

Kör i parallell notebook-fil

Hämta notebook-fil

Testa notebook-fil

Hämta notebook-fil

Testing-2 Notebook

Hämta notebook-fil