Blog
Wie Sie Ihr Python-Projekt auf Databricks bereitstellen

In den letzten Jahren hat sich Databricks zu einer immer beliebteren Umgebung für maschinelle Lernprojekte entwickelt. Seit etwa einem Jahr ist es auf allen gängigen Clouds verfügbar und damit für fast jedes Data Science-Team, das in der Cloud arbeitet, erreichbar.
Eine der wichtigsten Funktionen von Databricks sind die Notebooks. Damit ist die Einrichtung einer interaktiven Arbeitsumgebung mit großen Datensätzen auf einem Spark-Cluster eine Sache von Minuten - Sie erstellen ein Notebook, schließen einen Cluster an und können loslegen. Die Einfachheit dieser Vorgehensweise hat jedoch einen Nachteil: Notebooks sind im Allgemeinen nicht die beste Umgebung, um hochwertigen Code zu entwickeln. Das Schreiben von Unit-Tests für Code in einem Notizbuch ist schwierig - und wird oft übersprungen. Und da Databricks sogar die Planung von Notizbüchern als Auftrag erlaubt, landen Notizbücher, die ohne viel Struktur geschrieben wurden (manchmal sogar ohne die Funktionalität in Funktionen zu packen) und nie richtig getestet wurden, als Produktionsaufträge. Solche 'Produktionsnotizbücher' lassen meinen inneren Ingenieur erschaudern.
Wenn also die Planung Ihres Notebooks nicht der richtige Weg ist, wie sollten Sie dann Produktionsaufträge auf Databricks bereitstellen?
Schritt 1: Erstellen Sie ein Paket
Der erste Schritt besteht darin, ein Python-Paket zu erstellen. Strukturieren Sie Ihren Code in kurze Funktionen, gruppieren Sie diese in (Unter-)Module und schreiben Sie Unit-Tests. Erstellen Sie bei Bedarf Mock-Daten, um Ihre Datenverarbeitungsfunktionen zu testen. Fügen Sie einen Pre-Commit-Hook mit Linting und Typüberprüfung hinzu - zum Beispiel mit Paketen wie
Als Nächstes erstellen Sie einen Einstiegspunkt: eine einzelne Funktion, die den Startpunkt Ihres Auftrags darstellt. Diese Funktion analysiert in der Regel alle Argumente, die an Ihren Auftrag übergeben wurden, und ruft anschließend die entsprechende Funktionalität aus Ihrem Paket auf. Das Parsen von Argumenten kann auf herkömmliche Weise mit argparse oder mit Tools wie click oder typer durchgeführt werden. Schließlich müssen Sie diese Funktion als console_script-Einstiegspunkt in Ihrer setup.cfg registrieren.
Eine praktische Anleitung zur Erstellung eines Python-Pakets und zur Registrierung eines Einstiegspunkts finden Sie hier.
Schritt 2: Erstellen Sie ein Rad
Sobald Sie Ihr Paket und den Einstiegspunkt erstellt haben, ist der nächste Schritt die Erstellung eines Wheels. Dies ist erforderlich, um Ihren Code auf einem Databricks-Cluster zu installieren:
python -m build . —wheel
Dadurch wird eine Datei mit dem Namen yourpackage_version_py3_none_any.whl in einem Verzeichnis namens dist/ erstellt. Diese Datei enthält den gesamten Code des Pakets und die entsprechenden Metadaten.
Jetzt können Sie dieses Rad auf das DBFS hochladen. Falls Sie das noch nicht getan haben, installieren und konfigurieren Sie die Databricks CLI. Das Hochladen Ihres Wheels ist dann eine Sache der Ausführung von
databricks fs cp dist/<…>.whl dbfs:/some/place/appropriate
Und schon sind Sie fertig!
Wenn Sie die Funktionen Ihres Rades interaktiv in einem Databricks-Notebook nutzen möchten, können Sie
%pip install --force "/dbfs/path/to/yourpackage-version-py3-none-any.whl"
Und importieren Sie anschließend alles aus Ihrem Paket mit
from yourpackage import …
Aber bitte - denken Sie nicht einmal daran, das in der Produktion einzusetzen!
Alternativ: PyPI
Noch besser als das Hochladen Ihres Wheels auf DBFS wäre es, es in einen privaten PyPI (Python Package Index) wie Artifactory hochzuladen. Dazu müssten Sie über einen solchen Index verfügen - und das Einrichten eines solchen ist kein Kinderspiel. Wenn Sie über einen solchen Index verfügen, können Sie den Schlüssel whl in den untenstehenden json-Dateien einfach durch etwas wie "pypi": { "package": "yourpackage", "repo": "https://my-pypi-mirror.com" } ersetzen.
Schritt 3: Definieren Sie einen Auftrag
Sobald Ihr Paket erstellt ist, ist es an der Zeit, Ihren Auftrag zu definieren. Sie müssen eine json-Datei erstellen, die Ihren Auftrag beschreibt. Hier ist ein minimales Beispiel, das Ihnen den Einstieg erleichtert:
{
"name": "my-job",
"existing_cluster_id": "1234-567890-reef123",
"libraries": [
{"whl": "dbfs:/path/to/yourpackage-version-py3-none-any.whl"}
],
"python_wheel_task": {
"package_name": "yourpackage",
"entry_point": "yourentrypoint",
"parameters": ["some", "parameters"]
}
}
Diese Datei legt fest, dass Ihr Rad installiert sein muss, um Ihren Auftrag ausführen zu können. Und sie legt fest, dass Ihr Einstiegspunkt aus Ihrem Paket mit einigen Parametern ausgeführt werden muss.
Leider ist eine gute, vollständige und lesbare Dokumentation über das genaue Format dieser Datei nicht zu finden. Als Alternative können Sie versuchen, einen Auftrag über die Web-Benutzeroberfläche zu erstellen und dann die json-Definition nachzuschlagen.
Eine häufige Änderung gegenüber dem obigen Beispiel ist, dass Sie keinen bestehenden Cluster angeben, sondern immer einen neuen Cluster erstellen, wenn der Auftrag gestartet wird:
{
"name": "my-job",
"new_cluster": {
"spark_version": "9.1.x-scala2.12",
"node_type_id": "i3.xlarge",
"num_workers": 25
},
"libraries": [
{"whl": "dbfs:/path/to/yourpackage-version-py3-none-any.whl"}
],
"python_wheel_task": {
"package_name": "yourpackage",
"entry_point": "yourentrypoint",
"parameters": ["some", "parameters"]
}
}
Sobald Sie die Auftragsdefinition haben, ist das Erstellen des Auftrags so einfach wie das Ausführen von
databricks jobs create —json-file job-config.json
Wenn der Auftrag bereits existiert und Sie ihn aktualisieren möchten, müssen Sie die Auftragsnummer herausfinden und dann die Konfiguration des Auftrags überschreiben:
JOB_NAME="my-job"
JOB_ID=$(databricks jobs list --output json | jq -r '[.jobs[] | select(.settings.name == env.JOB_NAME)][0] | .job_id')
databricks jobs reset --job-id "${JOB_ID}" --json-file job-config.json
Laufen und Planen
Jetzt, wo Sie Ihren Auftrag definiert haben, möchten Sie ihn wahrscheinlich ausführen. Sie können ihn über die Weboberfläche auslösen oder die Databricks-Befehlszeile verwenden:
databricks jobs run-now --job-id <your-job-id>
Sie können die Parameter sogar außer Kraft setzen, indem Sie --python-params angeben.
Jetzt bleibt nur noch eines: den Auftrag so zu planen, dass er automatisch zu den gewünschten Zeiten ausgeführt wird. Am einfachsten ist es, wenn Sie Ihrer Auftragskonfiguration einen Schlüssel schedule hinzufügen:
"schedule": {
"quartz_cron_expression": "45 6 12 * * ?",
"timezone_id": "UTC",
"pause_status": "UNPAUSED"
},
Dies würde Ihren Auftrag jeden Tag um 6 Minuten und 45 Sekunden nach Mittag in UTC planen. Die Details der Syntax von Quartz Cron finden Sie hier.
Schritt 4: Erweiterte Terminplanung
Wenn Sie genauer steuern möchten, wann Ihr Auftrag ausgeführt wird, gibt es mehrere Optionen. Sie können zum Beispiel einen Auftrag haben, der aus mehreren Aufgaben besteht: z.B. Dateneingabe und -aufbereitung, Modelltraining und Vorhersage. Eine Dokumentation finden Sie hier.
Wenn Sie zufällig eine Airflow-Instanz zur Verfügung haben, ist DatabricksSubmitRunOperator Ihr Freund. Es akzeptiert den Inhalt Ihrer job-config.json (als Wörterbuch und ohne den Schlüssel "Name") und definiert, führt und verfolgt Ihre Aufträge für Sie.
Einpacken
Ich hoffe, dass dieser Blog Ihnen genügend Anhaltspunkte gegeben hat, um einen Databricks-Job einzurichten und zu planen, und dass Sie nie wieder ein anderes Notebook in Produktion geben werden. Notebooks sind zwar sehr schön, um interaktiv mit Ihren Daten zu arbeiten, aber sie sind nicht die richtige Umgebung, um hochwertigen Code zu schreiben. Wenn Sie Ihren Code in ein Paket packen, Unit-Tests schreiben und Linting und Typprüfung anwenden - das schafft eine Umgebung, in der guter Code gedeiht.
Verfasst von
Rogier van der Geer
Unsere Ideen
Weitere Blogs
Contact



