Hi everyone!
I'm building a small application that given a point (latitude, longitude) returns the 10 nearest cities and I thought KNN2 is a good solution for my use case but I'm not able to make it work.
The application must work in a docker container, so all the following commands has been executed in a docker Alpine 3.15.0 container.
Phase 1, install Spatialite and SQLite:
/ # apk add libspatialite
fetch https://dl-cdn.alpinelinux.org/alpine/v3.15/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.15/community/x86_64/APKINDEX.tar.gz
(1/18) Installing libgcc (10.3.1_git20211027-r0)
(2/18) Installing libstdc++ (10.3.1_git20211027-r0)
(3/18) Installing geos (3.10.1-r0)
(4/18) Installing minizip (1.2.11-r2)
(5/18) Installing ca-certificates (20191127-r7)
(6/18) Installing brotli-libs (1.0.9-r5)
(7/18) Installing nghttp2-libs (1.46.0-r0)
(8/18) Installing libcurl (7.80.0-r0)
(9/18) Installing sqlite-libs (3.36.0-r0)
(10/18) Installing libjpeg-turbo (2.1.2-r0)
(11/18) Installing xz-libs (5.2.5-r0)
(12/18) Installing libwebp (1.2.1-r0)
(13/18) Installing zstd-libs (1.5.0-r0)
(14/18) Installing tiff (4.3.0-r0)
(15/18) Installing proj (8.2.0-r0)
(16/18) Installing librttopo (1.1.0-r1)
(17/18) Installing libxml2 (2.9.12-r2)
(18/18) Installing libspatialite (5.0.1-r3)
Executing busybox-1.34.1-r3.trigger
Executing ca-certificates-20191127-r7.trigger
OK: 43 MiB in 32 packages
/ # apk add sqlite
(1/4) Installing ncurses-terminfo-base (6.3_p20211120-r0)
(2/4) Installing ncurses-libs (6.3_p20211120-r0)
(3/4) Installing readline (8.1.1-r0)
(4/4) Installing sqlite (3.36.0-r0)
Executing busybox-1.34.1-r3.trigger
OK: 45 MiB in 36 packages
Phase 2:
/ # unzip worldcities.zip
Archive: worldcities.zip
inflating: license.txt
inflating: worldcities.csv
inflating: worldcities.xlsx
/ # head worldcities.csv
"city","city_ascii","lat","lng","country","iso2","iso3","admin_name","capital","population","id"
/ # sqlite3 worldcities.db
SQLite version 3.36.0 2021-06-18 18:36:39
Enter ".help" for usage hints.
sqlite> .mode csv
sqlite> .import worldcities.csv worldcities
sqlite> SELECT * FROM worldcities LIMIT 1;
Tokyo,Tokyo,35.6897,139.6922,Japan,JP,JPN,"Tōkyō",primary,37977000,1392685764
sqlite> .schema worldcities
CREATE TABLE IF NOT EXISTS "worldcities"(
"city" TEXT,
"city_ascii" TEXT,
"lat" TEXT,
"lng" TEXT,
"country" TEXT,
"iso2" TEXT,
"iso3" TEXT,
"admin_name" TEXT,
"capital" TEXT,
"population" TEXT,
"id" TEXT
, "pinpoint" POINT);
CREATE TRIGGER "ggi_worldcities_pinpoint" BEFORE INSERT ON "worldcities"
FOR EACH ROW BEGIN
SELECT RAISE(ROLLBACK, 'worldcities.pinpoint violates Geometry constraint [geom-type or SRID not allowed]')
WHERE (SELECT geometry_type FROM geometry_columns
WHERE Lower(f_table_name) = Lower('worldcities') AND Lower(f_geometry_column) = Lower('pinpoint')
AND GeometryConstraints(NEW."pinpoint", geometry_type, srid) = 1) IS NULL;
END;
CREATE TRIGGER "ggu_worldcities_pinpoint" BEFORE UPDATE OF "pinpoint" ON "worldcities"
FOR EACH ROW BEGIN
SELECT RAISE(ROLLBACK, 'worldcities.pinpoint violates Geometry constraint [geom-type or SRID not allowed]')
WHERE (SELECT geometry_type FROM geometry_columns
WHERE Lower(f_table_name) = Lower('worldcities') AND Lower(f_geometry_column) = Lower('pinpoint')
AND GeometryConstraints(NEW."pinpoint", geometry_type, srid) = 1) IS NULL;
END;
CREATE TRIGGER "tmu_worldcities_pinpoint" AFTER UPDATE ON "worldcities"
FOR EACH ROW BEGIN
UPDATE geometry_columns_time SET last_update = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
WHERE Lower(f_table_name) = Lower('worldcities') AND Lower(f_geometry_column) = Lower('pinpoint');
END;
CREATE TRIGGER "tmi_worldcities_pinpoint" AFTER INSERT ON "worldcities"
FOR EACH ROW BEGIN
UPDATE geometry_columns_time SET last_insert = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
WHERE Lower(f_table_name) = Lower('worldcities') AND Lower(f_geometry_column) = Lower('pinpoint');
END;
CREATE TRIGGER "tmd_worldcities_pinpoint" AFTER DELETE ON "worldcities"
FOR EACH ROW BEGIN
UPDATE geometry_columns_time SET last_delete = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
WHERE Lower(f_table_name) = Lower('worldcities') AND Lower(f_geometry_column) = Lower('pinpoint');
END;
sqlite> SELECT load_extension('mod_spatialite');
sqlite> SELECT InitSpatialMetaData(1);
1
sqlite> SELECT CreateMissingSystemTables(1);
1
sqlite> SELECT AddGeometryColumn('worldcities', 'pinpoint', 4326, 'POINT', 'XY');
1
sqlite> UPDATE worldcities SET pinpoint = GeomFromText('POINT(' || lat || ' ' || lng || ')', 4326);
sqlite> SELECT CreateSpatialIndex("worldcities", "pinpoint");
1
So far, so good (if I'm not missing any step)
I try my first KNN2 query ...
sqlite> SELECT * FROM knn2 WHERE f_table_name = 'worldcities' AND f_geometry_column = 'pinpoint' AND ref_geometry = MakePoint(41, 36) AND radius = 1.0 AND max_items = 10 AND expand = 0;
Error: no such table: knn2
sqlite> .tables
ElementaryGeometries raster_coverages_srid
ISO_metadata rl2map_configurations
ISO_metadata_reference rl2map_configurations_view
ISO_metadata_view spatial_ref_sys
KNN spatial_ref_sys_all
SE_external_graphics spatial_ref_sys_aux
SE_external_graphics_view spatialite_history
SE_fonts sql_statements_log
SE_fonts_view stored_procedures
SE_raster_styled_layers stored_variables
SE_raster_styled_layers_view topologies
SE_raster_styles vector_coverages
SE_raster_styles_view vector_coverages_keyword
SE_vector_styled_layers vector_coverages_ref_sys
SE_vector_styled_layers_view vector_coverages_srid
SE_vector_styles vector_layers
SE_vector_styles_view vector_layers_auth
SpatialIndex vector_layers_field_infos
data_licenses vector_layers_statistics
geom_cols_ref_sys views_geometry_columns
geometry_columns views_geometry_columns_auth
geometry_columns_auth views_geometry_columns_field_infos
geometry_columns_field_infos views_geometry_columns_statistics
geometry_columns_statistics virts_geometry_columns
geometry_columns_time virts_geometry_columns_auth
idx_ISO_metadata_geometry virts_geometry_columns_field_infos
idx_ISO_metadata_geometry_node virts_geometry_columns_statistics
idx_ISO_metadata_geometry_parent wms_getcapabilities
idx_ISO_metadata_geometry_rowid wms_getmap
networks wms_ref_sys
raster_coverages wms_settings
raster_coverages_keyword worldcities
raster_coverages_ref_sys
My guess is that it should be a KNN2 table .. so I try to create a new one:
sqlite> CREATE VIRTUAL TABLE knn2 USING VirtualKNN2();
Error: no such module: VirtualKNN2
There is a note in the documentation about KNN2: Note: VirtualKNN2 necessarily requires a corresponding library support, so any attempt to open a db-file including a VirtualKNN2 table by using some previous version of the SpatiaLite will surely raise an error condition.
But which library? Probably I'm missing something here ...
Running the same Query but changing the table to knn, it works:
sqlite> sqlite> SELECT * FROM knn WHERE f_table_name = 'worldcities' AND f_geometry_column = 'pinpoint' AND ref_geometry = MakePoint(40.6500,35.8333);
worldcities|pinpoint||3|1|3572|0.0
worldcities|pinpoint||3|2|23964|60234.0327314011
worldcities|pinpoint||3|3|543|79537.9719636182
And here is where I´m stuck .. I don't really know what else I can do.
I also tried to compile from source SQLite (3.37) and Spatialite and same result.
Any help enabling KNN2 will be really appreciated, thanks!