2

I have a GPKG file of 46M records and 6.5GB filesize, and need to open about 300 records, where fieldX = Y (Y may change). Opening the entire file would cause memory overflow, while processing the entire file in chunks would take a couple of hours.

I walked through GDAL Python API docs, but there's nothing. Filtering seems to be done by calling a method rather than passing a parameter to Open.

If it's possible to open the file in Fiona and then call a method to filter records (.filter()), that would work too.

Of course, I can find workarounds, but would like to have it rather straightforward.

edit: I tried Fiona's .filter() with where argument (Iterator source, .filter source, OGR docs), but it doesn't seem to work:

import geopandas as gpd
import fiona
from shapely.geometry import Point

ds = (
    (Point(0, 0), 'abcde'),
    (Point(1, 1), 'fghij'),
    (Point(2, 2), 'klmno')
)

gdf = gpd.GeoDataFrame(ds, columns=['geometry', 'fieldX'])
gdf.to_file('test.gpkg', driver='GPKG')

with fiona.open('test.gpkg', layername='test') as fp:
    itr1 = fp.filter(where="fieldX='klmno'")
    print(next(itr1))

    itr2 = fp.filter(where="fieldX like '%klmno%'")
    print(next(itr2))

outputs:

{'type': 'Feature', 'id': '1', 'properties': OrderedDict([('fieldX', 'abcde')]), 'geometry': {'type': 'Point', 'coordinates': (0.0, 0.0)}}
{'type': 'Feature', 'id': '1', 'properties': OrderedDict([('fieldX', 'abcde')]), 'geometry': {'type': 'Point', 'coordinates': (0.0, 0.0)}}

In Sqlite3 this works as expected:

sqlite> .open notebooks/test.gpkg
sqlite> .tables
gpkg_contents           gpkg_spatial_ref_sys    rtree_test_geom_node  
gpkg_extensions         gpkg_tile_matrix        rtree_test_geom_parent
gpkg_geometry_columns   gpkg_tile_matrix_set    rtree_test_geom_rowid 
gpkg_ogr_contents       rtree_test_geom         test                  
sqlite> select * from test where fieldX='klmno';
3|GP|klmno
6
  • 2
    You can find lots of working Python code from the GDAL autotests github.com/OSGeo/gdal/blob/master/autotest/ogr/ogr_gpkg.py. You want to read the layer with ExecuteSQL this way sql_lyr = gpkg_ds.ExecuteSQL('SELECT * FROM "point_no_spi-but-with-dashes"'). For making the query fast create index on fieldX. ExecuteSQL is certainly documented.
    – user30184
    Commented Jun 2, 2021 at 5:58
  • What if you try filtered = filter(lambda f: f['properties']['fieldX']=='klmno', fp)?
    – Taras
    Commented Jun 2, 2021 at 8:11
  • @Taras that works, but it first reads all the records into Python, and I want to avoid doing that (I have 46M records).
    – culebrón
    Commented Jun 2, 2021 at 8:24
  • 1
    You may the approach suggested by @user30184, i.e. from osgeo import ogr; gpkg_source = ogr.Open("test.gpkg",update=False); sql_layer = gpkg_source.ExecuteSQL("SELECT * FROM test WHERE fieldX = 'klmno'"). What does it give?
    – Taras
    Commented Jun 2, 2021 at 8:41
  • 1
    Shall we ask @user30184 to put his comment as a valid answer, do not we?
    – Taras
    Commented Jun 2, 2021 at 9:32

1 Answer 1

1

You can pass a SQL statement to geopandas.read_file.

Something like this:

import geopandas as gpd

sql = f"""
    SELECT * FROM "test"
     WHERE fieldX = 'klmno'
"""
gdf = gpd.read_file("test.gpkg", sql=sql)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.