mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-18 21:49:37 -04:00
Store CRS to avoid costly lookup
Looking up the coordinate reference system for a given polygon’s bounds is surprisingly expensive. We can make things run faster by precomputing it at the time of generating the simplified polygons, then storing it in the SQLite database alongside the polygon data.
This commit is contained in:
Binary file not shown.
@@ -150,17 +150,17 @@ def polygons_and_simplified_polygons(feature):
|
||||
'Polygons.perimeter_to_buffer_ratio)'
|
||||
)
|
||||
|
||||
output = (
|
||||
output = [
|
||||
full_resolution.as_coordinate_pairs_long_lat,
|
||||
simplified.as_coordinate_pairs_long_lat,
|
||||
)
|
||||
]
|
||||
|
||||
# Check that the simplification process hasn’t introduced bad data
|
||||
for dataset in output:
|
||||
for polygon in dataset:
|
||||
assert Polygon(polygon).is_valid
|
||||
|
||||
return output
|
||||
return output + [simplified.utm_crs]
|
||||
|
||||
|
||||
def estimate_number_of_smartphones_in_area(country_or_ward_code):
|
||||
@@ -268,13 +268,14 @@ def add_test_areas():
|
||||
print() # noqa: T001
|
||||
print(f_name) # noqa: T001
|
||||
|
||||
feature, _ = polygons_and_simplified_polygons(
|
||||
feature, _, utm_crs = polygons_and_simplified_polygons(
|
||||
feature["geometry"]
|
||||
)
|
||||
areas_to_add.append([
|
||||
f'{dataset_id}-{f_id}', f_name,
|
||||
dataset_id, None,
|
||||
feature, feature,
|
||||
utm_crs,
|
||||
0,
|
||||
])
|
||||
|
||||
@@ -300,7 +301,7 @@ def add_demo_areas():
|
||||
print() # noqa: T001
|
||||
print(f_name) # noqa: T001
|
||||
|
||||
feature, _ = polygons_and_simplified_polygons(
|
||||
feature, _, utm_crs = polygons_and_simplified_polygons(
|
||||
feature["geometry"]
|
||||
)
|
||||
|
||||
@@ -310,6 +311,7 @@ def add_demo_areas():
|
||||
f'{dataset_id}-{f_id}', f_name,
|
||||
dataset_id, None,
|
||||
feature, feature,
|
||||
utm_crs,
|
||||
f_count_of_phones,
|
||||
])
|
||||
|
||||
@@ -334,13 +336,14 @@ def add_countries():
|
||||
print() # noqa: T001
|
||||
print(f_name) # noqa: T001
|
||||
|
||||
feature, simple_feature = (
|
||||
feature, simple_feature, utm_crs = (
|
||||
polygons_and_simplified_polygons(feature["geometry"])
|
||||
)
|
||||
areas_to_add.append([
|
||||
f'ctry19-{f_id}', f_name,
|
||||
dataset_id, None,
|
||||
feature, simple_feature,
|
||||
utm_crs,
|
||||
estimate_number_of_smartphones_in_area(f_id),
|
||||
])
|
||||
|
||||
@@ -376,7 +379,7 @@ def _add_electoral_wards(dataset_id):
|
||||
try:
|
||||
la_id = "lad20-" + ward_code_to_la_id_mapping[ward_code]
|
||||
|
||||
feature, simple_feature = (
|
||||
feature, simple_feature, utm_crs = (
|
||||
polygons_and_simplified_polygons(feature["geometry"])
|
||||
)
|
||||
|
||||
@@ -387,6 +390,7 @@ def _add_electoral_wards(dataset_id):
|
||||
ward_id, ward_name,
|
||||
dataset_id, la_id,
|
||||
feature, simple_feature,
|
||||
utm_crs,
|
||||
estimate_number_of_smartphones_in_area(ward_code),
|
||||
])
|
||||
|
||||
@@ -409,7 +413,7 @@ def _add_local_authorities(dataset_id):
|
||||
|
||||
group_id = "lad20-" + la_id
|
||||
|
||||
feature, simple_feature = (
|
||||
feature, simple_feature, utm_crs = (
|
||||
polygons_and_simplified_polygons(feature["geometry"])
|
||||
)
|
||||
|
||||
@@ -421,6 +425,7 @@ def _add_local_authorities(dataset_id):
|
||||
'ctyua19-' + ctyua_id if ctyua_id else None,
|
||||
feature,
|
||||
simple_feature,
|
||||
utm_crs,
|
||||
None,
|
||||
])
|
||||
repo.insert_broadcast_areas(areas_to_add, keep_old_polygons)
|
||||
@@ -439,7 +444,7 @@ def _add_counties_and_unitary_authorities(dataset_id):
|
||||
|
||||
group_id = "ctyua19-" + ctyua_id
|
||||
|
||||
feature, simple_feature = (
|
||||
feature, simple_feature, utm_crs = (
|
||||
polygons_and_simplified_polygons(feature["geometry"])
|
||||
)
|
||||
|
||||
@@ -447,6 +452,7 @@ def _add_counties_and_unitary_authorities(dataset_id):
|
||||
group_id, group_name,
|
||||
dataset_id, None,
|
||||
feature, simple_feature,
|
||||
utm_crs,
|
||||
None,
|
||||
])
|
||||
|
||||
|
||||
@@ -95,20 +95,27 @@ class BroadcastArea(BaseBroadcastArea, SortableMixin):
|
||||
@classmethod
|
||||
def from_row_with_simple_polygons(cls, row):
|
||||
instance = cls(row[:4])
|
||||
instance.simple_polygons = Polygons(row[4])
|
||||
instance.simple_polygons = Polygons(
|
||||
row[4],
|
||||
utm_crs=row[5],
|
||||
)
|
||||
return instance
|
||||
|
||||
@cached_property
|
||||
def polygons(self):
|
||||
polygons, utm_crs = BroadcastAreasRepository().get_polygons_for_area(self.id)
|
||||
return Polygons(
|
||||
BroadcastAreasRepository().get_polygons_for_area(self.id)
|
||||
polygons, utm_crs=utm_crs
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def simple_polygons(self):
|
||||
return Polygons(
|
||||
simple_polygons, utm_crs = (
|
||||
BroadcastAreasRepository().get_simple_polygons_for_area(self.id)
|
||||
)
|
||||
return Polygons(
|
||||
simple_polygons, utm_crs=utm_crs
|
||||
).utm_polygons
|
||||
|
||||
@cached_property
|
||||
def sub_areas(self):
|
||||
|
||||
@@ -54,7 +54,8 @@ class BroadcastAreasRepository(object):
|
||||
CREATE TABLE broadcast_area_polygons (
|
||||
id TEXT PRIMARY KEY,
|
||||
polygons TEXT NOT NULL,
|
||||
simple_polygons TEXT NOT NULL
|
||||
simple_polygons TEXT NOT NULL,
|
||||
utm_crs TEXT NOT NULL
|
||||
)""")
|
||||
|
||||
conn.execute("""
|
||||
@@ -98,19 +99,19 @@ class BroadcastAreasRepository(object):
|
||||
features_q = """
|
||||
INSERT INTO broadcast_area_polygons (
|
||||
id,
|
||||
polygons, simple_polygons
|
||||
polygons, simple_polygons, utm_crs
|
||||
)
|
||||
VALUES (?, ?, ?)
|
||||
VALUES (?, ?, ?, ?)
|
||||
"""
|
||||
|
||||
with self.conn() as conn:
|
||||
for id, name, area_id, group, polygons, simple_polygons, count_of_phones in areas:
|
||||
for id, name, area_id, group, polygons, simple_polygons, utm_crs, count_of_phones in areas:
|
||||
conn.execute(areas_q, (
|
||||
id, name, area_id, group, count_of_phones
|
||||
))
|
||||
if not keep_old_features:
|
||||
conn.execute(features_q, (
|
||||
id, json.dumps(polygons), json.dumps(simple_polygons),
|
||||
id, json.dumps(polygons), json.dumps(simple_polygons), utm_crs
|
||||
))
|
||||
|
||||
def query(self, sql, *args):
|
||||
@@ -143,7 +144,7 @@ class BroadcastAreasRepository(object):
|
||||
|
||||
def get_areas_with_simple_polygons(self, area_ids):
|
||||
q = """
|
||||
SELECT broadcast_areas.id, name, count_of_phones, broadcast_area_library_id, simple_polygons
|
||||
SELECT broadcast_areas.id, name, count_of_phones, broadcast_area_library_id, simple_polygons, utm_crs
|
||||
FROM broadcast_areas
|
||||
JOIN broadcast_area_polygons on broadcast_area_polygons.id = broadcast_areas.id
|
||||
WHERE broadcast_areas.id IN ({})
|
||||
@@ -152,7 +153,7 @@ class BroadcastAreasRepository(object):
|
||||
results = self.query(q, *area_ids)
|
||||
|
||||
areas = [
|
||||
(row[0], row[1], row[2], row[3], json.loads(row[4]))
|
||||
(row[0], row[1], row[2], row[3], json.loads(row[4]), row[5])
|
||||
for row in results
|
||||
]
|
||||
|
||||
@@ -231,22 +232,22 @@ class BroadcastAreasRepository(object):
|
||||
|
||||
def get_polygons_for_area(self, area_id):
|
||||
q = """
|
||||
SELECT polygons
|
||||
SELECT polygons, utm_crs
|
||||
FROM broadcast_area_polygons
|
||||
WHERE id = ?
|
||||
"""
|
||||
|
||||
results = self.query(q, area_id)
|
||||
|
||||
return json.loads(results[0][0])
|
||||
return json.loads(results[0][0]), results[0][1]
|
||||
|
||||
def get_simple_polygons_for_area(self, area_id):
|
||||
q = """
|
||||
SELECT simple_polygons
|
||||
SELECT simple_polygons, utm_crs
|
||||
FROM broadcast_area_polygons
|
||||
WHERE id = ?
|
||||
"""
|
||||
|
||||
results = self.query(q, area_id)
|
||||
|
||||
return json.loads(results[0][0])
|
||||
return json.loads(results[0][0]), results[0][1]
|
||||
|
||||
@@ -222,7 +222,7 @@ class BroadcastMessage(JSONModel):
|
||||
list(itertools.chain(*(
|
||||
getattr(area, area_attribute) for area in self.areas
|
||||
))),
|
||||
utm_crs=self.areas[0].polygons.utm_polygons.utm_crs,
|
||||
utm_crs=self.areas[0].simple_polygons.utm_polygons.utm_crs,
|
||||
)
|
||||
if area_attribute != 'polygons' and len(self.areas) > 1:
|
||||
# We’re combining simplified polygons from multiple areas so we
|
||||
|
||||
Reference in New Issue
Block a user