{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "Licensed to the Apache Software Foundation (ASF) under one\n", "or more contributor license agreements. See the NOTICE file\n", "distributed with this work for additional information\n", "regarding copyright ownership. The ASF licenses this file\n", "to you under the Apache License, Version 2.0 (the\n", "\"License\"); you may not use this file except in compliance\n", "with the License. You may obtain a copy of the License at\n", " http://www.apache.org/licenses/LICENSE-2.0\n", "Unless required by applicable law or agreed to in writing,\n", "software distributed under the License is distributed on an\n", "\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n", "KIND, either express or implied. See the License for the\n", "specific language governing permissions and limitations\n", "under the License.\n", "```" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pyspark.sql import SparkSession\n", "from pyspark import StorageLevel\n", "import geopandas as gpd\n", "import pandas as pd\n", "from pyspark.sql.types import StructType\n", "from pyspark.sql.types import StructField\n", "from pyspark.sql.types import StringType\n", "from pyspark.sql.types import LongType\n", "from shapely.geometry import Point\n", "from shapely.geometry import Polygon\n", "\n", "from sedona.spark import *\n", "from sedona.core.geom.envelope import Envelope\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "https://artifacts.unidata.ucar.edu/repository/unidata-all added as a remote repository with the name: repo-1\n", "Ivy Default Cache set to: /root/.ivy2/cache\n", "The jars for the packages stored in: /root/.ivy2/jars\n", "org.apache.sedona#sedona-spark-shaded-3.4_2.12 added as a dependency\n", "org.datasyslab#geotools-wrapper added as a dependency\n", "uk.co.gresearch.spark#spark-extension_2.12 added as a dependency\n", ":: resolving dependencies :: org.apache.spark#spark-submit-parent-7eb0c6dc-19b8-477f-b252-512428246ef7;1.0\n", "\tconfs: [default]\n", "\tfound org.apache.sedona#sedona-spark-shaded-3.4_2.12;1.5.1 in central\n", "\tfound edu.ucar#cdm-core;5.4.2 in repo-1\n", "\tfound edu.ucar#udunits;5.4.2 in repo-1\n", "\tfound edu.ucar#httpservices;5.4.2 in repo-1\n", "\tfound com.google.guava#guava;30.1-jre in central\n", "\tfound com.google.guava#failureaccess;1.0.1 in central\n", "\tfound com.google.guava#listenablefuture;9999.0-empty-to-avoid-conflict-with-guava in central\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ ":: loading settings :: url = jar:file:/opt/spark/jars/ivy-2.5.1.jar!/org/apache/ivy/core/settings/ivysettings.xml\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\tfound com.google.code.findbugs#jsr305;3.0.2 in central\n", "\tfound org.checkerframework#checker-qual;3.5.0 in central\n", "\tfound com.google.errorprone#error_prone_annotations;2.3.4 in central\n", "\tfound com.google.j2objc#j2objc-annotations;1.3 in central\n", "\tfound org.apache.httpcomponents#httpclient;4.5.13 in central\n", "\tfound org.apache.httpcomponents#httpcore;4.4.13 in central\n", "\tfound commons-logging#commons-logging;1.2 in central\n", "\tfound commons-codec#commons-codec;1.11 in central\n", "\tfound com.beust#jcommander;1.78 in central\n", "\tfound com.google.protobuf#protobuf-java;3.12.4 in central\n", "\tfound com.google.re2j#re2j;1.3 in central\n", "\tfound joda-time#joda-time;2.10.3 in central\n", "\tfound org.jdom#jdom2;2.0.6 in central\n", "\tfound org.slf4j#slf4j-api;1.7.36 in central\n", "\tfound org.apache.httpcomponents#httpmime;4.5.13 in central\n", "\tfound org.datasyslab#geotools-wrapper;1.5.1-28.2 in central\n", "\tfound uk.co.gresearch.spark#spark-extension_2.12;2.11.0-3.4 in central\n", "\tfound com.github.scopt#scopt_2.12;4.1.0 in central\n", ":: resolution report :: resolve 292ms :: artifacts dl 10ms\n", "\t:: modules in use:\n", "\tcom.beust#jcommander;1.78 from central in [default]\n", "\tcom.github.scopt#scopt_2.12;4.1.0 from central in [default]\n", "\tcom.google.code.findbugs#jsr305;3.0.2 from central in [default]\n", "\tcom.google.errorprone#error_prone_annotations;2.3.4 from central in [default]\n", "\tcom.google.guava#failureaccess;1.0.1 from central in [default]\n", "\tcom.google.guava#guava;30.1-jre from central in [default]\n", "\tcom.google.guava#listenablefuture;9999.0-empty-to-avoid-conflict-with-guava from central in [default]\n", "\tcom.google.j2objc#j2objc-annotations;1.3 from central in [default]\n", "\tcom.google.protobuf#protobuf-java;3.12.4 from central in [default]\n", "\tcom.google.re2j#re2j;1.3 from central in [default]\n", "\tcommons-codec#commons-codec;1.11 from central in [default]\n", "\tcommons-logging#commons-logging;1.2 from central in [default]\n", "\tedu.ucar#cdm-core;5.4.2 from repo-1 in [default]\n", "\tedu.ucar#httpservices;5.4.2 from repo-1 in [default]\n", "\tedu.ucar#udunits;5.4.2 from repo-1 in [default]\n", "\tjoda-time#joda-time;2.10.3 from central in [default]\n", "\torg.apache.httpcomponents#httpclient;4.5.13 from central in [default]\n", "\torg.apache.httpcomponents#httpcore;4.4.13 from central in [default]\n", "\torg.apache.httpcomponents#httpmime;4.5.13 from central in [default]\n", "\torg.apache.sedona#sedona-spark-shaded-3.4_2.12;1.5.1 from central in [default]\n", "\torg.checkerframework#checker-qual;3.5.0 from central in [default]\n", "\torg.datasyslab#geotools-wrapper;1.5.1-28.2 from central in [default]\n", "\torg.jdom#jdom2;2.0.6 from central in [default]\n", "\torg.slf4j#slf4j-api;1.7.36 from central in [default]\n", "\tuk.co.gresearch.spark#spark-extension_2.12;2.11.0-3.4 from central in [default]\n", "\t---------------------------------------------------------------------\n", "\t| | modules || artifacts |\n", "\t| conf | number| search|dwnlded|evicted|| number|dwnlded|\n", "\t---------------------------------------------------------------------\n", "\t| default | 25 | 0 | 0 | 0 || 25 | 0 |\n", "\t---------------------------------------------------------------------\n", ":: retrieving :: org.apache.spark#spark-submit-parent-7eb0c6dc-19b8-477f-b252-512428246ef7\n", "\tconfs: [default]\n", "\t0 artifacts copied, 25 already retrieved (0kB/9ms)\n", "24/01/20 22:54:19 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n", "Setting default log level to \"WARN\".\n", "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n" ] } ], "source": [ "config = SedonaContext.builder() .\\\n", " config('spark.jars.packages',\n", " 'org.apache.sedona:sedona-spark-3.4_2.12:1.5.1,'\n", " 'org.datasyslab:geotools-wrapper:1.5.1-28.2,'\n", " 'uk.co.gresearch.spark:spark-extension_2.12:2.11.0-3.4'). \\\n", " config('spark.jars.repositories', 'https://artifacts.unidata.ucar.edu/repository/unidata-all'). \\\n", " getOrCreate()\n", "\n", "sedona = SedonaContext.create(config)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "sc = sedona.sparkContext" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Create SpatialRDD" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Reading to PointRDD from CSV file" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Suppose we want load the CSV file into Apache Sedona PointRDD\n", "```\n", "testattribute0,-88.331492,32.324142,testattribute1,testattribute2\n", "testattribute0,-88.175933,32.360763,testattribute1,testattribute2\n", "testattribute0,-88.388954,32.357073,testattribute1,testattribute2\n", "testattribute0,-88.221102,32.35078,testattribute1,testattribute2\n", "testattribute0,-88.323995,32.950671,testattribute1,testattribute2\n", "testattribute0,-88.231077,32.700812,testattribute1,testattribute2\n", "```" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "point_rdd = PointRDD(sc, \"data/arealm-small.csv\", 1, FileDataSplitter.CSV, True, 10)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3000" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## Getting approximate total count\n", "point_rdd.approximateTotalCount" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/usr/local/lib/python3.10/dist-packages/sedona/core/geom/envelope.py:27: ShapelyDeprecationWarning: Setting custom attributes on geometry objects is deprecated, and will raise an AttributeError in Shapely 2.0\n", " self.minx = minx\n", "/usr/local/lib/python3.10/dist-packages/sedona/core/geom/envelope.py:28: ShapelyDeprecationWarning: Setting custom attributes on geometry objects is deprecated, and will raise an AttributeError in Shapely 2.0\n", " self.maxx = maxx\n", "/usr/local/lib/python3.10/dist-packages/sedona/core/geom/envelope.py:29: ShapelyDeprecationWarning: Setting custom attributes on geometry objects is deprecated, and will raise an AttributeError in Shapely 2.0\n", " self.miny = miny\n", "/usr/local/lib/python3.10/dist-packages/sedona/core/geom/envelope.py:30: ShapelyDeprecationWarning: Setting custom attributes on geometry objects is deprecated, and will raise an AttributeError in Shapely 2.0\n", " self.maxy = maxy\n" ] }, { "data": { "image/svg+xml": [ "" ], "text/plain": [ "Envelope(-173.120769, -84.965961, 30.244859, 71.355134)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# getting boundary for PointRDD or any other SpatialRDD, it returns Envelope object which inherits from\n", "# shapely.geometry.Polygon\n", "point_rdd.boundary()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# To run analyze please use function analyze\n", "point_rdd.analyze()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "Envelope(-173.120769, -84.965961, 30.244859, 71.355134)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Finding boundary envelope for PointRDD or any other SpatialRDD, it returns Envelope object which inherits from\n", "# shapely.geometry.Polygon\n", "point_rdd.boundaryEnvelope" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2996" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Calculate number of records without duplicates\n", "point_rdd.countWithoutDuplicates()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "''" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Getting source epsg code\n", "point_rdd.getSourceEpsgCode()" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "''" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Getting target epsg code\n", "point_rdd.getTargetEpsgCode()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Spatial partitioning data\n", "point_rdd.spatialPartitioning(GridType.KDBTREE)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operations on RawSpatialRDD" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "rawSpatialRDD method returns RDD which consists of GeoData objects which has 2 attributes\n", "
  • geom: shapely.geometry.BaseGeometry
  • \n", "
  • userData: str
  • \n", "\n", "You can use any operations on those objects and spread across machines" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# take firs element\n", "point_rdd.rawSpatialRDD.take(1)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2,\n", " Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2,\n", " Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2,\n", " Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2,\n", " Geometry: Point userData: testattribute0\ttestattribute1\ttestattribute2]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# collect to Python list\n", "point_rdd.rawSpatialRDD.collect()[:5]" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[111.08786851399313,\n", " 110.92828303170774,\n", " 111.1385974283527,\n", " 110.97450594034112,\n", " 110.97122518072091]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# apply map functions, for example distance to Point(52 21)\n", "point_rdd.rawSpatialRDD.map(lambda x: x.geom.distance(Point(21, 52))).take(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Transforming to GeoPandas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loaded data can be transformed to GeoPandas DataFrame in a few ways" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Directly from RDD" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "point_rdd_to_geo = point_rdd.rawSpatialRDD.map(lambda x: [x.geom, *x.getUserData().split(\"\\t\")])" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "point_gdf = gpd.GeoDataFrame(\n", " point_rdd_to_geo.collect(), columns=[\"geom\", \"attr1\", \"attr2\", \"attr3\"], geometry=\"geom\"\n", ")" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
    \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
    geomattr1attr2attr3
    0POINT (-88.33149 32.32414)testattribute0testattribute1testattribute2
    1POINT (-88.17593 32.36076)testattribute0testattribute1testattribute2
    2POINT (-88.38895 32.35707)testattribute0testattribute1testattribute2
    3POINT (-88.22110 32.35078)testattribute0testattribute1testattribute2
    4POINT (-88.32399 32.95067)testattribute0testattribute1testattribute2
    \n", "
    " ], "text/plain": [ " geom attr1 attr2 attr3\n", "0 POINT (-88.33149 32.32414) testattribute0 testattribute1 testattribute2\n", "1 POINT (-88.17593 32.36076) testattribute0 testattribute1 testattribute2\n", "2 POINT (-88.38895 32.35707) testattribute0 testattribute1 testattribute2\n", "3 POINT (-88.22110 32.35078) testattribute0 testattribute1 testattribute2\n", "4 POINT (-88.32399 32.95067) testattribute0 testattribute1 testattribute2" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "point_gdf[:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using Adapter" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Adapter allows you to convert geospatial data types introduced with sedona to other ones" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "spatial_df = Adapter.\\\n", " toDf(point_rdd, [\"attr1\", \"attr2\", \"attr3\"], sedona).\\\n", " createOrReplaceTempView(\"spatial_df\")\n", "\n", "spatial_gdf = sedona.sql(\"Select attr1, attr2, attr3, geometry as geom from spatial_df\")" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------+--------------+--------------+----------------------------+\n", "|attr1 |attr2 |attr3 |geom |\n", "+--------------+--------------+--------------+----------------------------+\n", "|testattribute0|testattribute1|testattribute2|POINT (-88.331492 32.324142)|\n", "|testattribute0|testattribute1|testattribute2|POINT (-88.175933 32.360763)|\n", "|testattribute0|testattribute1|testattribute2|POINT (-88.388954 32.357073)|\n", "|testattribute0|testattribute1|testattribute2|POINT (-88.221102 32.35078) |\n", "|testattribute0|testattribute1|testattribute2|POINT (-88.323995 32.950671)|\n", "+--------------+--------------+--------------+----------------------------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "spatial_gdf.show(5, False)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
    \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
    attr1attr2attr3geom
    0testattribute0testattribute1testattribute2POINT (-88.33149 32.32414)
    1testattribute0testattribute1testattribute2POINT (-88.17593 32.36076)
    2testattribute0testattribute1testattribute2POINT (-88.38895 32.35707)
    3testattribute0testattribute1testattribute2POINT (-88.22110 32.35078)
    4testattribute0testattribute1testattribute2POINT (-88.32399 32.95067)
    \n", "
    " ], "text/plain": [ " attr1 attr2 attr3 geom\n", "0 testattribute0 testattribute1 testattribute2 POINT (-88.33149 32.32414)\n", "1 testattribute0 testattribute1 testattribute2 POINT (-88.17593 32.36076)\n", "2 testattribute0 testattribute1 testattribute2 POINT (-88.38895 32.35707)\n", "3 testattribute0 testattribute1 testattribute2 POINT (-88.22110 32.35078)\n", "4 testattribute0 testattribute1 testattribute2 POINT (-88.32399 32.95067)" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gpd.GeoDataFrame(spatial_gdf.toPandas(), geometry=\"geom\")[:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### With DataFrame creation" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "schema = StructType(\n", " [\n", " StructField(\"geometry\", GeometryType(), False),\n", " StructField(\"attr1\", StringType(), False),\n", " StructField(\"attr2\", StringType(), False),\n", " StructField(\"attr3\", StringType(), False),\n", " ]\n", ")" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "geo_df = sedona.createDataFrame(point_rdd_to_geo, schema, verifySchema=False)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
    \n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
    geometryattr1attr2attr3
    0POINT (-88.33149 32.32414)testattribute0testattribute1testattribute2
    1POINT (-88.17593 32.36076)testattribute0testattribute1testattribute2
    2POINT (-88.38895 32.35707)testattribute0testattribute1testattribute2
    3POINT (-88.22110 32.35078)testattribute0testattribute1testattribute2
    4POINT (-88.32399 32.95067)testattribute0testattribute1testattribute2
    \n", "
    " ], "text/plain": [ " geometry attr1 attr2 attr3\n", "0 POINT (-88.33149 32.32414) testattribute0 testattribute1 testattribute2\n", "1 POINT (-88.17593 32.36076) testattribute0 testattribute1 testattribute2\n", "2 POINT (-88.38895 32.35707) testattribute0 testattribute1 testattribute2\n", "3 POINT (-88.22110 32.35078) testattribute0 testattribute1 testattribute2\n", "4 POINT (-88.32399 32.95067) testattribute0 testattribute1 testattribute2" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gpd.GeoDataFrame(geo_df.toPandas(), geometry=\"geometry\")[:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Load Typed SpatialRDDs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Currently The library supports 5 typed SpatialRDDs:\n", "
  • RectangleRDD
  • \n", "
  • PointRDD
  • \n", "
  • PolygonRDD
  • \n", "
  • LineStringRDD
  • \n", "
  • CircleRDD
  • " ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "rectangle_rdd = RectangleRDD(sc, \"data/zcta510-small.csv\", FileDataSplitter.CSV, True, 11)\n", "point_rdd = PointRDD(sc, \"data/arealm-small.csv\", 1, FileDataSplitter.CSV, False, 11)\n", "polygon_rdd = PolygonRDD(sc, \"data/primaryroads-polygon.csv\", FileDataSplitter.CSV, True, 11)\n", "linestring_rdd = LineStringRDD(sc, \"data/primaryroads-linestring.csv\", FileDataSplitter.CSV, True)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rectangle_rdd.analyze()\n", "point_rdd.analyze()\n", "polygon_rdd.analyze()\n", "linestring_rdd.analyze()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Spatial Partitioning" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Apache Sedona spatial partitioning method can significantly speed up the join query. Three spatial partitioning methods are available: KDB-Tree, Quad-Tree and R-Tree. Two SpatialRDD must be partitioned by the same way." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "point_rdd.spatialPartitioning(GridType.KDBTREE)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Create Index" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Apache Sedona provides two types of spatial indexes, Quad-Tree and R-Tree. Once you specify an index type, Apache Sedona will build a local tree index on each of the SpatialRDD partition." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "point_rdd.buildIndex(IndexType.RTREE, True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# SpatialJoin" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Spatial join is operation which combines data based on spatial relations like:\n", "
  • intersects
  • \n", "
  • touches
  • \n", "
  • within
  • \n", "
  • etc
  • \n", "\n", "To Use Spatial Join in GeoPyspark library please use JoinQuery object, which has implemented below methods:\n", "```python\n", "SpatialJoinQuery(spatialRDD: SpatialRDD, queryRDD: SpatialRDD, useIndex: bool, considerBoundaryIntersection: bool) -> RDD\n", "\n", "DistanceJoinQuery(spatialRDD: SpatialRDD, queryRDD: SpatialRDD, useIndex: bool, considerBoundaryIntersection: bool) -> RDD\n", "\n", "spatialJoin(queryWindowRDD: SpatialRDD, objectRDD: SpatialRDD, joinParams: JoinParams) -> RDD\n", "\n", "DistanceJoinQueryFlat(spatialRDD: SpatialRDD, queryRDD: SpatialRDD, useIndex: bool, considerBoundaryIntersection: bool) -> RDD\n", "\n", "SpatialJoinQueryFlat(spatialRDD: SpatialRDD, queryRDD: SpatialRDD, useIndex: bool, considerBoundaryIntersection: bool) -> RDD\n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example SpatialJoinQueryFlat PointRDD with RectangleRDD " ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "# partitioning the data\n", "point_rdd.spatialPartitioning(GridType.KDBTREE)\n", "rectangle_rdd.spatialPartitioning(point_rdd.getPartitioner())\n", "# building an index\n", "point_rdd.buildIndex(IndexType.RTREE, True)\n", "# Perform Spatial Join Query\n", "result = JoinQuery.SpatialJoinQueryFlat(point_rdd, rectangle_rdd, False, True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As result we will get RDD[GeoData, GeoData]\n", "It can be used like any other Python RDD. You can use map, take, collect and other functions " ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "MapPartitionsRDD[63] at map at FlatPairRddConverter.scala:30" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[Geometry: Polygon userData: , Geometry: Point userData: ],\n", " [Geometry: Polygon userData: , Geometry: Point userData: ]]" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result.take(2)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[Geometry: Polygon userData: , Geometry: Point userData: ],\n", " [Geometry: Polygon userData: , Geometry: Point userData: ],\n", " [Geometry: Polygon userData: , Geometry: Point userData: ]]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result.collect()[:3]" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0.0, 0.0, 0.0, 0.0, 0.0]" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# getting distance using SpatialObjects\n", "result.map(lambda x: x[0].geom.distance(x[1].geom)).take(5)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0.051572544132000575,\n", " 0.051572544132000575,\n", " 0.05189354027999942,\n", " 0.057069904940998895,\n", " 0.057069904940998895]" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# getting area of polygon data\n", "result.map(lambda x: x[0].geom.area).take(5)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "# Base on result you can create DataFrame object, using map function and build DataFrame from RDD" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "schema = StructType(\n", " [\n", " StructField(\"geom_left\", GeometryType(), False),\n", " StructField(\"geom_right\", GeometryType(), False)\n", " ]\n", ")" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+--------------------+\n", "| geom_left| geom_right|\n", "+--------------------+--------------------+\n", "|POLYGON ((-87.082...|POINT (-87.075409...|\n", "|POLYGON ((-87.082...|POINT (-87.08084 ...|\n", "|POLYGON ((-87.092...|POINT (-87.08084 ...|\n", "|POLYGON ((-87.285...|POINT (-87.095533...|\n", "|POLYGON ((-87.285...|POINT (-87.124441...|\n", "+--------------------+--------------------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "# Set verifySchema to False\n", "spatial_join_result = result.map(lambda x: [x[0].geom, x[1].geom])\n", "sedona.createDataFrame(spatial_join_result, schema, verifySchema=False).show(5, True)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "# Above code produces DataFrame with geometry Data type" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "root\n", " |-- geom_left: geometry (nullable = false)\n", " |-- geom_right: geometry (nullable = false)\n", "\n" ] } ], "source": [ "sedona.createDataFrame(spatial_join_result, schema, verifySchema=False).printSchema()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can create DataFrame object from Spatial Pair RDD using Adapter object as follows" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+-----+--------------------+-----+\n", "| geom_1|attr1| geom_2|attr2|\n", "+--------------------+-----+--------------------+-----+\n", "|POLYGON ((-87.082...| |POINT (-87.075409...| |\n", "|POLYGON ((-87.082...| |POINT (-87.08084 ...| |\n", "|POLYGON ((-87.092...| |POINT (-87.08084 ...| |\n", "|POLYGON ((-87.285...| |POINT (-87.095533...| |\n", "|POLYGON ((-87.285...| |POINT (-87.124441...| |\n", "+--------------------+-----+--------------------+-----+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "Adapter.toDf(result, [\"attr1\"], [\"attr2\"], sedona).show(5, True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This also produce DataFrame with geometry DataType " ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "root\n", " |-- geom_1: geometry (nullable = true)\n", " |-- attr1: string (nullable = true)\n", " |-- geom_2: geometry (nullable = true)\n", " |-- attr2: string (nullable = true)\n", "\n" ] } ], "source": [ "Adapter.toDf(result, [\"attr1\"], [\"attr2\"], sedona).printSchema()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can create RDD which will be of type RDD[GeoData, List[GeoData]]\n", "We can for example calculate number of Points within some polygon data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To do that we can use code specified below" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "point_rdd.spatialPartitioning(GridType.KDBTREE)\n", "rectangle_rdd.spatialPartitioning(point_rdd.getPartitioner())" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [], "source": [ "spatial_join_result_non_flat = JoinQuery.SpatialJoinQuery(point_rdd, rectangle_rdd, False, True)" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "# number of point for each polygon\n", "number_of_points = spatial_join_result_non_flat.map(lambda x: [x[0].geom, x[1].__len__()])" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [], "source": [ "schema = StructType([\n", " StructField(\"geometry\", GeometryType(), False),\n", " StructField(\"number_of_points\", LongType(), False)\n", "])" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+----------------+\n", "| geometry|number_of_points|\n", "+--------------------+----------------+\n", "|POLYGON ((-87.114...| 15|\n", "|POLYGON ((-87.082...| 12|\n", "|POLYGON ((-86.697...| 1|\n", "|POLYGON ((-87.285...| 26|\n", "|POLYGON ((-87.105...| 15|\n", "|POLYGON ((-86.816...| 6|\n", "|POLYGON ((-87.229...| 7|\n", "|POLYGON ((-87.092...| 5|\n", "|POLYGON ((-86.749...| 4|\n", "|POLYGON ((-86.860...| 12|\n", "+--------------------+----------------+\n", "\n" ] } ], "source": [ "sedona.createDataFrame(number_of_points, schema, verifySchema=False).show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# KNNQuery" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Spatial KNNQuery is operation which help us find answer which k number of geometries lays closest to other geometry.\n", "\n", "For Example:\n", " 5 closest Shops to your home. To use Spatial KNNQuery please use object \n", " KNNQuery which has one method:\n", "```python\n", "SpatialKnnQuery(spatialRDD: SpatialRDD, originalQueryPoint: BaseGeometry, k: int, useIndex: bool)-> List[GeoData]\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Finds 5 closest points from PointRDD to given Point" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [], "source": [ "result = KNNQuery.SpatialKnnQuery(point_rdd, Point(-84.01, 34.01), 5, False)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Geometry: Point userData: ,\n", " Geometry: Point userData: ,\n", " Geometry: Point userData: ,\n", " Geometry: Point userData: ,\n", " Geometry: Point userData: ]" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As Reference geometry you can also use Polygon or LineString object" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "polygon = Polygon(\n", " [(-84.237756, 33.904859), (-84.237756, 34.090426),\n", " (-83.833011, 34.090426), (-83.833011, 33.904859),\n", " (-84.237756, 33.904859)\n", " ])\n", "polygons_nearby = KNNQuery.SpatialKnnQuery(polygon_rdd, polygon, 5, False)" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Geometry: Polygon userData: ,\n", " Geometry: Polygon userData: ,\n", " Geometry: Polygon userData: ,\n", " Geometry: Polygon userData: ,\n", " Geometry: Polygon userData: ]" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "polygons_nearby" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'POLYGON ((-83.993559 34.087259, -83.993559 34.131247, -83.959903 34.131247, -83.959903 34.087259, -83.993559 34.087259))'" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "polygons_nearby[0].geom.wkt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# RangeQuery" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A spatial range query takes as input a range query window and an SpatialRDD and returns all geometries that intersect / are fully covered by the query window. \n", "RangeQuery has one method:\n", "\n", "```python\n", "SpatialRangeQuery(self, spatialRDD: SpatialRDD, rangeQueryWindow: BaseGeometry, considerBoundaryIntersection: bool, usingIndex: bool) -> RDD\n", "```" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [], "source": [ "from sedona.core.geom.envelope import Envelope" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/usr/local/lib/python3.10/dist-packages/sedona/core/geom/envelope.py:27: ShapelyDeprecationWarning: Setting custom attributes on geometry objects is deprecated, and will raise an AttributeError in Shapely 2.0\n", " self.minx = minx\n", "/usr/local/lib/python3.10/dist-packages/sedona/core/geom/envelope.py:28: ShapelyDeprecationWarning: Setting custom attributes on geometry objects is deprecated, and will raise an AttributeError in Shapely 2.0\n", " self.maxx = maxx\n", "/usr/local/lib/python3.10/dist-packages/sedona/core/geom/envelope.py:29: ShapelyDeprecationWarning: Setting custom attributes on geometry objects is deprecated, and will raise an AttributeError in Shapely 2.0\n", " self.miny = miny\n", "/usr/local/lib/python3.10/dist-packages/sedona/core/geom/envelope.py:30: ShapelyDeprecationWarning: Setting custom attributes on geometry objects is deprecated, and will raise an AttributeError in Shapely 2.0\n", " self.maxy = maxy\n" ] } ], "source": [ "query_envelope = Envelope(-85.01, -60.01, 34.01, 50.01)\n", "\n", "result_range_query = RangeQuery.SpatialRangeQuery(linestring_rdd, query_envelope, False, False)" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "MapPartitionsRDD[127] at map at GeometryRddConverter.scala:30" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result_range_query" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Geometry: LineString userData: ,\n", " Geometry: LineString userData: ,\n", " Geometry: LineString userData: ,\n", " Geometry: LineString userData: ,\n", " Geometry: LineString userData: ,\n", " Geometry: LineString userData: ]" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result_range_query.take(6)" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [], "source": [ "# Creating DataFrame from result" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [], "source": [ "schema = StructType([StructField(\"geometry\", GeometryType(), False)])" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+\n", "| geometry|\n", "+--------------------+\n", "|LINESTRING (-72.1...|\n", "|LINESTRING (-72.4...|\n", "|LINESTRING (-72.4...|\n", "|LINESTRING (-73.4...|\n", "|LINESTRING (-73.6...|\n", "+--------------------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "sedona.createDataFrame(\n", " result_range_query.map(lambda x: [x.geom]),\n", " schema,\n", " verifySchema=False\n", ").show(5, True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Load From other Formats" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "GeoPyspark allows to load the data from other Data formats like:\n", "
  • GeoJSON
  • \n", "
  • Shapefile
  • \n", "
  • WKB
  • \n", "
  • WKT
  • " ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [], "source": [ "## ShapeFile - load to SpatialRDD" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [], "source": [ "shape_rdd = ShapefileReader.readToGeometryRDD(sc, \"data/polygon\")" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shape_rdd" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+\n", "| geometry|\n", "+--------------------+\n", "|MULTIPOLYGON (((1...|\n", "|MULTIPOLYGON (((-...|\n", "|MULTIPOLYGON (((1...|\n", "|POLYGON ((118.362...|\n", "|MULTIPOLYGON (((-...|\n", "+--------------------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "Adapter.toDf(shape_rdd, sedona).show(5, True)" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [], "source": [ "## GeoJSON - load to SpatialRDD" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "{ \"type\": \"Feature\", \"properties\": { \"STATEFP\": \"01\", \"COUNTYFP\": \"077\", \"TRACTCE\": \"011501\", \"BLKGRPCE\": \"5\", \"AFFGEOID\": \"1500000US010770115015\", \"GEOID\": \"010770115015\", \"NAME\": \"5\", \"LSAD\": \"BG\", \"ALAND\": 6844991, \"AWATER\": 32636 }, \"geometry\": { \"type\": \"Polygon\", \"coordinates\": [ [ [ -87.621765, 34.873444 ], [ -87.617535, 34.873369 ], [ -87.6123, 34.873337 ], [ -87.604049, 34.873303 ], [ -87.604033, 34.872316 ], [ -87.60415, 34.867502 ], [ -87.604218, 34.865687 ], [ -87.604409, 34.858537 ], [ -87.604018, 34.851336 ], [ -87.603716, 34.844829 ], [ -87.603696, 34.844307 ], [ -87.603673, 34.841884 ], [ -87.60372, 34.841003 ], [ -87.603879, 34.838423 ], [ -87.603888, 34.837682 ], [ -87.603889, 34.83763 ], [ -87.613127, 34.833938 ], [ -87.616451, 34.832699 ], [ -87.621041, 34.831431 ], [ -87.621056, 34.831526 ], [ -87.62112, 34.831925 ], [ -87.621603, 34.8352 ], [ -87.62158, 34.836087 ], [ -87.621383, 34.84329 ], [ -87.621359, 34.844438 ], [ -87.62129, 34.846387 ], [ -87.62119, 34.85053 ], [ -87.62144, 34.865379 ], [ -87.621765, 34.873444 ] ] ] } },\n", "```" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [], "source": [ "geo_json_rdd = GeoJsonReader.readToGeometryRDD(sc, \"data/testPolygon.json\")" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "geo_json_rdd" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+-------+--------+-------+--------+--------------------+------------+----+----+--------+\n", "| geometry|STATEFP|COUNTYFP|TRACTCE|BLKGRPCE| AFFGEOID| GEOID|NAME|LSAD| ALAND|\n", "+--------------------+-------+--------+-------+--------+--------------------+------------+----+----+--------+\n", "|POLYGON ((-87.621...| 01| 077| 011501| 5|1500000US01077011...|010770115015| 5| BG| 6844991|\n", "|POLYGON ((-85.719...| 01| 045| 021102| 4|1500000US01045021...|010450211024| 4| BG|11360854|\n", "|POLYGON ((-86.000...| 01| 055| 001300| 3|1500000US01055001...|010550013003| 3| BG| 1378742|\n", "|POLYGON ((-86.574...| 01| 089| 001700| 2|1500000US01089001...|010890017002| 2| BG| 1040641|\n", "|POLYGON ((-85.382...| 01| 069| 041400| 1|1500000US01069041...|010690414001| 1| BG| 8243574|\n", "+--------------------+-------+--------+-------+--------+--------------------+------------+----+----+--------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "Adapter.toDf(geo_json_rdd, sedona).drop(\"AWATER\").show(5, True)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [], "source": [ "## WKT - loading to SpatialRDD" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [], "source": [ "wkt_rdd = WktReader.readToGeometryRDD(sc, \"data/county_small.tsv\", 0, True, False)" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wkt_rdd" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "root\n", " |-- geometry: geometry (nullable = true)\n", "\n" ] } ], "source": [ "Adapter.toDf(wkt_rdd, sedona).printSchema()" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+\n", "| geometry|\n", "+--------------------+\n", "|POLYGON ((-97.019...|\n", "|POLYGON ((-123.43...|\n", "|POLYGON ((-104.56...|\n", "|POLYGON ((-96.910...|\n", "|POLYGON ((-98.273...|\n", "+--------------------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "Adapter.toDf(wkt_rdd, sedona).show(5, True)" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [], "source": [ "## WKB - load to SpatialRDD" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [], "source": [ "wkb_rdd = WkbReader.readToGeometryRDD(sc, \"data/county_small_wkb.tsv\", 0, True, False)" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+\n", "| geometry|\n", "+--------------------+\n", "|POLYGON ((-97.019...|\n", "|POLYGON ((-123.43...|\n", "|POLYGON ((-104.56...|\n", "|POLYGON ((-96.910...|\n", "|POLYGON ((-98.273...|\n", "+--------------------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "Adapter.toDf(wkb_rdd, sedona).show(5, True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Converting RDD Spatial join result to DF directly, avoiding jvm python serde" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [], "source": [ "point_rdd.spatialPartitioning(GridType.KDBTREE)\n", "rectangle_rdd.spatialPartitioning(point_rdd.getPartitioner())\n", "# building an index\n", "point_rdd.buildIndex(IndexType.RTREE, True)\n", "# Perform Spatial Join Query\n", "result = JoinQueryRaw.SpatialJoinQueryFlat(point_rdd, rectangle_rdd, False, True)" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [], "source": [ "# without passing column names, the result will contain only two geometries columns\n", "geometry_df = Adapter.toDf(result, sedona)" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "root\n", " |-- leftgeometry: geometry (nullable = true)\n", " |-- rightgeometry: geometry (nullable = true)\n", "\n" ] } ], "source": [ "geometry_df.printSchema()" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+--------------------+\n", "| leftgeometry| rightgeometry|\n", "+--------------------+--------------------+\n", "|POLYGON ((-87.285...|POINT (-87.28468 ...|\n", "|POLYGON ((-87.285...|POINT (-87.278485...|\n", "|POLYGON ((-87.285...|POINT (-87.280556...|\n", "|POLYGON ((-87.285...|POINT (-87.270187...|\n", "|POLYGON ((-87.285...|POINT (-87.268766...|\n", "+--------------------+--------------------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "geometry_df.show(5)" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Row(leftgeometry=, rightgeometry=)" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "geometry_df.collect()[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Passing column names" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [], "source": [ "geometry_df = Adapter.toDf(result, [\"left_user_data\"], [\"right_user_data\"], sedona)" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+--------------+--------------------+---------------+\n", "| leftgeometry|left_user_data| rightgeometry|right_user_data|\n", "+--------------------+--------------+--------------------+---------------+\n", "|POLYGON ((-87.285...| |POINT (-87.28468 ...| null|\n", "|POLYGON ((-87.285...| |POINT (-87.278485...| null|\n", "|POLYGON ((-87.285...| |POINT (-87.280556...| null|\n", "|POLYGON ((-87.285...| |POINT (-87.270187...| null|\n", "|POLYGON ((-87.285...| |POINT (-87.268766...| null|\n", "+--------------------+--------------+--------------------+---------------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "geometry_df.show(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Converting RDD Spatial join result to DF directly, avoiding jvm python serde" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [], "source": [ "query_envelope = Envelope(-85.01, -60.01, 34.01, 50.01)\n", "\n", "result_range_query = RangeQueryRaw.SpatialRangeQuery(linestring_rdd, query_envelope, False, False)" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [], "source": [ "# converting to df\n", "gdf = Adapter.toDf(result_range_query, sedona)" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+\n", "| geometry|\n", "+--------------------+\n", "|LINESTRING (-72.1...|\n", "|LINESTRING (-72.4...|\n", "|LINESTRING (-72.4...|\n", "|LINESTRING (-73.4...|\n", "|LINESTRING (-73.6...|\n", "+--------------------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "gdf.show(5)" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "root\n", " |-- geometry: geometry (nullable = true)\n", "\n" ] } ], "source": [ "gdf.printSchema()" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [], "source": [ "# Passing column names\n", "# converting to df\n", "gdf_with_columns = Adapter.toDf(result_range_query, sedona, [\"_c1\"])" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+--------------------+---+\n", "| geometry|_c1|\n", "+--------------------+---+\n", "|LINESTRING (-72.1...| |\n", "|LINESTRING (-72.4...| |\n", "|LINESTRING (-72.4...| |\n", "|LINESTRING (-73.4...| |\n", "|LINESTRING (-73.6...| |\n", "+--------------------+---+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "gdf_with_columns.show(5)" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "root\n", " |-- geometry: geometry (nullable = true)\n", " |-- _c1: string (nullable = true)\n", "\n" ] } ], "source": [ "gdf_with_columns.printSchema()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.12" } }, "nbformat": 4, "nbformat_minor": 4 }