Beim Umgang mit GeoSpatial-Daten in Python verwende ich häufig GeoPandas für kleine bis mittlere Daten, aber beim Umgang mit großen Daten gibt es Grenzen. .. Dann scheint es, dass die Erweiterungsfunktion von PostgreSQL PostGIS häufig verwendet wird, und wenn es sich um NoSQL handelt, kann der Geometrietyp beispielsweise auch in MongoDB verwendet werden. Ja (Referenz), aber ich habe eine Datenbank gestartet, ein Schema vorbereitet und eine Tabelle oder Sammlung erstellt. Ist ziemlich mühsam und ich interessiere mich für diesen Bereich, aber ich habe ihn noch nicht berührt.
Persönlich verwende ich häufig pyspark für die Datenverarbeitung in großem Maßstab. Kann ich also etwas damit anfangen? Als ich suchte, fand ich etwas namens GeoSpark.
Es scheint, dass sich die Bibliothek noch entwickelt, aber wie Sie sehen können, im Jahr 2020-07-19 (* Datum des Artikelschreibens: 2020-08-08) unter dem Namen Apache Sedona, [Apache Incubator](https: //) Es ist in inkubator.apache.org/) registriert. (Ich bin nicht sehr vertraut damit, aber es scheint, dass wenn es gut anfängt, es ein formelles Apache-Projekt wird. Da das Management auf die Apache-Seite verlagert wird, denke ich, dass die oben genannten Repository-Dokumente auch bald verschoben werden. .)
Es scheint ziemlich interessant zu sein, Daten mit einem Gefühl zu verarbeiten, das Pandas und Geopandas relativ nahe kommt (es kann mit einem geeigneten Gefühl ohne Schemadesign verwendet werden), während ich die Möglichkeit habe, große Datenmengen zu verarbeiten, also habe ich ein wenig damit gespielt. ist.
Umwelt zur Hand: Linux(Ubuntu20.04) (Obwohl weggelassen, können Sie es unter Windows in fast der gleichen Atmosphäre machen.)
Ich habe die Python-Umgebung mit pyenv
+ miniconda3
(dh conda) vorbereitet, aber ich denke, alles ist in Ordnung.
Bereiten Sie beispielsweise die folgende YAML-Datei vor:
create_env.yml
name: geospark_demo
channels:
- conda-forge
- defaults
dependencies:
- python==3.7.*
- pip
- jupyterlab # for test
- pyspark==2.4.*
- openjdk==8.*
- pyarrow
- pandas
- geopandas
- folium # for test
- matplotlib # for test
- descartes # for test
- pip:
- geospark
pyspark
und java8
sind nicht erforderlich, wenn Sie Ihre eigenen vorbereitet habengeospark (1.3.1 )
unterstützte Version von Apache Spark zum Zeitpunkt des Schreibens (August 2020) 2.2 - bis 2.4 series. geospark-sql-python / # apache-spark), also gibt pyspark
die 2.4-Serie anmit diesem
conda env create -f create_env.yml
#Geben Sie die erstellte virtuelle Umgebung ein
conda activate geospark_demo
Anschließend können Sie eine virtuelle Conda-Umgebung mit dem Namen "geospark_demo" erstellen. (Informationen zu verschiedenen Anpassungen wie Paketen und Namen virtueller Umgebungen finden Sie beispielsweise unter hier. ) (Ich denke, Sie können das gleiche tun, ohne Conda zu verwenden)
Im obigen Beispiel (unter Verwendung der virtuellen Umgebung von conda) werden die Einstellungen "PATH" und "JAVA_HOME" ohne Erlaubnis vorgenommen, es müssen jedoch einige zusätzliche Umgebungsvariablen festgelegt werden.
Zunächst bezieht sich Geospark manchmal intern auf "SPARK_HOME". Legen Sie daher den Installationsort von Apache Spark mit der Umgebungsvariablen fest. Wenn Apache Spark wie in diesem Beispiel mit conda usw. installiert wird, kann es außerdem schwierig sein zu wissen, wo sich der Hauptteil von Spark befindet, z. B. hier. How-to-Find-Funken-Installationsverzeichnis)
#Überprüfen Sie den Installationsort von Apache Spark
echo 'sc.getConf.get("spark.home")' | spark-shell
# SPARK_HOME-Einstellungen
export SPARK_HOME=<Der Weg, der oben herauskam>
Stellen Sie so ein. Der Autor sieht aus wie "SPARK_HOME = / home /
Wenn die installierte "Pyarrow" -Version 0.15 oder höher ist, [hier](https://spark.apache.org/docs/2.4.6/sql-pyspark-pandas-with-arrow.html#compatibiliy " -setting-for-pyarrow - 0150-and-spark-23x-24x)
export ARROW_PRE_0_15_IPC_FORMAT=1
Es muss eingestellt werden (Einstellung für die pyspark 2.x-Serie erforderlich). Alternativ können Sie "pyarrow == 0.14. *" Angeben, um es zu installieren.
Es ist mühsam, es von Hand zu machen, also schreibe ich es persönlich in eine Datei und mache es zu "Quelle" oder setze es mit Docker unter Verwendung von "ENV" usw.
Jupyter Notebook für Python und die erforderlichen Testdaten (gespeichert in python / data /
) werden auf Official GitHub abgelegt. Verwenden Sie sie also, um sicherzustellen, dass es gut funktioniert.
Zum Beispiel
#Wechseln Sie in das Arbeitsverzeichnis
cd /path/to/workdir
#Laden Sie das Notizbuch von github herunter
wget https://raw.githubusercontent.com/DataSystemsLab/GeoSpark/master/python
/GeoSparkCore.ipynb
wget https://raw.githubusercontent.com/DataSystemsLab/GeoSpark/master/python/GeoSparkSQL.ipynb
#Laden Sie mit svn nur bestimmte Verzeichnisse von github herunter
svn export https://github.com/DataSystemsLab/GeoSpark/trunk/python/data/
Sie können es so bekommen. Sie können das Verzeichnis von GitHub mit svn hier oder hier herunterladen. Ich bezog mich auf.
Starten Sie danach jupyter lab oder jupyter notebook und führen Sie ↑ notebook aus. Ich denke, dies ist eine Referenz für die Art der Atmosphäre, die Sie bei der Überprüfung des Betriebs verwenden können.
Das Notizbuch und das offizielle Dokument Tutorial, die bei der Funktionsprüfung von ↑ verwendet werden, sind nützlicher, aber es ist eine große Sache. Ich werde selbst ein bisschen spielen.
Verwenden Sie die [National Municipal Boundary Data] von esri Japan (https://www.esrij.com/products/japan-shp/). Wenn Sie am Linkziel auf "Datei herunterladen" klicken und "Zustimmen" aktivieren, können Sie die shp-Datei in Form von "japan_ver821.zip" abrufen. Entpacken Sie sie also in das Arbeitsverzeichnis und legen Sie sie ab.
Versuche Folgendes:
Unten haben wir die Operation auf jupyterlab bestätigt.
#Importieren Sie die erforderlichen Bibliotheken
import os
import folium
import geopandas as gpd
from pyspark.sql import SparkSession
from geospark.register import GeoSparkRegistrator
from geospark.utils import GeoSparkKryoRegistrator, KryoSerializer
from geospark.register import upload_jars
#Funken-Sitzung generieren
upload_jars()
spark = SparkSession.builder.\
master("local[*]").\
appName("TestApp").\
config("spark.serializer", KryoSerializer.getName).\
config("spark.kryo.registrator", GeoSparkKryoRegistrator.getName) .\
getOrCreate()
GeoSparkRegistrator.registerAll(spark)
sdf_japan = spark.createDataFrame(
#Lesen Sie die heruntergeladenen Grenzdaten zu Esri Japan mit Geopandas
gpd.read_file("japan_ver821/japan_ver821.shp")
)
#Bestätigung
sdf_japan.show(5)
# +-----+------+----------+----+------+----------+--------------------+--------+--------+--------------------+
# |JCODE| KEN| SICHO| GUN|SEIREI|SIKUCHOSON| CITY_ENG| P_NUM| H_NUM| geometry|
# +-----+------+----------+----+------+----------+--------------------+--------+--------+--------------------+
# |01101|Hokkaido|Ishikari Promotion Bureau|null|Sapporo|Chuo-ku|Sapporo-shi, Chuo-ku|235449.0|141734.0|POLYGON ((141.342...|
# |01102|Hokkaido|Ishikari Promotion Bureau|null|Sapporo|Kita Ward|Sapporo-shi, Kita-ku|286112.0|151891.0|POLYGON ((141.408...|
# |01103|Hokkaido|Ishikari Promotion Bureau|null|Sapporo|Higashi Ward|Sapporo-shi, Higa...|261777.0|142078.0|POLYGON ((141.446...|
# |01104|Hokkaido|Ishikari Promotion Bureau|null|Sapporo|Shiraishi Ward|Sapporo-shi, Shir...|212671.0|122062.0|POLYGON ((141.465...|
# |01105|Hokkaido|Ishikari Promotion Bureau|null|Sapporo|Toyohei Ward|Sapporo-shi, Toyo...|222504.0|126579.0|POLYGON ((141.384...|
# +-----+------+----------+----+------+----------+--------------------+--------+--------+--------------------+
# only showing top 5 rows
#.
sdf_japan.write.save("esri_japan")
#.parquet)
spark.sql("CREATE DATABASE IF NOT EXISTS geo_test") #
sdf_japan.write.saveAsTable("geo_test.esri_japan") #__Parkettformat) Im Hive-Tabellenformat speichern (die eigentliche Datei ist standardmäßig nicht bissig erforderlich, aber als Tabelle esrijapan beim Datenbankerstellungsdatenbank-Geotest speichern
↑ Sie können Format
und Komprimierung
mit den Optionen save und saveAsTable ändern, und es scheint, dass Sie auch mit zlib.orc
und json.gzip
speichern können. (Abgesehen davon, wie glücklich es ist)
#Datei lesen
#Geben Sie das Verzeichnis an, in dem die eigentliche Datei gespeichert wird. Geben Sie beim Speichern in einem anderen Format als Parkett das Format in der Ladeoption an.
sdf_from_file = spark.read.load("esri_japan")
sdf_from_file.show(5)
# +-----+------+-----+------+------+----------+--------------+-------+-------+--------------------+
# |JCODE| KEN|SICHO| GUN|SEIREI|SIKUCHOSON| CITY_ENG| P_NUM| H_NUM| geometry|
# +-----+------+-----+------+------+----------+--------------+-------+-------+--------------------+
# |32207|Präfektur Shimane| null| null| null|Ezu Stadt| Gotsu-shi|23664.0|11513.0|MULTIPOLYGON (((1...|
# |32209|Präfektur Shimane| null| null| null|Stadt Yunnan| Unnan-shi|38479.0|13786.0|MULTIPOLYGON (((1...|
# |32343|Präfektur Shimane| null|Nita-Pistole| null|Oku Izumo Stadt| Okuizumo-cho|12694.0| 4782.0|POLYGON ((133.078...|
# |32386|Präfektur Shimane| null|Iiishi-Pistole| null|Iinan Stadt| Iinan-cho| 4898.0| 2072.0|POLYGON ((132.678...|
# |32441|Präfektur Shimane| null|Echi-Pistole| null|Kawamoto Stadt|Kawamoto-machi| 3317.0| 1672.0|POLYGON ((132.487...|
# +-----+------+-----+------+------+----------+--------------+-------+-------+--------------------+
# only showing top 5 rows
#Tabelle gelesen
sdf_from_table = spark.table("geo_test.esri_japan") #Geben Sie den zu lesenden Tabellennamen an
sdf_from_table.show(5)
# +-----+------+-----+------+------+----------+--------------+-------+-------+--------------------+
# |JCODE| KEN|SICHO| GUN|SEIREI|SIKUCHOSON| CITY_ENG| P_NUM| H_NUM| geometry|
# +-----+------+-----+------+------+----------+--------------+-------+-------+--------------------+
# |32207|Präfektur Shimane| null| null| null|Ezu Stadt| Gotsu-shi|23664.0|11513.0|MULTIPOLYGON (((1...|
# |32209|Präfektur Shimane| null| null| null|Stadt Yunnan| Unnan-shi|38479.0|13786.0|MULTIPOLYGON (((1...|
# |32343|Präfektur Shimane| null|Nita-Pistole| null|Oku Izumo Stadt| Okuizumo-cho|12694.0| 4782.0|POLYGON ((133.078...|
# |32386|Präfektur Shimane| null|Iiishi-Pistole| null|Iinan Stadt| Iinan-cho| 4898.0| 2072.0|POLYGON ((132.678...|
# |32441|Präfektur Shimane| null|Echi-Pistole| null|Kawamoto Stadt|Kawamoto-machi| 3317.0| 1672.0|POLYGON ((132.487...|
# +-----+------+-----+------+------+----------+--------------+-------+-------+--------------------+
# only showing top 5 rows
Es wurde bestätigt, dass es als einfache Datei oder in einem Tabellenformat gespeichert und gelesen werden kann. Außerdem war ich der Meinung, dass die Konvertierung von Geopandas in DataFrame von pyspark langsam war, und dachte daher, dass es besser ist, die Konvertierung von Geopandas <-> pyspark zu minimieren.
※dtypes
sdf = sdf_from_file #Im Folgenden wird der aus der Datei gelesene als sdf bezeichnet.
display(sdf.dtypes)
# [('JCODE', 'string'),
# ('KEN', 'string'),
# ('SICHO', 'string'),
# ('GUN', 'string'),
# ('SEIREI', 'string'),
# ('SIKUCHOSON', 'string'),
# ('CITY_ENG', 'string'),
# ('P_NUM', 'double'),
# ('H_NUM', 'double'),
# ('geometry', 'udt')]
Es scheint, dass "Geometrie" als ein "udt" -Typ behandelt wird, der in der Geospark-Bibliothek definiert ist. (Wenn Sie also versuchen, eine Datei oder Tabelle ohne Geospark-Einstellungen zu lesen, wird eine Fehlermeldung angezeigt.)
Siehe insbesondere aus der offiziellen Dokumentation:
#Registrieren Sie den DataFrame als TEMP VIEW, damit Sie spark sql verwenden können
sdf.createOrReplaceTempView('esri_japan')
#Bestätigen Sie die Anzahl der Originaldaten
sdf.count() # 1907
#Längengrad: 135-140, Breitengrad: 35-Filter im Bereich von 40
sdf_filtered = spark.sql("""
SELECT * FROM esri_japan
WHERE ST_Contains(ST_PolygonFromEnvelope(135., 35., 140., 40.), esri_japan.geometry)
""")
sdf_filtered.show(5)
# +-----+------+-----+--------+------+----------+----------------+-------+------+--------------------+
# |JCODE| KEN|SICHO| GUN|SEIREI|SIKUCHOSON| CITY_ENG| P_NUM| H_NUM| geometry|
# +-----+------+-----+--------+------+----------+----------------+-------+------+--------------------+
# |06401|Präfektur Yamagata| null|Nishioki-Pistole| null|Oguni Stadt| Oguni-machi| 7612.0|3076.0|POLYGON ((139.911...|
# |06426|Präfektur Yamagata| null|Higashidagawa-Pistole| null|Mikawa Town| Mikawa-machi| 7400.0|2387.0|POLYGON ((139.842...|
# |07364|Präfektur Fukushima| null|Minami Aizu-Pistole| null|Hiedagi Village| Hinoemata-mura| 557.0| 202.0|POLYGON ((139.259...|
# |07367|Präfektur Fukushima| null|Minami Aizu-Pistole| null|Tadami Stadt| Tadami-machi| 4366.0|1906.0|POLYGON ((139.366...|
# |07368|Präfektur Fukushima| null|Minami Aizu-Pistole| null|Minami Aizu Stadt|Minamiaizu-machi|15679.0|6707.0|POLYGON ((139.530...|
# +-----+------+-----+--------+------+----------+----------------+-------+------+--------------------+
# only showing top 5 rows
sdf_filtered.count() # 573 <- original: 1907
Die Anzahl der DataFrames hat sich ebenfalls verringert (1907-> 573), und es scheint, dass der Filter ordnungsgemäß abgeschlossen wurde, aber ich werde ihn visualisieren und für alle Fälle überprüfen.
# matplotlib
gdf_filtered = gpd.GeoDataFrame( #In Geopandas konvertieren
sdf_filtered.toPandas(),
geometry='geometry'
)
gdf_filtered.plot()
(Handlungsergebnis)
Übrigens, wenn Sie das gesamte Original japan_ver821.shp zeichnen
gpd.read_file('japan_ver821/japan_ver821.shp') \
.plot()
Es scheint also, dass die Filterung richtig durchgeführt wird.
Sie können auch folium
für die interaktive Visualisierung verwenden.
m = folium.Map(
location=(37.5, 137.5), #Beachten Sie, dass die Reihenfolge Breiten- und Längengrad ist.
zoom_start=7,
control_scale=True,
)
m.add_child(folium.LatLngPopup()) #Klicken Sie hier, um den Breiten- und Längengrad in einem Popup zu überprüfen
#Konvertieren Sie den gefilterten DataFrame in GeoJSON und übergeben Sie ihn an Folium
m.add_child(
folium.GeoJson(gdf_filtered.to_json())
)
folium.LayerControl().add_to(m) #LayerControl hinzugefügt
m.save('df_filterd.html') #sparen
m #Wird auf dem Jupiter angezeigt
Ich konnte es auch auf dem Folium visualisieren.
――Ich war diesmal nicht sehr glücklich, weil ich nur eine sehr einfache Abfrage zu kleinen Daten durchgeführt habe, aber es war interessant, auf Spark eine PostGIS-ähnliche Atmosphäre schaffen zu können.
Recommended Posts