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:
Chris Hill-Scott
2021-08-05 19:37:57 +01:00
parent 0cf443e9a6
commit 6a3aba3bc5
5 changed files with 38 additions and 24 deletions

View File

@@ -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 hasnt 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,
])

View File

@@ -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):

View File

@@ -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]

View File

@@ -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:
# Were combining simplified polygons from multiple areas so we