Algorithmen, die Sie in Earth Engine erstellen, werden in der Google Cloud auf vielen Computern ausgeführt. Das Entfernen von Fehlern kann schwierig sein, da sie entweder im clientseitigen Code oder bei der serverseitigen Ausführung der codierten Anweisungen auftreten können und auf Skalierungsprobleme sowie syntaktische oder logische Fehler zurückzuführen sind. Die Programmteile, die irgendwo in der Cloud ausgeführt werden, können nur dann geprüft werden, wenn Sie danach fragen. In diesem Dokument werden Strategien, Tools und Lösungen zur Fehlerbehebung vorgestellt, mit denen Sie häufige Fehler beheben und Earth Engine-Scripts debuggen können.
Syntaxfehler
Syntaxfehler treten auf, wenn Ihr Code gegen die Regeln der Programmiersprache verstößt (entweder JavaScript oder Python in Earth Engine). Diese Fehler verhindern, dass Ihr Code ausgeführt wird, und werden in der Regel vor der Ausführung erkannt. Wenn Sie einen Syntaxfehler finden, prüfen Sie die markierte Zeile oder Fehlermeldung sorgfältig und sehen Sie sich Ressourcen wie die Python-Referenz oder den Google JavaScript-Stilguide an. Ein Code-Linter kann auch dabei helfen, diese Probleme zu identifizieren und zu beheben.
Clientseitige Fehler
Auch wenn der Code syntaktisch korrekt ist, können Fehler in Bezug auf die Konsistenz oder Logik des Scripts auftreten. In den folgenden Beispielen werden Fehler durch die Verwendung einer nicht vorhandenen Variablen und Methode veranschaulicht.
Fehler: Dieser Code funktioniert nicht.
// Load a Sentinel-2 image. var image = ee.Image('USGS/SRTMGL1_003'); // Error: "bandNames" is not defined in this scope. var display = image.visualize({bands: bandNames, min: 0, max: 9000}); // Error: image.selfAnalyze is not a function var silly = image.selfAnalyze();
import ee import geemap.core as geemap
# Load a Sentinel-2 image. image = ee.Image('USGS/SRTMGL1_003') # NameError: name 'band_names' is not defined. display = image.visualize(bands=band_names, min=0, max=9000) # AttributeError: 'Image' object has no attribute 'selfAnalyze'. silly = image.selfAnalyze()
Der erste Fehler informiert Sie darüber, dass die Variable bandNames
nicht im Gültigkeitsbereich definiert ist, in dem auf sie verwiesen wird. Als Lösung können Sie die Variable festlegen oder ein Listenargument für den Parameter bands
angeben. Der zweite Fehler zeigt, was passiert, wenn die nicht vorhandene selfAnalyze()
-Funktion aufgerufen wird. Da dies keine echte Methode für Bilder ist, wird durch den Fehler angezeigt, dass es sich nicht um eine Funktion handelt. In beiden Fällen beschreibt der Fehler das Problem.
Unbekannte Objekttypumwandlung
Der Fehler „...is not a function
“ kann darauf zurückzuführen sein, dass Earth Engine den Typ einer Variablen nicht kennt. Häufige Ursachen für dieses Problem:
- Eine Aktion auf ein Objekt ausführen, das von
first()
zurückgegeben wird (der Typ der Elemente in einer Sammlung ist unbekannt). - Es wird eine Aktion auf ein Objekt ausgeführt, das von
get()
zurückgegeben wird. Der Typ des Elements, das in einem Attribut gespeichert ist, ist unbekannt. - Wenn in einer Funktion etwas mit einem Funktionsargument gemacht wird, dessen Typ nicht bekannt ist.
Beispiel für Ersteres:
Fehler: Dieser Code funktioniert nicht.
var collection = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017'); // Error: collection.first(...).area is not a function var area = collection.first().area();
import ee import geemap.core as geemap
collection = ee.FeatureCollection('USDOS/LSIB_SIMPLE/2017') # AttributeError: 'Element' object has no attribute 'area'. area = collection.first().area()
Die Lösung besteht in jedem Fall darin, das Objekt mit unbekanntem Typ mit dem Konstruktor des bekannten Typs zu casten. Im Anschluss an das vorherige Beispiel besteht die Lösung darin, zu ee.Feature
zu casten:
Lösung: Verwenden Sie einen Stream.
var area = ee.Feature(collection.first()).area();
import ee import geemap.core as geemap
area = ee.Feature(collection.first()).area()
Hinweis: Sie können hier jede Methode auf Element
sicher aufrufen, da Earth Engine davon ausgeht, dass es sich um Element
handelt.
Client- und Serverfunktionen nicht mischen
Das folgende Beispiel ist weniger offensichtlich:
Fehler: Der Code führt nicht zu dem gewünschten Ergebnis.
// Don't mix EE objects and JavaScript objects. var image = ee.Image('USGS/SRTMGL1_003'); var nonsense = image + 2; // You can print this, but it's not what you were hoping for. print(nonsense); // Error: g.eeObject.name is not a function Map.addLayer(nonsense);
import ee import geemap.core as geemap
# Don't mix EE objects and Python objects. image = ee.Image('USGS/SRTMGL1_003') nonsense = image + 2 # TypeError: unsupported operand type(s) for +: 'Image' and 'int'. display(nonsense) # TypeError: unsupported operand type(s) for +: 'Image' and 'int'. m = geemap.Map() m.add_layer(nonsense) m
Angenommen, der Autor dieses Codes wollte jedem Pixel im Bild 2
hinzufügen, dann ist dies nicht die richtige Methode. Insbesondere wird in diesem Code ein serverseitiges Objekt (image
) fälschlicherweise mit einem clientseitigen Operator (+
) vermischt. Die Ergebnisse können überraschend sein. Im ersten Fall wird durch das Drucken von nonsense
im JavaScript-Code-Editor der angeforderte Vorgang (+
) ausgeführt, indem sowohl image
als auch 2
in Strings umgewandelt und dann zusammengefügt werden. Der resultierende String ist nicht beabsichtigt (in Python wird eine TypeError-Ausnahme geworfen).
Im zweiten Fall, wenn der Karte nonsense
hinzugefügt wird, wird im JavaScript-Code-Editor der kryptische Fehler g.eeObject.name is not a function
angezeigt, da das Objekt, das der Karte hinzugefügt wird, nonsense
, ein String und kein EE-Objekt ist (in Python wird eine TypeError-Ausnahme ausgelöst). Um möglicherweise unbeabsichtigte Ergebnisse und nicht aussagekräftige Fehler zu vermeiden, sollten Sie Serverobjekte und ‑funktionen nicht mit Clientobjekten, ‑primitiven oder ‑funktionen mischen. Die Lösung in diesem Beispiel besteht darin, eine Serverfunktion zu verwenden.
Lösung: Verwenden Sie eine Serverfunktion.
Map.addLayer(image.add(2));
import ee import geemap.core as geemap
m = geemap.Map() m.add_layer(image.add(2)) m
Weitere Informationen finden Sie auf der Seite Client und Server im Vergleich.
Browsersperre für den JavaScript-Code-Editor
Einfrieren oder Blockieren des Browsers kann auftreten, wenn die Ausführung von JavaScript im Client zu lange dauert oder wenn auf eine Antwort von Earth Engine gewartet wird. Zwei häufige Ursachen für diesen Fehler sind For-Schleifen und/oder getInfo()
im Code des JavaScript-Code-Editors. Im schlimmsten Fall befindet sich getInfo()
in einer For-Schleife. For-Schleifen können dazu führen, dass der Browser gesperrt wird, da der Code auf Ihrem Computer ausgeführt wird. getInfo()
hingegen fordert das Ergebnis einer Berechnung synchron von der Earth Engine an und blockiert, bis das Ergebnis empfangen wird. Wenn die Berechnung lange dauert, kann es durch die Blockierung dazu kommen, dass Ihr Browser gesperrt wird. Vermeiden Sie sowohl For-Schleifen als auch getInfo()
, wenn Sie im Code-Editor arbeiten. Weitere Informationen finden Sie auf der Seite Client und Server im Vergleich.
Serverfehler
Trotz logischer Konsistenz im Clientcode kann es zu Fehlern kommen, die erst zur Laufzeit auf dem Server auftreten. Das folgende Beispiel zeigt, was passiert, wenn versucht wird, einen nicht vorhandenen Kanal abzurufen.
Fehler: Dieser Code funktioniert nicht.
// Load a Sentinel-2 image. var s2image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR'); // Error: Image.select: Pattern 'nonBand' did not match any bands. print(s2image.select(['nonBand']));
import ee import geemap.core as geemap
# Load a Sentinel-2 image. s2image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR' ) # EEException: Image.select: Band pattern 'non_band' did not match any bands. print(s2image.select(['non_band']).getInfo())
In diesem Beispiel wird in der Fehlermeldung angegeben, dass es keine Band mit dem Namen nonBand
gibt. Die naheliegende Lösung besteht darin, einen Bandnamen anzugeben, der tatsächlich existiert. Sie können die Bandnamen ermitteln, indem Sie das Bild ausdrucken und in der Konsole ansehen oder indem Sie die Liste der Bandnamen ausdrucken, die von image.bandNames()
zurückgegeben wird.
Unveränderlichkeit
Serverseitige Objekte, die Sie in Earth Engine erstellen, sind immutable. (Jede ee.Object
ist eine serverseitige Object
). Wenn Sie also eine Änderung am Objekt vornehmen möchten, müssen Sie den geänderten Status in einer neuen Variablen speichern. So können Sie beispielsweise keine Property für das Sentinel-2-Bild festlegen:
Fehler: Dieser Code funktioniert nicht wie gewünscht.
var s2image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR'); s2image.set('myProperty', 'This image is not assigned to a variable'); // This will not result in an error, but will not find 'myProperty'. print(s2image.get('myProperty')); // null
import ee import geemap.core as geemap
s2image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20160625T100617_20160625T170310_T33UVR' ) s2image.set('my_property', 'This image is not assigned to a variable') # This will not result in an error, but will not find 'my_property'. display(s2image.get('my_property')) # None
In diesem Beispiel gibt s2image.set()
eine Kopie des Bildes mit der neuen Eigenschaft zurück, das in der Variablen s2image
gespeicherte Bild bleibt jedoch unverändert. Sie müssen das von s2image.set()
zurückgegebene Bild in einer neuen Variablen speichern. Beispiel:
Lösung: Speichern Sie das Ergebnis in einer Variablen.
s2image = s2image.set('myProperty', 'OK'); print(s2image.get('myProperty')); // OK
import ee import geemap.core as geemap
s2image = s2image.set('my_property', 'OK') display(s2image.get('my_property')) # OK
Zugeordnete Funktionen
Ein weiterer Kontext, in dem Client- und Serverfunktionen nicht miteinander kombiniert werden, sind zugeordnete Funktionen. Insbesondere werden die von der zugeordneten Funktion angegebenen Vorgänge in der Cloud ausgeführt. Daher funktionieren Clientfunktionen wie getInfo
und Export
(sowie print
und die Methode für Map
und Chart
im JavaScript-Code-Editor) in zugeordneten Funktionen nicht. Beispiel:
Fehler: Dieser Code funktioniert nicht.
var collection = ee.ImageCollection('MODIS/006/MOD44B'); // Error: A mapped function's arguments cannot be used in client-side operations var badMap3 = collection.map(function(image) { print(image); return image; });
import ee import geemap.core as geemap
collection = ee.ImageCollection('MODIS/006/MOD44B') # Error: A mapped function's arguments cannot be used in client-side operations. bad_map_3 = collection.map(lambda image: print(image.getInfo()))
Dieser etwas kryptische Fehler ist auf den Prozess zurückzuführen, mit dem Earth Engine diesen Code in eine Reihe von Anweisungen umwandelt, die auf Google-Servern ausgeführt werden können. Clientseitige Funktionen und Kontrollstrukturen können nicht verwendet werden, um das an die zugeordnete Funktion übergebene Argumentbild zu bearbeiten. Verwenden Sie daher keine clientseitigen Funktionen in zugeordneten Funktionen. Auf der Seite Client und Server im Vergleich finden Sie weitere Informationen zum Unterschied zwischen Client- und Serverfunktionen.
Für zugeordnete Funktionen gelten zusätzliche Anforderungen. So müssen beispielsweise zugeordnete Funktionen etwas zurückgeben:
Fehler: Dieser Code funktioniert nicht.
var collection = ee.ImageCollection('MODIS/006/MOD44B'); // Error: User-defined methods must return a value. var badMap1 = collection.map(function(image) { // Do nothing. });
import ee import geemap.core as geemap
collection = ee.ImageCollection('MODIS/006/MOD44B') # Error: User-defined methods must return a value. bad_map_1 = collection.map(lambda image: None)
Die naheliegende Lösung ist, etwas zurückzugeben. Es kann aber nicht einfach irgendetwas zurückgeben. Insbesondere müssen Funktionen, die über eine ImageCollection
oder FeatureCollection
zugeordnet sind, eine Image
oder Feature
zurückgeben. So können Sie beispielsweise kein Datum aus einer Funktion zurückgeben, die auf eine ImageCollection
angewendet wird:
Fehler: Dieser Code funktioniert nicht.
var collection = ee.ImageCollection('MODIS/006/MOD44B'); var badMap2 = collection.map(function(image) { return image.date(); }); // Error: Collection.map: A mapped algorithm must return a Feature or Image. print(badMap2);
import ee import geemap.core as geemap
collection = ee.ImageCollection('MODIS/006/MOD44B') bad_map_2 = collection.map(lambda image: image.date()) # EEException: Collection.map: # A mapped algorithm must return a Feature or Image. print(bad_map_2.getInfo())
Um dies zu vermeiden, geben Sie das Eingabebild mit einem neuen Property-Set zurück. Wenn Sie eine Liste der Datumsangaben der Bilder in der Sammlung benötigen, können Sie aggregate_array()
verwenden:
Lösung: Legen Sie eine Property fest.
var collection = ee.ImageCollection('MODIS/006/MOD44B'); var okMap2 = collection.map(function(image) { return image.set('date', image.date()); }); print(okMap2); // Get a list of the dates. var datesList = okMap2.aggregate_array('date'); print(datesList);
import ee import geemap.core as geemap
collection = ee.ImageCollection('MODIS/006/MOD44B') ok_map_2 = collection.map(lambda image: image.set('date', image.date())) print(ok_map_2.getInfo()) # Get a list of the dates. dates_list = ok_map_2.aggregate_array('date') print(dates_list.getInfo())
Verfahrensfehler
Muster wurde auf ein Bild ohne Streifen angewendet
Der Fehler "Pattern 'my_band' was applied to an Image with no bands"
bedeutet, dass ein ee.Image.select()
-Aufruf für ein Bild mit einer leeren Bandliste erfolgt. So können Sie das Problem beheben:
- Wenn das Bild aus einer ImageCollection mit einem Reducer oder mit den Aufrufen
first()
odertoBands()
erstellt wird, darf die Quellsammlung nicht leer sein. - Wenn das Bild mit
ee.Dictionary().toImage()
aus einem Wörterbuch erstellt wird, darf das Wörterbuch nicht leer sein. - Wenn das Bild eigenständig ist, muss es Daten enthalten und darf nicht nur
ee.Image(0)
enthalten.
Skalierungsfehler
Auch wenn ein Script syntaktisch korrekt und ohne logische Fehler ist und eine gültige Anweisungsliste für den Server darstellt, können die resultierenden Objekte bei der Parallelisierung und Ausführung der Berechnung zu groß, zu zahlreich oder zu lang für die Berechnung sein. In diesem Fall erhalten Sie die Fehlermeldung, dass der Algorithmus nicht skaliert werden kann. Diese Fehler sind in der Regel am schwierigsten zu diagnostizieren und zu beheben. Beispiele für diese Art von Fehlern:
- Zeitüberschreitung bei der Berechnung
- Zu viele gleichzeitige Aggregationen
- Speicherlimit für Nutzer überschritten
- Interner Fehler
Wenn Sie die Skalierung Ihres Codes verbessern, erhalten Sie schneller Ergebnisse und die Verfügbarkeit von Rechenressourcen für alle Nutzer wird verbessert. In den folgenden Abschnitten werden die einzelnen Fehlertypen erläutert. Vorab ein kurzer Hinweis zu reduceRegion()
, einer häufig verwendeten Funktion, die für alle Arten von Skalierungsfehlern bekannt ist.
reduceRegion()
Obwohl reduceRegion()
so viele Pixel verbraucht, dass eine Vielzahl von Fehlern ausgelöst wird, gibt es auch Parameter, mit denen die Berechnung gesteuert werden kann, um die Fehler zu vermeiden. Betrachten Sie beispielsweise die folgende unzulässige Kürzung:
Fehler: Dieser Code funktioniert nicht.
var absurdComputation = ee.Image(1).reduceRegion({ reducer: 'count', geometry: ee.Geometry.Rectangle([-180, -90, 180, 90], null, false), scale: 100, }); // Error: Image.reduceRegion: Too many pixels in the region. // Found 80300348117, but only 10000000 allowed. print(absurdComputation);
import ee import geemap.core as geemap
absurd_computation = ee.Image(1).reduceRegion( reducer='count', geometry=ee.Geometry.Rectangle([-180, -90, 180, 90], None, False), scale=100, ) # EEException: Image.reduceRegion: Too many pixels in the region. # Found 80300348117, but only 10000000 allowed. print(absurd_computation.getInfo())
Dieses dumme Beispiel dient nur zur Veranschaulichung. Mit diesem Fehler werden Sie gefragt, ob Sie wirklich 803.003.481.17 Pixel (80 Milliarden) reduzieren möchten. Falls nicht, erhöhen Sie scale
(Pixelgröße in Metern) entsprechend oder setzen Sie bestEffort
auf „wahr“, um automatisch einen größeren Maßstab zu berechnen. Weitere Informationen zu diesen Parametern finden Sie auf der Seite reduceRegion()
.
Zeitüberschreitung bei der Berechnung
Angenommen, Sie benötigen alle diese Pixel für Ihre Berechnung. In diesem Fall können Sie den Parameter maxPixels
erhöhen, damit die Berechnung erfolgreich abgeschlossen werden kann. Es dauert jedoch einige Zeit, bis die Berechnung in der Earth Engine abgeschlossen ist. Dies kann zu einem Fehler vom Typ „Berechnung hat Zeitüberschreitung verursacht“ führen:
Schlecht: Tun Sie das nicht!
var ridiculousComputation = ee.Image(1).reduceRegion({ reducer: 'count', geometry: ee.Geometry.Rectangle([-180, -90, 180, 90], null, false), scale: 100, maxPixels: 1e11 }); // Error: Computation timed out. print(ridiculousComputation);
import ee import geemap.core as geemap
ridiculous_computation = ee.Image(1).reduceRegion( reducer='count', geometry=ee.Geometry.Rectangle([-180, -90, 180, 90], None, False), scale=100, maxPixels=int(1e11), ) # Error: Computation timed out. print(ridiculous_computation.getInfo())
Das bedeutet, dass Earth Engine etwa fünf Minuten gewartet hat, bevor die Berechnung beendet wurde. Durch den Export kann Earth Engine die Berechnung in einer Umgebung mit längeren zulässigen Laufzeiten (aber nicht mit mehr Arbeitsspeicher) ausführen. Da der Rückgabewert von reduceRegion()
ein Wörterbuch ist, können Sie mit dem Wörterbuch die Eigenschaften eines Features mit Nullgeometrie festlegen:
Gut – verwenden Sie Export
.
Export.table.toDrive({ collection: ee.FeatureCollection([ ee.Feature(null, ridiculousComputation) ]), description: 'ridiculousComputation', fileFormat: 'CSV' });
import ee import geemap.core as geemap
task = ee.batch.Export.table.toDrive( collection=ee.FeatureCollection([ee.Feature(None, ridiculous_computation)]), description='ridiculous_computation', fileFormat='CSV', ) # task.start()
Zu viele gleichzeitige Aggregationen
Der Teil „Aggregationen“ dieses Fehlers bezieht sich auf Vorgänge, die auf mehrere Maschinen verteilt sind, z. B. Reduktionen, die mehr als eine Kachel umfassen. In Earth Engine gibt es Limits, die verhindern, dass zu viele dieser Aggregationen gleichzeitig ausgeführt werden. In diesem Beispiel wird der Fehler „Zu viele gleichzeitige Aggregationen“ durch eine Reduzierung innerhalb einer Karte ausgelöst:
Schlecht: Tun Sie das nicht!
var collection = ee.ImageCollection('LANDSAT/LT05/C02/T1') .filterBounds(ee.Geometry.Point([-123, 43])); var terribleAggregations = collection.map(function(image) { return image.set(image.reduceRegion({ reducer: 'mean', geometry: image.geometry(), scale: 30, maxPixels: 1e9 })); }); // Error: Quota exceeded: Too many concurrent aggregations. print(terribleAggregations);
import ee import geemap.core as geemap
collection = ee.ImageCollection('LANDSAT/LT05/C02/T1').filterBounds( ee.Geometry.Point([-123, 43]) ) def apply_mean_aggregation(image): return image.set( image.reduceRegion( reducer='mean', geometry=image.geometry(), scale=30, maxPixels=int(1e9), ) ) terrible_aggregations = collection.map(apply_mean_aggregation) # EEException: Computation timed out. print(terrible_aggregations.getInfo())
Angenommen, der Zweck dieses Codes besteht darin, Bildstatistiken für jedes Bild abzurufen, ist eine mögliche Lösung, das Ergebnis zu Export
. Angenommen, ein ImageCollection
ist auch ein FeatureCollection
. Dann können die zu den Bildern gehörenden Metadaten als Tabelle exportiert werden:
Gut – verwenden Sie Export
.
Export.table.toDrive({ collection: terribleAggregations, description: 'terribleAggregations', fileFormat: 'CSV' });
import ee import geemap.core as geemap
task = ee.batch.Export.table.toDrive( collection=terrible_aggregations, description='terrible_aggregations', fileFormat='CSV', ) # task.start()
Speicherlimit für Nutzer überschritten
Eine Möglichkeit, wie Ihre Algorithmen in Earth Engine parallelisiert werden, besteht darin, die Eingaben in Kacheln aufzuteilen, dieselbe Berechnung für jede Kachel separat auszuführen und dann die Ergebnisse zu kombinieren. Daher müssen alle Eingaben, die zur Berechnung einer Ausgabekachel erforderlich sind, in den Arbeitsspeicher passen. Wenn die Eingabe beispielsweise ein Bild mit vielen Bändern ist, kann das viel Arbeitsspeicher verbrauchen, wenn alle Bänder bei der Berechnung verwendet werden. Zur Veranschaulichung wird in diesem Beispiel zu viel Arbeitsspeicher verbraucht, da eine ganze Bildsammlung (unnötigerweise) in eine Kachel gepackt wird:
Schlecht: Tun Sie das nicht!
var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']; var memoryHog = ee.ImageCollection('LANDSAT/LT05/C02/T1').select(bands) .toArray() .arrayReduce(ee.Reducer.mean(), [0]) .arrayProject([1]) .arrayFlatten([bands]) .reduceRegion({ reducer: 'mean', geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale: 1, bestEffort: true, }); // Error: User memory limit exceeded. print(memoryHog);
import ee import geemap.core as geemap
bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'] memory_hog = ( ee.ImageCollection('LANDSAT/LT05/C02/T1') .select(bands) .toArray() .arrayReduce(ee.Reducer.mean(), [0]) .arrayProject([1]) .arrayFlatten([bands]) .reduceRegion( reducer=ee.Reducer.mean(), geometry=ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale=1, bestEffort=True, ) ) # EEException: User memory limit exceeded. print(memory_hog.getInfo())
Dieser sehr schlechte Code ist ein Beispiel dafür, warum Arrays nur dann verwendet werden sollten, wenn es wirklich notwendig ist (siehe auch Abschnitt „Unnötige Typumwandlung vermeiden“). Wenn diese Sammlung in ein riesiges Array umgewandelt wird, muss das Array auf einmal in den Arbeitsspeicher geladen werden. Da es sich um eine lange Zeitreihe von Bildern handelt, ist das Array groß und passt nicht in den Arbeitsspeicher.
Eine mögliche Lösung besteht darin, den Parameter tileScale
auf einen höheren Wert festzulegen. Höhere Werte für „tileScale“ führen zu Kacheln, die um den Faktor tileScale^2
kleiner sind. Mit folgendem Code kann die Berechnung beispielsweise erfolgreich durchgeführt werden:
var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']; var smallerHog = ee.ImageCollection('LANDSAT/LT05/C02/T1').select(bands) .toArray() .arrayReduce(ee.Reducer.mean(), [0]) .arrayProject([1]) .arrayFlatten([bands]) .reduceRegion({ reducer: 'mean', geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale: 1, bestEffort: true, tileScale: 16 }); print(smallerHog);
import ee import geemap.core as geemap
bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'] smaller_hog = ( ee.ImageCollection('LANDSAT/LT05/C02/T1') .select(bands) .toArray() .arrayReduce(ee.Reducer.mean(), [0]) .arrayProject([1]) .arrayFlatten([bands]) .reduceRegion( reducer=ee.Reducer.mean(), geometry=ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale=1, bestEffort=True, tileScale=16, ) ) print(smaller_hog.getInfo())
Die beste Lösung besteht jedoch darin, Arrays nicht unnötig zu verwenden, damit Sie sich nicht mit tileScale
herumschlagen müssen:
Gut: Vermeiden Sie Arrays!
var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7']; var okMemory = ee.ImageCollection('LANDSAT/LT05/C02/T1').select(bands) .mean() .reduceRegion({ reducer: 'mean', geometry: ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale: 1, bestEffort: true, }); print(okMemory);
import ee import geemap.core as geemap
bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7'] ok_memory = ( ee.ImageCollection('LANDSAT/LT05/C02/T1') .select(bands) .mean() .reduceRegion( reducer=ee.Reducer.mean(), geometry=ee.Geometry.Point([-122.27, 37.87]).buffer(1000), scale=1, bestEffort=True, ) ) print(ok_memory.getInfo())
Sofern nicht erforderlich, um einen Speicherfehler zu beheben, sollten Sie tileScale
nicht festlegen, da kleinere Kacheln auch zu einem höheren Parallelisierungsaufwand führen.
Interne Fehler
Möglicherweise wird ein Fehler wie der folgende angezeigt:
Wenn dieser Fehler auftritt, klicken Sie in der Konsole des JavaScript-Code-Editors auf den Link „Fehler melden“. Du kannst auch über die Schaltfläche Hilfe Feedback geben. Dieser Fehler kann durch logische Fehler in Ihrem Script verursacht werden, die erst zur Laufzeit auffallen, oder durch ein Problem mit der Funktionsweise von Earth Engine. In beiden Fällen ist der Fehler nicht aussagekräftig und sollte gemeldet werden, damit er behoben werden kann.
Interne Fehler enthalten eine request
-ID, z. B.:
Diese Strings dienen als eindeutige Kennung, damit das Earth Engine-Team bestimmte Probleme identifizieren kann. Fügen Sie diesen String in Fehlerberichte ein.
Debugging-Methoden
Sie haben Ihre Analyse programmiert, ausgeführt und einen Fehler erhalten. Was heißt das für die Zukunft? In diesem Abschnitt werden allgemeine Techniken zur Fehlerbehebung beschrieben, mit denen Sie das Problem eingrenzen und beheben können.
Variablen und Kartenebenen prüfen
Angenommen, Sie haben eine sehr komplexe Analyse, die einen Fehler verursacht. Wenn nicht klar ist, woher der Fehler stammt, ist es eine gute Strategie, Zwischenobjekte zu drucken oder zu visualisieren und zu prüfen, ob die Struktur des Objekts mit der Logik in Ihrem Script übereinstimmt. Insbesondere können Sie die Pixelwerte von Ebenen prüfen, die der Karte mit dem Code-Editor oder den geemap-Inspektionstools hinzugefügt wurden. Wenn Sie etwas drucken, sollten Sie die Eigenschaften mit den Zip-Symbolen (▶) maximieren. Prüfen Sie Folgendes:
- Bandnamen Stimmen die Namen der Bildstreifen mit Ihrem Code überein?
- Pixelwerte Haben Ihre Daten den richtigen Bereich? Ist es angemessen maskiert?
- Null. Sind Werte auf „null“ gesetzt, die es nicht sein sollten?
- Größen Ist die Größe „0“, obwohl das nicht der Fall sein sollte?
aside()
Es kann mühsam sein, jeden Zwischenschritt einer Analyse in eine Variable zu setzen, damit er gedruckt und geprüft werden kann. Mit der Methode aside()
können Sie Zwischenwerte aus einer langen Kette von Funktionsaufrufen drucken. Beispiel:
var image = ee.Image(ee.ImageCollection('COPERNICUS/S2') .filterBounds(ee.Geometry.Point([-12.29, 168.83])) .aside(print) .filterDate('2011-01-01', '2016-12-31') .first());
import ee import geemap.core as geemap
image = ee.Image( ee.ImageCollection('COPERNICUS/S2_HARMONIZED') .filterBounds(ee.Geometry.Point([-12.29, 168.83])) .aside(display) .filterDate('2011-01-01', '2016-12-31') .first() )
Denken Sie daran, dass aside(print)
(JavaScript-Code-Editor) und aside(display)
(Python-geemap) clientseitige Funktionen aufrufen und dass es weiterhin bei zugeordneten Funktionen zu Fehlern kommt. Sie können „aside“ auch mit benutzerdefinierten Funktionen verwenden. Beispiel:
var composite = ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') .filterBounds(ee.Geometry.Point([106.91, 47.91])) .map(function(image) { return image.addBands(image.normalizedDifference(['B5', 'B4'])); }) .aside(Map.addLayer, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'collection') .qualityMosaic('nd'); Map.setCenter(106.91, 47.91, 11); Map.addLayer(composite, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'composite');
import ee import geemap.core as geemap
m = geemap.Map() m.set_center(106.91, 47.91, 11) composite = ( ee.ImageCollection('LANDSAT/LC08/C02/T1_TOA') .filterBounds(ee.Geometry.Point([106.91, 47.91])) .map(lambda image: image.addBands(image.normalizedDifference(['B5', 'B4']))) .aside(m.add_layer, {'bands': ['B4', 'B3', 'B2'], 'max': 0.3}, 'collection') .qualityMosaic('nd') ) m.add_layer(composite, {'bands': ['B4', 'B3', 'B2'], 'max': 0.3}, 'composite') m
Funktion auf first()
ausführen
Drucken und Visualisieren sind nützlich für das Debugging, sofern verfügbar. Wenn Sie jedoch eine Funktion debuggen, die auf eine Sammlung zugeordnet ist, können Sie nicht in der Funktion drucken, wie im Abschnitt zu zugeordneten Funktionen beschrieben. In diesem Fall ist es hilfreich, problematische Elemente in der Sammlung zu isolieren und die zugeordnete Funktion an einem einzelnen Element zu testen. Wenn Sie die Funktion ohne Zuordnung testen, können Sie mithilfe von Print-Anweisungen das Problem nachvollziehen. Dazu ein Beispiel:
Fehler: Dieser Code funktioniert nicht.
var image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20150821T111616_20160314T094808_T30UWU'); var someFeatures = ee.FeatureCollection([ ee.Feature(ee.Geometry.Point([-2.02, 48.43])), ee.Feature(ee.Geometry.Point([-2.80, 48.37])), ee.Feature(ee.Geometry.Point([-1.22, 48.29])), ee.Feature(ee.Geometry.Point([-1.73, 48.65])), ]); var problem = someFeatures.map(function(feature) { var dictionary = image.reduceRegion({ reducer: 'first', geometry: feature.geometry(), scale: 10, }); return feature.set({ result: ee.Number(dictionary.get('B5')) .divide(dictionary.get('B4')) }); }); // Error in map(ID=2): // Number.divide: Parameter 'left' is required. print(problem);
import ee import geemap.core as geemap
image = ee.Image( 'COPERNICUS/S2_HARMONIZED/20150821T111616_20160314T094808_T30UWU' ) some_features = ee.FeatureCollection([ ee.Feature(ee.Geometry.Point([-2.02, 48.43])), ee.Feature(ee.Geometry.Point([-2.80, 48.37])), ee.Feature(ee.Geometry.Point([-1.22, 48.29])), ee.Feature(ee.Geometry.Point([-1.73, 48.65])), ]) # Define a function to be mapped over the collection. def function_to_map(feature): dictionary = image.reduceRegion( reducer=ee.Reducer.first(), geometry=feature.geometry(), scale=10 ) return feature.set( {'result': ee.Number(dictionary.get('B5')).divide(dictionary.get('B4'))} ) problem = some_features.map(function_to_map) # EEException: Error in map(ID=2): # Number.divide: Parameter 'left' is required. print(problem.getInfo())
Zur Fehlerbehebung ist es hilfreich, den Fehler zu untersuchen. Glücklicherweise informiert Sie dieser hilfreiche Fehler darüber, dass ein Problem mit der Funktion mit ID=2
vorliegt. Für weitere Untersuchungen ist es hilfreich, den Code etwas zu überarbeiten. Insbesondere dürfen in der Funktion keine Print-Anweisungen vorhanden sein, wenn sie wie in diesem Abschnitt beschrieben auf eine Sammlung angewendet wird. Ziel des Debuggings ist es, die problematische Funktion zu isolieren und die Funktion mit einigen Print-Anweisungen auszuführen. Mit demselben Bild und denselben Funktionen wie zuvor:
// Define a function to be mapped over the collection. var functionToMap = function(feature) { var dictionary = image.reduceRegion({ reducer: 'first', geometry: feature.geometry(), scale: 10, }); // Debug: print(dictionary); return feature.set({ result: ee.Number(dictionary.get('B5')) .divide(dictionary.get('B4')) }); }; // Isolate the feature that's creating problems. var badFeature = ee.Feature(someFeatures .filter(ee.Filter.eq('system:index', '2')) .first()); // Test the function with print statements added. functionToMap(badFeature); // Inspect the bad feature in relation to the image. Map.centerObject(badFeature, 11); Map.addLayer(badFeature, {}, 'bad feature'); Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], max: 3000}, 'image');
import ee import geemap.core as geemap
# Define a function to be mapped over the collection. def function_to_map(feature): dictionary = image.reduceRegion( reducer=ee.Reducer.first(), geometry=feature.geometry(), scale=10 ) # Debug: display(dictionary) return feature.set( {'result': ee.Number(dictionary.get('B5')).divide(dictionary.get('B4'))} ) # Isolate the feature that's creating problems. bad_feature = ee.Feature( some_features.filter(ee.Filter.eq('system:index', '2')).first() ) # Test the function with print statements added. function_to_map(bad_feature) # Inspect the bad feature in relation to the image. m = geemap.Map() m.center_object(bad_feature, 11) m.add_layer(bad_feature, {}, 'bad feature') m.add_layer(image, {'bands': ['B4', 'B3', 'B2'], 'max': 3000}, 'image') m
Da die Funktion nur für eine einzelne Entität ausgeführt wird, können Sie einen Print-Aufruf (`display` für Python geemap) einfügen. Bei der Prüfung des gedruckten Objekts stellen Sie fest, dass das von reduceRegion()
zurückgegebene Objekt für jede Band Nullwerte enthält. Das erklärt, warum die Division fehlschlägt: Null kann nicht durch Null geteilt werden. Warum ist der Wert überhaupt null?
Fügen Sie zur Untersuchung das Eingabebild und das fehlerhafte Element zur Karte hinzu und zentrieren Sie die Karte auf das fehlerhafte Element. Dabei stellen Sie fest, dass das Problem darauf zurückzuführen ist, dass sich der Punkt außerhalb des Bildes befindet. Auf dieser Grundlage lautet der behobene Code:
var functionToMap = function(feature) { var dictionary = image.reduceRegion({ reducer: 'first', geometry: feature.geometry(), scale: 10, }); return feature.set({ result: ee.Number(dictionary.get('B5')) .divide(dictionary.get('B4')) }); }; var noProblem = someFeatures .filterBounds(image.geometry()) .map(functionToMap); print(noProblem);
import ee import geemap.core as geemap
def function_to_map(feature): dictionary = image.reduceRegion( reducer=ee.Reducer.first(), geometry=feature.geometry(), scale=10 ) return feature.set( {'result': ee.Number(dictionary.get('B5')).divide(dictionary.get('B4'))} ) no_problem = some_features.filterBounds(image.geometry()).map(function_to_map) display(no_problem)
Profiler
Der Profiler liefert Informationen zur EECU-Zeit und zur Speichernutzung (pro Algorithmus und Asset), die durch die Berechnung entstehen, die ausgeführt wird, während er aktiviert ist. Die Einträge oben im Profiler enthalten Informationen zu den ressourcenintensivsten Vorgängen. Bei lang laufenden oder ineffizienten Scripts geben die Einträge oben im Profiler Hinweise darauf, wo Sie sich bei der Optimierung des Scripts konzentrieren sollten. Wichtiger Hinweis: Der Profiler selbst beeinflusst die Leistung des Scripts. Daher sollten Sie ihn nur ausführen, wenn es unbedingt erforderlich ist.