From 8a68bb5f17a1a92638ee87060dc1c64a66ef65df Mon Sep 17 00:00:00 2001 From: ephe-meral Date: Wed, 10 Aug 2022 10:43:26 +0200 Subject: [PATCH] =?UTF-8?q?=20=F0=9F=97=BA=20Include=20GeoNames=20to=20ver?= =?UTF-8?q?ify=20admin=20boundaries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 +- .../common/python_utils/src/file_converter.py | 8 + .../database/importer/sql/create_tables.sql | 24 + .../importer/src/admin_boundary_importer.py | 82 +- .../database/transformer/dbt/dbt_project.yml | 14 +- .../get_all_versions_of_city_names.sql | 9 + ...match_admin_boundaries_with_city_names.sql | 14 + .../dbt/models/admin_boundaries/cities.sql | 10 + .../admin_boundaries/city_candidates.sql | 22 + .../dbt/models/admin_boundaries/schema.yml | 36 + .../transformer/dbt/models/poi/poi.sql | 2 +- .../dbt/models/poi/poi_address_city.sql | 8 +- .../transformer/dbt/models/poi/schema.yml | 12 +- .../poi_category_by_population.ipynb | 2 +- .../notebooks/popularity_correlation.ipynb | 8 - kuwala/pipelines/admin-boundaries/dockerfile | 1 + .../admin-boundaries/requirements.txt | 4 +- .../src/geonames_controller.py | 71 + kuwala/pipelines/admin-boundaries/src/main.py | 6 + .../google-poi/resources/categories.json | 1199 ++++++++++++++++- 20 files changed, 1481 insertions(+), 53 deletions(-) create mode 100644 kuwala/common/python_utils/src/file_converter.py create mode 100644 kuwala/core/database/transformer/dbt/macros/admin_boundaries/get_all_versions_of_city_names.sql create mode 100644 kuwala/core/database/transformer/dbt/macros/admin_boundaries/match_admin_boundaries_with_city_names.sql create mode 100644 kuwala/core/database/transformer/dbt/models/admin_boundaries/cities.sql create mode 100644 kuwala/core/database/transformer/dbt/models/admin_boundaries/city_candidates.sql create mode 100644 kuwala/core/database/transformer/dbt/models/admin_boundaries/schema.yml create mode 100644 kuwala/pipelines/admin-boundaries/src/geonames_controller.py diff --git a/docker-compose.yml b/docker-compose.yml index 64f0c54d..45688ebb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -75,7 +75,7 @@ services: - POSTGRES_USER=kuwala - POSTGRES_PASSWORD=password - POSTGRES_DB=kuwala - - POSTGRES_MULTIPLE_EXTENSIONS=postgis,hstore,postgis_topology,postgis_raster,pgrouting,h3 + - POSTGRES_MULTIPLE_EXTENSIONS=postgis,hstore,postgis_topology,postgis_raster,pgrouting,h3,unaccent,fuzzystrmatch ports: - '5432:5432' volumes: diff --git a/kuwala/common/python_utils/src/file_converter.py b/kuwala/common/python_utils/src/file_converter.py new file mode 100644 index 00000000..fe9faf1b --- /dev/null +++ b/kuwala/common/python_utils/src/file_converter.py @@ -0,0 +1,8 @@ +import pandas + + +def txt_to_csv(file_path): + read_file = pandas.read_csv( + file_path, delimiter="\t", header=None, low_memory=False + ) + read_file.to_csv(file_path.replace(".txt", ".csv"), index=None, header=False) diff --git a/kuwala/core/database/importer/sql/create_tables.sql b/kuwala/core/database/importer/sql/create_tables.sql index 6d410c59..14499b6f 100644 --- a/kuwala/core/database/importer/sql/create_tables.sql +++ b/kuwala/core/database/importer/sql/create_tables.sql @@ -22,6 +22,30 @@ CREATE TABLE IF NOT EXISTS admin_boundary ( geometry geometry ); +-- Creation of admin_boundary_geonames_cities table + +CREATE TABLE IF NOT EXISTS admin_boundary_geonames_cities ( + geoname_id text NOT NULL PRIMARY KEY, + name text NOT NULL, + ascii_name text, + alternate_names text[], + latitude decimal NOT NULL, + longitude decimal NOT NULL, + feature_class text NOT NULL, + feature_code text, + country_code text, + alternate_country_codes text[], + admin_1_code text, + admin_2_code text, + admin_3_code text, + admin_4_code text, + population integer NOT NULL, + elevation integer, + digital_elevation_model integer NOT NULL, + timezone text NOT NULL, + modification_date date NOT NULL +); + -- Creation of population_density table CREATE TABLE IF NOT EXISTS population_density ( diff --git a/kuwala/core/database/importer/src/admin_boundary_importer.py b/kuwala/core/database/importer/src/admin_boundary_importer.py index 2d201243..4f4dea9a 100644 --- a/kuwala/core/database/importer/src/admin_boundary_importer.py +++ b/kuwala/core/database/importer/src/admin_boundary_importer.py @@ -6,33 +6,18 @@ from pyspark.sql.functions import lit -def import_admin_boundaries( +def import_osm_admin_boundaries( spark, database_host, database_port, database_name, database_url, database_properties, - continent, country, - country_region, + file_path, ): - start_time = time.time() - - logging.info( - f"Starting import of admin boundaries for " - f'{f"{country_region}, " if country_region else ""}{country}, {continent}' - ) - - script_dir = os.path.dirname(__file__) - file_path = os.path.join( - script_dir, - f"../../../../tmp/kuwala/admin_boundary_files/{continent}/{country}" - f'{f"/{country_region}" if country_region else ""}/admin_boundaries.parquet', - ) - if not os.path.exists(file_path): - logging.warning("No admin boundaries file available. Skipping import.") + logging.warning("No OSM admin boundaries file available. Skipping import.") return data = ( @@ -58,6 +43,67 @@ def import_admin_boundaries( path_to_query_file="../sql/create_admin_boundary_geometries.sql", ) + +def import_geonames_cities(spark, database_url, database_properties, file_path): + if not os.path.exists(file_path): + logging.warning("No GeoNames city names available. Skipping import.") + return + + data = spark.read.parquet(file_path) + + data.write.option("truncate", True).jdbc( + url=database_url, + table="admin_boundary_geonames_cities", + mode="overwrite", + properties=database_properties, + ) + + +def import_admin_boundaries( + spark, + database_host, + database_port, + database_name, + database_url, + database_properties, + continent, + country, + country_region, +): + start_time = time.time() + + logging.info( + f"Starting import of admin boundaries for " + f'{f"{country_region}, " if country_region else ""}{country}, {continent}' + ) + + script_dir = os.path.dirname(__file__) + file_path_geonames_cities = os.path.join( + script_dir, "../../../../tmp/kuwala/admin_boundary_files/cities_500.parquet" + ) + file_path_osm_admin_boundaries = os.path.join( + script_dir, + f"../../../../tmp/kuwala/admin_boundary_files/{continent}/{country}" + f'{f"/{country_region}" if country_region else ""}/admin_boundaries.parquet', + ) + + import_geonames_cities( + spark=spark, + database_url=database_url, + database_properties=database_properties, + file_path=file_path_geonames_cities, + ) + import_osm_admin_boundaries( + spark=spark, + database_host=database_host, + database_port=database_port, + database_name=database_name, + database_url=database_url, + database_properties=database_properties, + country=country, + file_path=file_path_osm_admin_boundaries, + ) + logging.info( f"Successfully imported admin boundaries for " f'{f"{country_region}, " if country_region else ""}{country}, {continent} after ' diff --git a/kuwala/core/database/transformer/dbt/dbt_project.yml b/kuwala/core/database/transformer/dbt/dbt_project.yml index a72e5cbc..d7bb2988 100644 --- a/kuwala/core/database/transformer/dbt/dbt_project.yml +++ b/kuwala/core/database/transformer/dbt/dbt_project.yml @@ -1,4 +1,3 @@ - # Name your project! Project names should contain only lowercase characters # and underscores. A good package name should reflect your organization's # name or the intended use of these models @@ -25,6 +24,8 @@ clean-targets: # directories to be removed by `dbt clean` - "dbt_modules" vars: + # Country to match cities + country: 'MT' # POI brand focus_brand: 'focus_brand_id_prefix' # Aggregation grid @@ -43,10 +44,19 @@ vars: models: kuwala_core_transformer: + admin_boundaries: + cities: + +materialized: table poi: poi: +materialized: table + poi_address_city: + +materialized: table + poi_address_country: + +materialized: table poi_aggregated: +materialized: table + poi_matched: + +materialized: table poi_popularity_time_series: - +materialized: table \ No newline at end of file + +materialized: table diff --git a/kuwala/core/database/transformer/dbt/macros/admin_boundaries/get_all_versions_of_city_names.sql b/kuwala/core/database/transformer/dbt/macros/admin_boundaries/get_all_versions_of_city_names.sql new file mode 100644 index 00000000..91a3270b --- /dev/null +++ b/kuwala/core/database/transformer/dbt/macros/admin_boundaries/get_all_versions_of_city_names.sql @@ -0,0 +1,9 @@ +{% macro get_all_versions_of_city_names(country_code) %} + {% set query %} + SELECT DISTINCT geoname_id, unnest(ascii_name || alternate_names) AS name + FROM admin_boundary_geonames_cities + WHERE country_code = '{{ country_code }}' + {% endset %} + + {{ return(query) }} +{% endmacro %} \ No newline at end of file diff --git a/kuwala/core/database/transformer/dbt/macros/admin_boundaries/match_admin_boundaries_with_city_names.sql b/kuwala/core/database/transformer/dbt/macros/admin_boundaries/match_admin_boundaries_with_city_names.sql new file mode 100644 index 00000000..bec34ac8 --- /dev/null +++ b/kuwala/core/database/transformer/dbt/macros/admin_boundaries/match_admin_boundaries_with_city_names.sql @@ -0,0 +1,14 @@ +{% macro match_admin_boundaries_with_city_names(country_code) %} + {% set all_versions_of_city_names = get_all_versions_of_city_names(country_code) %} + + {% set query %} + SELECT id, geoname_id, levenshtein(ab.name, avocn.name) AS levenshtein_distance + FROM admin_boundary AS ab LEFT JOIN ({{ all_versions_of_city_names }}) AS avocn ON + ab.name = avocn.name OR + unaccent(ab.name) = avocn.name OR + ab.name LIKE avocn.name || '%' OR + unaccent(ab.name) LIKE avocn.name || '%' + {% endset %} + + {{ return(query) }} +{% endmacro %} \ No newline at end of file diff --git a/kuwala/core/database/transformer/dbt/models/admin_boundaries/cities.sql b/kuwala/core/database/transformer/dbt/models/admin_boundaries/cities.sql new file mode 100644 index 00000000..8e21a5c8 --- /dev/null +++ b/kuwala/core/database/transformer/dbt/models/admin_boundaries/cities.sql @@ -0,0 +1,10 @@ +SELECT city_name, geometry +FROM {{ ref('city_candidates') }} +INNER JOIN ( + SELECT city_name AS city_name_best_match, MIN(min_levenshtein_distance) AS min_levenshtein_distance_best_match + FROM {{ ref('city_candidates') }} + GROUP BY city_name +) AS best_city_candidates ON + city_candidates.city_name = best_city_candidates.city_name_best_match AND + city_candidates.min_levenshtein_distance = best_city_candidates.min_levenshtein_distance_best_match +WHERE st_contains(geometry, st_setsrid(st_makepoint(candidate_longitude, candidate_latitude), 4326)) \ No newline at end of file diff --git a/kuwala/core/database/transformer/dbt/models/admin_boundaries/city_candidates.sql b/kuwala/core/database/transformer/dbt/models/admin_boundaries/city_candidates.sql new file mode 100644 index 00000000..3dbc41bd --- /dev/null +++ b/kuwala/core/database/transformer/dbt/models/admin_boundaries/city_candidates.sql @@ -0,0 +1,22 @@ +SELECT + abgc.ascii_name AS city_name, + ab.name AS admin_boundary_name, + min_levenshtein_distance, + ab.geometry AS geometry, + abgc.latitude AS candidate_latitude, + abgc.longitude AS candidate_longitude +FROM ( + SELECT id, geoname_id, levenshtein_distance + FROM ({{ match_admin_boundaries_with_city_names(var('country')) }}) AS mabwcn + WHERE geoname_id IS NOT NULL AND levenshtein_distance < 10 +) AS matched_cities +INNER JOIN ( + SELECT id AS id_best_match, MIN(levenshtein_distance) AS min_levenshtein_distance + FROM ({{ match_admin_boundaries_with_city_names(var('country')) }}) AS mabwcn + WHERE geoname_id IS NOT NULL AND levenshtein_distance < 10 + GROUP BY id +) AS matched_cities_min_levenshtein_distances ON + matched_cities.id = matched_cities_min_levenshtein_distances.id_best_match AND + matched_cities.levenshtein_distance = matched_cities_min_levenshtein_distances.min_levenshtein_distance +LEFT JOIN admin_boundary_geonames_cities AS abgc USING (geoname_id) +LEFT JOIN admin_boundary AS ab USING (id) \ No newline at end of file diff --git a/kuwala/core/database/transformer/dbt/models/admin_boundaries/schema.yml b/kuwala/core/database/transformer/dbt/models/admin_boundaries/schema.yml new file mode 100644 index 00000000..d46fedf2 --- /dev/null +++ b/kuwala/core/database/transformer/dbt/models/admin_boundaries/schema.yml @@ -0,0 +1,36 @@ + +version: 2 + +models: + # Cities + - name: cities + description: 'List of matched city names from GeoNames against OSM admin boundaries' + columns: + - name: city_name + description: 'City name from GeoNames' + tests: + - not_null + - name: geometry + description: 'Geometry based on matched admin boundary' + tests: + - not_null + # City candidates + - name: city_candidates + description: 'List of matched city names from GeoNames against OSM admin boundaries' + columns: + - name: city_name + description: 'City name from GeoNames' + tests: + - not_null + - name: admin_boundary_name + description: 'Name of matched admin boundary' + tests: + - not_null + - name: min_levenshtein_distance + description: 'Levenshtein distance of GeoNames city name and admin boundary name' + tests: + - not_null + - name: geometry + description: 'Geometry of matched admin boundary' + tests: + - not_null \ No newline at end of file diff --git a/kuwala/core/database/transformer/dbt/models/poi/poi.sql b/kuwala/core/database/transformer/dbt/models/poi/poi.sql index 7b3d7caf..ce15e3e5 100644 --- a/kuwala/core/database/transformer/dbt/models/poi/poi.sql +++ b/kuwala/core/database/transformer/dbt/models/poi/poi.sql @@ -1,6 +1,6 @@ SELECT poi_matched.*, - poi_address_city.name AS poi_address_city, + poi_address_city.city_name AS poi_address_city, poi_address_country.name AS poi_address_country, h3_to_parent(poi_h3_index::h3index, 8) AS poi_h3_index_res_8, h3_to_parent(poi_h3_index::h3index, 9) AS poi_h3_index_res_9, diff --git a/kuwala/core/database/transformer/dbt/models/poi/poi_address_city.sql b/kuwala/core/database/transformer/dbt/models/poi/poi_address_city.sql index bef7262a..4bced6e7 100644 --- a/kuwala/core/database/transformer/dbt/models/poi/poi_address_city.sql +++ b/kuwala/core/database/transformer/dbt/models/poi/poi_address_city.sql @@ -1,5 +1,3 @@ -SELECT poi_id, name, id -FROM admin_boundary AS ab, {{ ref('poi_matched') }} AS poi -WHERE - kuwala_admin_level = (SELECT max(kuwala_admin_level) FROM admin_boundary) AND - st_contains(ab.geometry, st_setsrid(st_makepoint(poi.longitude, poi.latitude), 4326)) +SELECT DISTINCT poi_id, city_name +FROM {{ ref('cities') }} AS cities, {{ ref('poi_matched') }} AS poi +WHERE st_contains(cities.geometry, st_setsrid(st_makepoint(poi.longitude, poi.latitude), 4326)) diff --git a/kuwala/core/database/transformer/dbt/models/poi/schema.yml b/kuwala/core/database/transformer/dbt/models/poi/schema.yml index 41214e8f..9efb5c3a 100644 --- a/kuwala/core/database/transformer/dbt/models/poi/schema.yml +++ b/kuwala/core/database/transformer/dbt/models/poi/schema.yml @@ -98,25 +98,21 @@ models: - accepted_values: values: [ 15 ] - name: poi_address_city - description: 'Name of the admin boundary with the highest kuwala_admin_level containing POI coordinates' + description: 'Name of the city containing POI coordinates based on matched GeoNames and OSM data' - name: poi_address_country description: 'Name of admin boundary having kuwala_admin_level 1 containing POI coordinates' # POI city based on admin boundary - name: poi_address_city - description: 'Admin boundary name with highest admin level containing POI coordinates' + description: 'City containing POI coordinates based on matched GeoNames and OSM data' columns: - name: poi_id description: 'Unique ID referring to a POI' tests: - unique - not_null - - name: name - description: 'Name of matching admin boundary' - tests: - - not_null - - name: id - description: 'ID of matching admin boundary' + - name: city_name + description: 'Name of matching city' tests: - not_null diff --git a/kuwala/core/jupyter/notebooks/poi_category_by_population.ipynb b/kuwala/core/jupyter/notebooks/poi_category_by_population.ipynb index c91da0c8..a138f62d 100644 --- a/kuwala/core/jupyter/notebooks/poi_category_by_population.ipynb +++ b/kuwala/core/jupyter/notebooks/poi_category_by_population.ipynb @@ -391,4 +391,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/kuwala/core/jupyter/notebooks/popularity_correlation.ipynb b/kuwala/core/jupyter/notebooks/popularity_correlation.ipynb index d747e773..5d8994df 100644 --- a/kuwala/core/jupyter/notebooks/popularity_correlation.ipynb +++ b/kuwala/core/jupyter/notebooks/popularity_correlation.ipynb @@ -32,7 +32,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false, "jupyter": { "outputs_hidden": false }, @@ -65,7 +64,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false, "jupyter": { "outputs_hidden": false }, @@ -93,7 +91,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false, "jupyter": { "outputs_hidden": false }, @@ -124,7 +121,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false, "jupyter": { "outputs_hidden": false }, @@ -217,7 +213,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false, "jupyter": { "outputs_hidden": false }, @@ -243,7 +238,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false, "jupyter": { "outputs_hidden": false }, @@ -275,7 +269,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false, "jupyter": { "outputs_hidden": false }, @@ -334,7 +327,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false, "jupyter": { "outputs_hidden": false }, diff --git a/kuwala/pipelines/admin-boundaries/dockerfile b/kuwala/pipelines/admin-boundaries/dockerfile index 8a391429..d7b33a3d 100644 --- a/kuwala/pipelines/admin-boundaries/dockerfile +++ b/kuwala/pipelines/admin-boundaries/dockerfile @@ -1,6 +1,7 @@ FROM kuwala/base-images:python-java-0.2.0-alpha COPY ./pipelines/admin-boundaries /opt/pipelines/app +COPY ./common/python_utils /opt/common/python_utils WORKDIR /opt/pipelines/app RUN pip install --no-cache-dir -r requirements.txt diff --git a/kuwala/pipelines/admin-boundaries/requirements.txt b/kuwala/pipelines/admin-boundaries/requirements.txt index 5b9dd8e8..d90e296c 100644 --- a/kuwala/pipelines/admin-boundaries/requirements.txt +++ b/kuwala/pipelines/admin-boundaries/requirements.txt @@ -1,3 +1,5 @@ pandas==1.4.1 pyspark==3.2.1 -Shapely==1.8.0 \ No newline at end of file +requests==2.28.1 +Shapely==1.8.0 +tqdm==4.64.0 diff --git a/kuwala/pipelines/admin-boundaries/src/geonames_controller.py b/kuwala/pipelines/admin-boundaries/src/geonames_controller.py new file mode 100644 index 00000000..6c9fd97c --- /dev/null +++ b/kuwala/pipelines/admin-boundaries/src/geonames_controller.py @@ -0,0 +1,71 @@ +import os +import re +import zipfile + +from pyspark.sql.functions import split +from pyspark.sql.types import DateType, DoubleType, IntegerType, StringType, StructType +from python_utils.src.FileDownloader import download_file +from python_utils.src.file_converter import txt_to_csv + + +def download_geonames_file(dump_name, file_path): + download_file( + url=f"https://download.geonames.org/export/dump/{dump_name}.zip", path=file_path + ) + + with zipfile.ZipFile(file_path, "r") as zip_ref: + zip_ref.extractall(file_path.split(f"/{dump_name}.zip")[0]) + + os.remove(file_path) + + +def get_schema(): + return ( + StructType() + .add("geoname_id", IntegerType()) + .add("name", StringType()) + .add("ascii_name", StringType()) + .add("alternate_names", StringType()) + .add("latitude", DoubleType()) + .add("longitude", DoubleType()) + .add("feature_class", StringType()) + .add("feature_code", StringType()) + .add("country_code", StringType()) + .add("alternate_country_codes", StringType()) + .add("admin_1_code", StringType()) + .add("admin_2_code", StringType()) + .add("admin_3_code", StringType()) + .add("admin_4_code", StringType()) + .add("population", IntegerType()) + .add("elevation", IntegerType()) + .add("digital_elevation_model", IntegerType()) + .add("timezone", StringType()) + .add("modification_date", DateType()) + ) + + +def get_geonames_cities(sp): + dump_name = "cities500" + script_dir = os.path.dirname(__file__) + file_path_zip = os.path.join( + script_dir, f"../../../tmp/kuwala/admin_boundary_files/{dump_name}.zip" + ) + file_path_txt = file_path_zip.replace(".zip", ".txt") + file_path_csv = file_path_zip.replace(".zip", ".csv") + r = re.compile("([a-zA-Z]+)([0-9]+)") + m = r.match(dump_name) + file_path_parquet = file_path_zip.replace( + f"{dump_name}.zip", f"{m.group(1)}_{m.group(2)}.parquet" + ) + + download_geonames_file(dump_name=dump_name, file_path=file_path_zip) + txt_to_csv(file_path=file_path_txt) + + df = sp.read.csv(file_path_csv, schema=get_schema()) + df = df.withColumn("alternate_names", split("alternate_names", ",")).withColumn( + "alternate_country_codes", split("alternate_country_codes", ",") + ) + + df.write.mode("overwrite").parquet(file_path_parquet) + os.remove(file_path_txt) + os.remove(file_path_csv) diff --git a/kuwala/pipelines/admin-boundaries/src/main.py b/kuwala/pipelines/admin-boundaries/src/main.py index bf351459..414829a8 100644 --- a/kuwala/pipelines/admin-boundaries/src/main.py +++ b/kuwala/pipelines/admin-boundaries/src/main.py @@ -1,7 +1,12 @@ +import sys + +sys.path.insert(0, "../../../common/") + import argparse import os from admin_boundaries_controller import get_admin_boundaries +from geonames_controller import get_geonames_cities from pyspark.sql import SparkSession if __name__ == "__main__": @@ -23,6 +28,7 @@ .newSession() ) + get_geonames_cities(sp=spark) get_admin_boundaries( sp=spark, continent=continent, country=country, country_region=country_region ) diff --git a/kuwala/pipelines/google-poi/resources/categories.json b/kuwala/pipelines/google-poi/resources/categories.json index b6f8c625..214c0142 100644 --- a/kuwala/pipelines/google-poi/resources/categories.json +++ b/kuwala/pipelines/google-poi/resources/categories.json @@ -487,9 +487,1198 @@ "garden_furniture_store", "furniture_wholesaler", "brewpub", - "design_agency", - "shopping", + "postal_code", + "surveyor", + "industrial_engineer", + "urban_planning_department", + "hydraulic_engineer", + "engineer", + "asian_restaurant", + "labor_union", + "car_inspection_station", + "vitamin_and_supplements_store", + "escape_room_center", + "bicycle_repair_shop", + "lingerie_store", + "animal_hospital", + "funeral_home", + "dance_restaurant", + "public_medical_center", + "vehicle_inspection", + "plastic_fabrication_company", + "bicycle_sharing_location", + "eyebrow_bar", + "senior_high_school", + "dog_day_care_center", + "soccer_field", + "heritage_museum", + "flea_market", + "bird_watching_area", + "drugstore", + "nepalese_restaurant", + "outdoor_activity_organizer", + "sauna", + "waste_management_service", + "newspaper_publisher", + "video_production_service", + "web_hosting_service", + "peak", + "boat_dealer", + "pier", + "license_bureau", + "sculpture", + "congregation", + "finnish_restaurant", + "chalet", + "sports_school", + "athletic_field", + "karaoke_bar", + "public_school", + "painting", + "cultural_landmark", + "hiking_area", + "philharmonic_hall", + "event_planner", + "civic_center", + "picture_frame_shop", + "poster_store", + "coffee_roasters", + "ferris_wheel", + "key_duplication_service", + "boot_repair_shop", + "engraver", + "river", + "faculty_of_pharmacy", + "island", + "city_courthouse", + "high_school", + "tattoo_shop", + "wax_museum", + "amusement_park", + "cottage", + "campground", + "water_park", + "ballroom", + "meeting_room", + "market_researcher", + "club", + "university_library", + "learner_driver_training_area", + "car_battery_store", + "european_institution", + "video_arcade", + "soup_restaurant", + "childrens_cafe", + "vegetarian_cafe_and_deli", + "dog_cafe", + "auto_chemistry_shop", + "horseback_riding_service", + "equestrian_facility", + "primary_school", + "contractor", + "physiotherapist", + "coffee_wholesaler", + "middle_school", + "lake", + "travel_agency", + "educational_consultant", + "city_administration", + "car_detailing_service", + "care_services", + "ice_skating_rink", + "kindergarten", + "scenic_spot", + "reflexologist", + "hunting_and_fishing_store", + "bridal_shop", + "training_school", + "forestry_service", + "glass_merchant", + "pottery_store", + "ferry_terminal", + "public_relations_firm", + "swimming_lake", + "government_hospital", + "skateboard_park", + "arboretum", + "bookkeeping_service", + "recreation_center", + "lutheran_church", + "earth_works_company", + "home_builder", + "demolition_contractor", + "asphalt_contractor", + "curtain_store", + "nursing_home", + "senior_citizens_care_service", + "nursing_agency", + "golf_driving_range", + "business_park", + "barber_supply_store", + "evangelical_church", + "cng_station", + "temp_agency", + "recruiter", + "second_hand_shop", + "pentecostal_church", + "bed_shop", + "cajun_restaurant", + "aquatic_center", + "national_park", + "hockey_rink", + "beauty_school", + "car_race_track", + "goldsmith", + "packaging_supply_store", + "banner_store", + "societe_de_flocage", + "neon_sign_shop", + "boat_storage_facility", + "building_restoration_service", + "furnace_repair_service", + "furnace_store", + "heating_contractor", + "hvac_contractor", + "truck_repair_shop", + "shipyard", + "boat_repair_shop", + "hair_extension_technician", + "hair_extensions_supplier", + "beauty_products_wholesaler", + "technical_school", + "public_golf_course", + "golf_instructor", + "formal_clothing_store", + "vintage_clothing_store", + "dog_park", + "used_bicycle_shop", + "farm_shop", + "needlework_shop", + "rehabilitation_center", + "occupational_safety_and_health", + "portrait_studio", + "tex_mex_restaurant", + "candy_store", + "telecommunications_equipment_supplier", + "gun_shop", + "host_club", + "staple_food_package", + "sunglasses_store", + "antique_store", + "state_archive", + "kitchen_remodeler", + "foreclosure_service", + "beach_pavillion", + "gold_dealer", + "rubber_products_supplier", + "cutlery_store", + "mental_health_service", + "united_methodist_church", + "opel_dealer", + "toyota_dealer", + "ophthalmologist", + "youth_center", + "bingo_hall", + "shipping_and_mailing_service", + "shooting_range", + "orthodox_church", + "amusement_center", + "ravine", + "sports", + "outdoor_clothing_and_equipment_shop", + "orthopedic_clinic", + "surgeon", + "mri_center", + "occupational_therapist", + "sports_medicine_physician", + "machine_maintenance", "irish_pub", + "public_sauna", + "dressmaker", + "tennis_court", + "gas_shop", + "laboratory", + "trucking_company", + "transmission_shop", + "patisserie", + "internist", + "housing_complex", + "cell_phone_accessory_store", + "insulation_materials_store", + "animal_rescue_service", + "snowboard_shop", + "baseball_goods_store", + "martial_arts_supply_store", + "tennis_store", + "makeup_artist", + "perfume_store", + "meat_wholesaler", + "outlet_store", + "energy_supplier", + "laser_tag_center", + "design_agency", + "occupational_medical_physician", + "yarn_store", + "dance_pavillion", + "public_swimming_pool", + "basketball_court", + "tanning_studio", + "acrobatic_diving_pool", + "theater_company", + "washer_and_dryer_store", + "carpenter", + "preschool", + "camera_store", + "recycling_center", + "concrete_contractor", + "internet_shop", + "gay_night_club", + "honey_farm", + "sushi_takeaway", + "shelving_store", + "industrial_equipment_supplier", + "stainless_steel_plant", + "australian_restaurant", + "fraternal_organization", + "vocational_training_school", + "instruction", + "baptist_church", + "railway_services", + "health_and_beauty_shop", + "photo_lab", + "photo_restoration_service", + "invitation_printing_service", + "electric_vehicle_charging_station", + "work_clothes_store", + "audio_visual_equipment_supplier", + "laundry", + "auto_spring_shop", + "horse_riding_school", + "carriage_ride_service", + "tack_shop", + "day_spa", + "children_hall", + "soccer_practice", + "winery", + "gay_bar", + "electrical_repair_shop", + "wholesale_bakery", + "electronics_manufacturer", + "driving_school", + "passport_photo_processor", + "observatory", + "employment_agency", + "war_museum", + "railroad_company", + "community_college", + "small_engine_repair_service", + "trailer_dealer", + "boat_trailer_dealer", + "textile_engineer", + "general_practitioner", + "gynecologist", + "fuel_supplier", + "porsche_dealer", + "ski_resort", + "establishment_service", + "wheel_store", + "nissan_dealer", + "mortgage_lender", + "family_day_care_service", + "university_hospital", + "small_appliance_repair_service", + "motorcycle_repair_shop", + "structural_engineer", + "sports_club", + "building_materials_market", + "mercedes_benz_dealer", + "sauna_store", + "batting_cage_center", + "veterans_organization", + "law_firm", + "silversmith", + "home_health_care_service", + "dental_lab", + "beach", + "village_hall", + "fortress", + "industrial_building", + "army_museum", + "rare_book_store", + "hearing_aid_store", + "scout_hall", + "cabinet_store", + "childrens_furniture_store", + "polytechnic_school", + "thai_massage_shop", + "foot_massage_parlor", + "citizen_information_bureau", + "osteopath", + "power_plant", + "restaurant_supply_store", + "trailer_repair_shop", + "truck_parts_supplier", + "truck_dealer", + "contact_lenses_supplier", + "eye_care_center", + "warehouse", + "nature_preserve", + "handicraft", + "sports_massage_therapist", + "student_union", + "indoor_cycling", + "valet_parking_service", + "architect", + "social_services_organization", + "pool_hall", + "equipment_rental_agency", + "log_cabins", + "metal_fabricator", + "boat_builder", + "amateur_theatre", + "jazz_club", + "port_authority", + "rock_climbing_centre", + "orchard", + "theater_production", + "cottage_rental", + "university", + "montessori_school", + "exhibition_and_trade_center", + "vietnamese_restaurant", + "south_east_asian_restaurant", + "skateboard_shop", + "farm_equipment_supplier", + "rv_park", + "political_party", + "machining_manufacturer", + "taxi_stand", + "boat_club", + "regional_government_office", + "machine_shop", + "metal_working_shop", + "steel_fabricator", + "hydraulic_repair_service", + "digital_printing_service", + "dvd_store", + "music_store", + "oriental_goods_store", + "train_depot", + "hunting_store", + "korean_restaurant", + "tae_kwon_do_comp_area", + "dance_club", + "tool_rental_service", + "construction_machine_rental_service", + "crane_rental_agency", + "computer_consultant", + "environmental_program", + "corporate_campus", + "home_help", + "jehovahs_witness_church", + "diesel_engine_repair_service", + "construction_material_wholesaler", + "saw_mill", + "bathroom_remodeler", + "hot_tub_store", + "fishing_charter", + "metal_workshop", + "rock_climbing", + "building_firm", + "peninsula", + "used_furniture_store", + "electrical_installation_service", + "self_defense_school", + "emergency_services", + "seating_area", + "homeowners_association", + "investment_company", + "auto_glass_shop", + "auto_dent_removal_service", + "auto_restoration_service", + "wheel_alignment_service", + "function_room_facility", + "fastener_supplier", + "school_center", + "automobile_storage_facility", + "real_estate_developer", + "self_storage_facility", + "rv_storage_facility", + "luggage_storage_facility", + "electronics_repair_shop", + "venture_capital_company", + "off_road_race_track", + "disc_golf_course", + "karaoke", + "military_base", + "state_department_of_tourism", + "marketing", + "motorcycle_dealer", + "seventh_day_adventist_church", + "event_ticket_seller", + "psychotherapist", + "grill_store", + "motorcycle_parts_store", + "seed_supplier", + "food_manufacturing_supply", + "internet_service_provider", + "bearing_supplier", + "students_support_association", + "property_maintenance", + "fur_coat_shop", + "plastic_products_supplier", + "adventure_sports", + "airline", + "dance_hall", + "student_dormitory", + "glazier", + "business_administration_service", + "postal_code_prefix", + "arena", + "auto_painting", + "excavating_contractor", + "shipping_company", + "van_rental_agency", + "visa_and_passport_office", + "art_restoration_service", + "indian_grocery_store", + "internet_marketing_service", + "real_estate_auctioneer", + "adult_day_care_center", + "denture_care_center", + "emergency_dental_service", + "dental_radiology", + "raft_trip_outfitter", + "paintball_center", + "cleaning_service", + "window_cleaning_service", + "traffic_officer", + "rock_shop", + "plumber", + "linens_store", + "trust_bank", + "research_and_product_development", + "catering_food_and_drink_supplies", + "metal_industry_suppliers", + "stable", + "junk_dealer", + "childrens_hospital", + "auto_body_parts_supplier", + "barbecue_spots", + "medical_lab", + "eastern_orthodox_church", + "money_order_service", + "money_transfer_service", + "design", + "paper_store", + "media_house", + "facial_spa", + "health_consultant", + "automation_company", + "security_guard_service", + "country_house", + "importer", + "stage", + "tutoring_service", + "wetland", + "business_school", + "handicraft_fair", + "plywood_supplier", + "swimming_basin", + "channel", + "general_contractor", + "short_term_apartment_rental_agency", + "extended_stay_hotel", + "public_recycling_container_location", + "entertainment_and_recreation", + "food_manufacturer", + "transportation_infrastructure", + "family_counselor", + "miniatures_store", + "game_store", + "trading_card_store", + "live_music_bar", + "human_ressource_consulting", + "social_worker", + "paintings_store", + "camping_cabin", + "burrito_restaurant", + "bus_company", + "scandinavian_restaurant", + "aromatherapy_service", + "utility_contractor", + "trailer_supply_store", + "woodworking_supply_store", + "jewelry_manufacturer", + "outlet_mall", + "pawn_shop", + "hockey_field", + "vocational_college", + "department_of_public_safety", + "motorcycle_shop", + "cycling_park", + "bicycle_rental_service", + "parking_lot_for_bicycles", + "bicycle_club", + "ski_rental_service", + "snowboard_rental_service", + "hospital_department", + "upholstery_shop", + "european_restaurant", + "fondue_restaurant", + "auto_wrecker", + "auto_parts_market", + "medical_equipment_manufacturer", + "chemical_plant", + "appliance_parts_supplier", + "pipe_supplier", + "road_construction_company", + "fashion_designer", + "knitwear_manufacturer", + "electrician", + "residents_association", + "meditation_center", + "football_field", + "wedding_buffet", + "vaporizer_store", + "airport_parking_lot", + "religious_destination", + "veterinary_care", + "correctional_services_department", + "fire_protection_service", + "window_treatment_store", + "circus", + "athletic_club", + "auction_house", + "credit_union", + "loan_agency", + "auto_electrical_service", + "fairground", + "laser_cutting_service", + "machine_workshop", + "family_planning_center", + "foster_care_service", + "ford_dealer", + "kia_dealer", + "musical_instrument_repair_shop", + "violin_shop", + "stringed_intrument_maker", + "athletic_track", + "mechanical_contractor", + "meat_processor", + "screen_store", + "machine_construction", + "mechanical_engineer", + "children_amusement_center", + "bank_or_atm", + "food_processing_company", + "sewing_company", + "pediatrician", + "indoor_golf_course", + "fire_damage_restoration_service", + "water_damage_restoration_service", + "spanish_restaurant", + "tire_repair_shop", + "oil_change_service", + "social_services", + "handyman", + "volkswagen_dealer", + "seat_dealer", + "audi_dealer", + "animal_protection_organization", + "table_tennis_supply_store", + "pet_friendly_accommodation", + "health_resort", + "construction_machine_dealer", + "snowmobile_rental_service", + "motor_scooter_dealer", + "atv_dealer", + "flag_store", + "curling_hall", + "masonry_supply_store", + "window_supplier", + "feed_store", + "sauna_club", + "syrian_restaurant", + "cancer_treatment_center", + "coaching_center", + "social_club", + "interior_decoration", + "midwife", + "paper_mill", + "castle", + "modern_european_restaurant", + "advertising_service", + "e_commerce_service", + "locksmith", + "park_and_ride", + "discount_store", + "do_it_yourself_store", + "modeling_agency", + "golf_shop", + "mountain_cable_car", + "mobile_home_park", + "public_bathroom", + "guitar_store", + "bus_charter", + "information_services", + "martial_arts_school", + "adult_entertainment_store", + "interior_architect_office", + "municipal_administration_office", + "yemenite_restaurant", + "event_technology_service", + "audio_visual_equipment_rental_service", + "karaoke_equipment_rental_service", + "voluntary_fire_brigade", + "marine", + "baseball_field", + "rapids", + "computer_accessories_store", + "music_college", + "recycling_drop_off_location", + "manor_house", + "district_government_office", + "church_of_jesus_christ_of_latter_day_saints", + "air_duct_cleaning_service", + "air_conditioning_repair_service", + "rest_stop", + "athletic_park", + "mill", + "rectory", + "folk_high_school", + "used_computer_store", + "welder", + "ethnic_restaurant", + "outerwear_store", + "logistics_service", + "logging_contractor", + "appliance_repair_service", + "textiles", + "hobby_store", + "hair_care", + "psychiatrist", + "ready_mix_concrete_supplier", + "chocolate_factory", + "commercial_real_estate_agency", + "youth_clothing_store", + "indoor_snowcenter", + "hockey_supply_store", + "office", + "geological_research_company", + "cottage_village", + "candle_store", + "tent_rental_service", + "dim_sum_restaurant", + "restaurant_or_cafe", + "room", + "observation_deck", + "lumber_store", + "consignment_shop", + "driving_test_centre", + "landscaping_supply_store", + "camp", + "data_recovery_service", + "immigration_detention_center", + "memorial_park", + "fertilizer_supplier", + "video_editing_service", + "camping_farm", + "social_welfare_center", + "insulator_supplier", + "dude_ranch", + "roofing_contractor", + "psychologist", + "package_locker", + "hot_bedstone_spa", + "intersection", + "beer_distributor", + "seafood_wholesaler", + "skoda_dealer", + "seminary", + "ferry_service", + "beautician", + "physical_fitness_program", + "diamond_dealer", + "gemologist", + "clock_repair_service", + "hydraulic_equipment_supplier", + "train_repairing_center", + "gas_company", + "down_home_cooking_restaurant", + "drum_store", + "sheet_music_store", + "piano_store", + "musical_instrument_rental_service", + "dj_supply_store", + "social_security_office", + "research_engineer", + "antique_furniture_store", + "oil_company", + "religious_goods_store", + "moving_company", + "open_air_museum", + "part_time_daycare", + "rowing_club", + "parish", + "photography_service", + "iron_works", + "boat_accessories_supplier", + "tree_service", + "baking_supply_store", + "log_home_builder", + "fishing_pond", + "zoo", + "bus_ticket_agency", + "persian_restaurant", + "waldorf_kindergarten", + "lamp_repair_service", + "remodeler", + "indoor_playground", + "architecture_firm", + "african_restaurant", + "tattoo_and_piercing_shop", + "heritage_building", + "billiards_supply_store", + "alternative_fuel_station", + "insulation_contractor", + "costume_store", + "event_management_company", + "wood_industry", + "foundry", + "mobility_equipment_supplier", + "fair_trade_organization", + "coffee_machine_supplier", + "free_parking_lot", + "concrete_product_supplier", + "ramen_restaurant", + "army_and_navy_store", + "coast_guard_station", + "countertop_store", + "garbage_dump", + "organic_restaurant", + "stall_installation_service", + "bead_store", + "monument", + "roofing_supply_store", + "restaurant_brasserie", + "miniature_golf_course", + "dry_cleaner", + "mailing_service", + "psychiatric_hospital", + "english_restaurant", + "fusion_restaurant", + "animal_shelter", + "legal_affairs_bureau", + "school_house", + "electric_utility_company", + "rv_repair_shop", + "auto_bodywork_mechanic", + "tool_repair_shop", + "self_service_car_wash", + "gymnastics_center", + "auditorium", + "sewing_machine_repair_service", + "haberdashery", + "notions_store", + "sewing_machine_store", + "screen_printing_shop", + "embroidery_service", + "housing_society", + "water_utility_company", + "womens_personal_trainer", + "badminton_court", + "snowmobile_dealer", + "interior_decorator", + "music", + "blacksmith", + "research_foundation", + "telecommunications_contractor", + "obstetrics_gynecology_clinic", + "plastic_surgeon", + "race_course", + "pharmaceutical_products_wholesaler", + "doner_kebab_restaurant", + "imax_theater", + "employment_center", + "city_employment_department", + "import_export_company", + "glass_shop", + "x_ray_lab", + "repair_service", + "leisurecentre", + "boat_rental_service", + "appliances_customer_service", + "hookah_store", + "aerial_installation_service", + "prosthetics", + "hall", + "city_district_office", + "food_and_beverage_consultant", + "currency_exchange_service", + "asbestos_testing_service", + "recording_studio", + "pet_boarding_service", + "utility_trailer_dealer", + "food_store", + "meat_packer", + "travel", + "painter", + "freight_forwarding_service", + "appliances", + "telecommunications", + "sailing_club", + "biotechnology_company", + "dental_implants_periodontist", + "pediatric_dentist", + "orthodontist", + "rental", + "construction_equipment_supplier", + "scale_model_shop", + "comic_book_store", + "stone_carving", + "agricultural_service", + "wig_shop", + "water_works", + "industrial_real_estate_agency", + "moving_and_storage_service", + "gambling_house", + "mechanic", + "refrigerator_repair_service", + "water_treatment_plant", + "tenant_ownership", + "technical_education_academy", + "welding_supply_store", + "debt_collecting", + "establishment", + "copier_repair_service", + "camera_repair_shop", + "tennis_instructor", + "tennis_club", + "massage_school", + "medical_spa", + "fertility_clinic", + "wood_floor_installation_service", + "measuring_instruments_supplier", + "sand_and_gravel_supplier", + "rv_supply_store", + "mobile_home_rental_agency", + "mobile_home_dealer", + "fish_and_chips_takeaway", + "glassware_store", + "gymnasium_school", + "noodle_shop", + "art_supply_store", + "beverages", + "building_equipment_hire_service", + "aerial_photographer", + "copy_shop", + "ceramic_manufacturer", + "chamber_of_handicrafts", + "adventure_sports_center", + "meditation_instructor", + "outdoor_bath", + "swimming_school", + "dairy_farm", + "wedding_bakery", + "design_institute", + "refrigerator_store", + "electronic_parts_supplier", + "dance_store", + "energy_equipment_and_solutions", + "city_tax_office", + "tax_collectors_office", + "leather_repair_service", + "boot_store", + "western_apparel_store", + "leather_cleaning_service", + "orthopedic_shoe_store", + "massage", + "country_club", + "skate_sharpening_service", + "fund_management_company", + "lawn_mower_repair_service", + "lawn_mower_store", + "outboard_motor_store", + "childrens_library", + "stamp_shop", + "latin_american_restaurant", + "venezuelan_restaurant", + "city_government_office", + "paint_manufacturer", + "first_aid", + "volvo_dealer", + "animal_control_service", + "special_education_school", + "steel_distributor", + "army_facility", + "computer_networking_center", + "computer_software_store", + "electronics_company", + "wok_restaurant", + "community_garden", + "auto_radiator_repair_service", + "radiator_repair_service", + "supreme_court", + "cleaners", + "eclectic_restaurant", + "tax_preparation", + "transportation", + "district_court", + "toy_museum", + "professional_and_hobby_associations", + "mobile_home_supply_store", + "balloon_store", + "ski_club", + "airsoft_gun_shop", + "border_crossing_station", + "soup_shop", + "community_health_center", + "south_asia_restaurant", + "news_service", + "legally_defined_lodging", + "clothing_alteration_service", + "outdoor_activities", + "protestant_church", + "workers_club", + "horse_riding_field", + "pony_club", + "equestrian_club", + "racing_car_parts_store", + "mazda_dealer", + "mitsubishi_dealer", + "fiat_dealer", + "alfa_romeo_dealer", + "jeep_dealer", + "train_yard", + "eye_care", + "body_piercing_shop", + "cooking_school", + "ambulance_service", + "japanese_grocery_store", + "californian_restaurant", + "electrical_engineer", + "holiday_park", + "regional_airport", + "surplus_store", + "wedding_store", + "private_equity_firm", + "cleaning_products_supplier", + "makerspace", + "garage_door_supplier", + "door_supplier", + "travellers_lodge", + "fishing_pier", + "rowing_area", + "tuxedo_shop", + "t_shirt_store", + "water_mill", + "fishing_camp", + "dinner_theater", + "squash_court", + "chiropractor", + "wesleyan_church", + "party_equipment_rental_service", + "metal_supplier", + "hindu_temple", + "dog_trainer", + "youth_hostel", + "uniform_store", + "business_development_service", + "sheltered_housing", + "door_manufacturer", + "tobacco_supplier", + "drinking_water_fountain", + "home_theater_store", + "indonesian_restaurant", + "methodist_church", + "amusement_park_ride", + "carpet_manufacturer", + "parochial_school", + "sundae_restaurant", + "lock_store", + "swimming_pool_supply_store", + "plus_size_clothing_store", + "culinary_school", + "internet_cafe", + "guitar_instructor", + "car_stereo_store", + "senior_citizen_center", + "consumer_advice_center", + "paper_distributor", + "mountain_hut", + "machinery_parts_manufacturer", + "mobile_catering", + "gas_installation_service", + "motor_scooter_repair_shop", + "farmstay", + "canoe_and_kayak_rental_service", + "shop_supermarket_furniture_store", + "nursing_school", + "counselor", + "waxing_hair_removal_service", + "skin_care_clinic", + "gymnastics_club", + "delivery_chinese_restaurant", + "flower_market", + "sewage_treatment_plant", + "entertainment_agency", + "military_barrack", + "german_restaurant", + "income_tax_help_association", + "record_storage_facility", + "video_camera_repair_service", + "kennel", + "truck_stop", + "repairs", + "czech_restaurant", + "nutritionist", + "rheumatologist", + "audio_visual_consultant", + "gasfitter", + "trailer_manufacturer", + "truck_accessories_store", + "book_publisher", + "housing_development", + "prosthodontist", + "hair_removal_service", + "armed_forces_association", + "fireworks_store", + "boarding_house", + "civil_engineer", + "environmental_engineer", + "youth_groups", + "adult_entertainment_club", + "festival", + "gardening", + "honda_dealer", + "alcoholism_treatment_program", + "full_gospel_church", + "pressure_washing_service", + "childrens_farm", + "thai_massage_therapist", + "e_commerce_agency", + "exporter", + "mandarin_restaurant", + "occupational_health_service", + "practitioner_service_location", + "judo_school", + "drug_testing_service", + "travel_clinic", + "blood_testing_service", + "emergency_training", + "specialized_hospital", + "childrens_book_store", + "christian_book_store", + "weightlifting_area", + "foot_care", + "school_district_office", + "football_club", + "construction_and_maintenance_office", + "bicycles", + "veterans_center", + "housing_authority", + "low_income_housing_program", + "professional_services", + "canoe_and_kayak_tour_agency", + "sports_equipment_rental_service", + "eyelash_salon", + "electric_vehicle_charging_station_contractor", + "self_service_restaurant", + "junkyard", + "fire_protection_equipment_supplier", + "estate_appraiser", + "real_estate_attorney", + "civil_law_attorney", + "antique_furniture_restoration_service", + "municipal_department_of_tourism", + "customs_department", + "flooring_contractor", + "floor_refinishing_service", + "orphanage", + "pet_cemetery", + "african_goods_store", + "wildlife_and_safari_park", + "dogsled_ride_service", + "bowling_supply_shop", + "taekwondo_school", + "auto_tune_up_service", + "sports_activity_location", + "mexican_torta_restaurant", + "garbage_collection_service", + "international_school", + "pet_trainer", + "state_park", + "go_kart_track", + "skate_shop", + "georgian_restaurant", + "used_motorcycle_dealer", + "electrical_substation", + "gift_wrap_store", + "wind_turbine_builder", + "notary_public", + "shredding_service", + "mailbox_rental_service", + "futsal_field", + "vegetation", + "hydroelectric_power_plant", + "sculpture_museum", + "movie_rental_store", + "county_government_office", + "baseball", + "auto_air_conditioning_service", + "warehouse_store", + "addiction_treatment_center", + "small_plates_restaurant", + "commercial_cleaning_service", + "entertainer", + "vineyard", + "russian_orthodox_church", + "childrens_home", + "child_health_care_centre", + "shooting_event_area", + "sportwear_manufacturer", + "exhibit", + "mordern_izakaya_restaurants", + "japanese_authentic_restaurant", + "custom_tailor", + "tailor", + "knife_store", + "justice_department", + "hawaiian_restaurant", + "auto_sunroof_shop", + "citroen_dealer", + "peugeot_dealer", + "isuzu_dealer", + "hyundai_dealer", + "renault_dealer", + "suzuki_dealer", + "public_health_department", + "cabinet_maker", + "farmers_market", + "yacht_broker", + "fishing", + "planetarium", + "wholesale_plant_nursery", + "emergency_room", + "deck_builder", + "patients_support_association", + "kosher_grocery_store", + "travel_lounge", + "green_energy_supplier", + "race_car_dealer", + "fax_service", + "used_tire_shop", + "church_supply_store", + "outdoor_equestrian_facility", + "rail_museum", + "ethiopian_restaurant", + "tractor_repair_shop", + "nurse_practitioner", + "padel_court", + "bay", + "wellness_hotel", + "computer_security_service", "heritage_preservation", "fish_restaurant", "chinese_supermarket", @@ -663,7 +1852,6 @@ "sports", "dive_club", "part_time_daycare", - "preschool", "child_care_agency", "creche", "public_safety_office", @@ -671,11 +1859,6 @@ "hoagie_restaurant", "northern_italian_restaurant", "southern_italian_restaurant", - "uniform_store", - "restaurant_supply_store", - "food_store", - "live_music_bar", - "noodle_shop" ] }, "office": {