Beispiel #1
0
def _relations_sync(moved_sensor_ids: typing.List[int]):
    logger = get_celery_logger()

    trie: Trie[Zipcode] = Trie()
    for zipcode in Zipcode.query.all():
        trie.insert(zipcode.geohash, zipcode)

    new_relations = []

    # Delete the old relations before rebuilding them
    deleted_relations_count = SensorZipcodeRelation.query.filter(
        SensorZipcodeRelation.sensor_id.in_(moved_sensor_ids)).delete(
            synchronize_session=False)
    logger.info("Deleting %s relations", deleted_relations_count)

    sensors = Sensor.query.filter(Sensor.id.in_(moved_sensor_ids)).all()
    for sensor in sensors:
        gh = sensor.geohash
        latitude = sensor.latitude
        longitude = sensor.longitude
        done = False
        zipcode_ids: typing.Set[int] = set()
        # TODO: Use Postgres' native geolocation extension.
        while gh and not done:
            zipcodes = [
                zipcode for zipcode in trie.get(gh)
                if zipcode.id not in zipcode_ids
            ]

            for zipcode_id, distance in sorted(
                [(
                    z.id,
                    haversine_distance(longitude, latitude, z.longitude,
                                       z.latitude),
                ) for z in zipcodes],
                    key=lambda t: t[1],
            ):
                if distance >= 25:
                    done = True
                    break
                if len(zipcode_ids) >= 25:
                    done = True
                    break
                zipcode_ids.add(zipcode_id)
                data = {
                    "zipcode_id": zipcode_id,
                    "sensor_id": sensor.id,
                    "distance": distance,
                }
                new_relations.append(SensorZipcodeRelation(**data))
            gh = gh[:-1]

    if new_relations:
        logger.info("Creating %s relations", len(new_relations))
        for objs in chunk_list(new_relations):
            db.session.bulk_save_objects(objs)
            db.session.commit()
Beispiel #2
0
 def distance(self, other: "Zipcode") -> float:
     """Distance between this zip and the given zip."""
     if other.id in self._distance_cache:
         return self._distance_cache[other.id]
     if self.id in other._distance_cache:
         return other._distance_cache[self.id]
     self._distance_cache[other.id] = haversine_distance(
         other.longitude,
         other.latitude,
         self.longitude,
         self.latitude,
     )
     return self._distance_cache[other.id]
Beispiel #3
0
def _is_in_range(lat: float, lon: float):
    return haversine_distance(lon, lat, COORDINATES[1],
                              COORDINATES[0]) < RADIUS