2018-01-19 18:14:57 +00:00
|
|
|
from datetime import datetime
|
|
|
|
|
2017-12-12 20:46:21 +00:00
|
|
|
from celery.utils.log import get_task_logger
|
|
|
|
|
|
|
|
from sqlalchemy import insert, distinct
|
2018-01-21 20:06:27 +00:00
|
|
|
from sqlalchemy.sql import null, and_, func, or_, update
|
2018-01-19 18:14:57 +00:00
|
|
|
from sqlalchemy.sql.expression import literal_column, case
|
2017-12-12 20:46:21 +00:00
|
|
|
|
2017-12-13 09:58:48 +00:00
|
|
|
from ogn.model import AircraftBeacon, DeviceStats, ReceiverStats
|
2017-12-12 20:46:21 +00:00
|
|
|
|
|
|
|
from .celery import app
|
2018-01-19 18:14:57 +00:00
|
|
|
from ogn.model.receiver_beacon import ReceiverBeacon
|
2017-12-12 20:46:21 +00:00
|
|
|
|
|
|
|
logger = get_task_logger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
@app.task
|
2017-12-13 13:08:29 +00:00
|
|
|
def update_device_stats(session=None, date=None):
|
2018-01-11 07:35:07 +00:00
|
|
|
"""Add/update device stats."""
|
2017-12-12 20:46:21 +00:00
|
|
|
|
2017-12-13 13:08:29 +00:00
|
|
|
if session is None:
|
|
|
|
session = app.session
|
|
|
|
|
2017-12-12 20:46:21 +00:00
|
|
|
if not date:
|
|
|
|
logger.warn("A date is needed for calculating stats. Exiting")
|
|
|
|
return None
|
|
|
|
|
|
|
|
# First kill the stats for the selected date
|
2017-12-13 13:08:29 +00:00
|
|
|
deleted_counter = session.query(DeviceStats) \
|
2017-12-12 20:46:21 +00:00
|
|
|
.filter(DeviceStats.date == date) \
|
|
|
|
.delete()
|
|
|
|
|
2018-01-19 18:14:57 +00:00
|
|
|
# Since "distinct count" does not work in window functions we need a work-around for receiver counting
|
|
|
|
sq = session.query(AircraftBeacon,
|
|
|
|
func.dense_rank()
|
|
|
|
.over(partition_by=AircraftBeacon.device_id, order_by=AircraftBeacon.receiver_id)
|
|
|
|
.label('dr')) \
|
2018-01-21 20:06:27 +00:00
|
|
|
.filter(and_(func.date(AircraftBeacon.timestamp) == date, AircraftBeacon.device_id != null())) \
|
2018-01-19 18:14:57 +00:00
|
|
|
.filter(or_(AircraftBeacon.error_count == 0, AircraftBeacon.error_count == null())) \
|
|
|
|
.subquery()
|
|
|
|
|
|
|
|
# Calculate stats, firstseen, lastseen and last values != NULL
|
2017-12-13 13:08:29 +00:00
|
|
|
device_stats = session.query(
|
2018-01-19 18:14:57 +00:00
|
|
|
distinct(sq.c.device_id).label('device_id'),
|
|
|
|
func.date(sq.c.timestamp).label('date'),
|
|
|
|
func.max(sq.c.dr)
|
|
|
|
.over(partition_by=sq.c.device_id)
|
|
|
|
.label('receiver_count'),
|
|
|
|
func.max(sq.c.altitude)
|
|
|
|
.over(partition_by=sq.c.device_id)
|
|
|
|
.label('max_altitude'),
|
|
|
|
func.count(sq.c.id)
|
|
|
|
.over(partition_by=sq.c.device_id)
|
|
|
|
.label('aircraft_beacon_count'),
|
|
|
|
func.first_value(sq.c.timestamp)
|
|
|
|
.over(partition_by=sq.c.device_id, order_by=case([(sq.c.timestamp == null(), None)], else_=sq.c.timestamp).asc().nullslast())
|
|
|
|
.label('firstseen'),
|
|
|
|
func.first_value(sq.c.timestamp)
|
|
|
|
.over(partition_by=sq.c.device_id, order_by=case([(sq.c.timestamp == null(), None)], else_=sq.c.timestamp).desc().nullslast())
|
|
|
|
.label('lastseen'),
|
|
|
|
func.first_value(sq.c.aircraft_type)
|
|
|
|
.over(partition_by=sq.c.device_id, order_by=case([(sq.c.aircraft_type == null(), None)], else_=sq.c.timestamp).desc().nullslast())
|
|
|
|
.label('aircraft_type'),
|
|
|
|
func.first_value(sq.c.stealth)
|
|
|
|
.over(partition_by=sq.c.device_id, order_by=case([(sq.c.stealth == null(), None)], else_=sq.c.timestamp).desc().nullslast())
|
|
|
|
.label('stealth'),
|
|
|
|
func.first_value(sq.c.software_version)
|
|
|
|
.over(partition_by=sq.c.device_id, order_by=case([(sq.c.software_version == null(), None)], else_=sq.c.timestamp).desc().nullslast())
|
|
|
|
.label('software_version'),
|
|
|
|
func.first_value(sq.c.hardware_version)
|
|
|
|
.over(partition_by=sq.c.device_id, order_by=case([(sq.c.hardware_version == null(), None)], else_=sq.c.timestamp).desc().nullslast())
|
|
|
|
.label('hardware_version'),
|
|
|
|
func.first_value(sq.c.real_address)
|
|
|
|
.over(partition_by=sq.c.device_id, order_by=case([(sq.c.real_address == null(), None)], else_=sq.c.timestamp).desc().nullslast())
|
|
|
|
.label('real_address')) \
|
2017-12-12 20:46:21 +00:00
|
|
|
.subquery()
|
|
|
|
|
|
|
|
# And insert them
|
|
|
|
ins = insert(DeviceStats).from_select(
|
2018-01-19 18:14:57 +00:00
|
|
|
[DeviceStats.device_id, DeviceStats.date, DeviceStats.receiver_count, DeviceStats.max_altitude, DeviceStats.aircraft_beacon_count, DeviceStats.firstseen, DeviceStats.lastseen, DeviceStats.aircraft_type, DeviceStats.stealth,
|
|
|
|
DeviceStats.software_version, DeviceStats.hardware_version, DeviceStats.real_address],
|
2017-12-12 20:46:21 +00:00
|
|
|
device_stats)
|
2017-12-13 13:08:29 +00:00
|
|
|
res = session.execute(ins)
|
2017-12-12 20:46:21 +00:00
|
|
|
insert_counter = res.rowcount
|
2017-12-13 13:08:29 +00:00
|
|
|
session.commit()
|
2018-01-11 07:35:07 +00:00
|
|
|
logger.debug("DeviceStats for {}: {} deleted, {} inserted".format(date, deleted_counter, insert_counter))
|
2017-12-12 20:46:21 +00:00
|
|
|
|
2018-01-11 07:35:07 +00:00
|
|
|
return "DeviceStats for {}: {} deleted, {} inserted".format(date, deleted_counter, insert_counter)
|
2017-12-12 20:46:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
@app.task
|
2018-01-21 20:06:27 +00:00
|
|
|
def update_receiver_stats(session=None, date=None):
|
2018-01-11 07:35:07 +00:00
|
|
|
"""Add/update receiver stats."""
|
2017-12-12 20:46:21 +00:00
|
|
|
|
2018-01-21 20:06:27 +00:00
|
|
|
if session is None:
|
|
|
|
session = app.session
|
|
|
|
|
2017-12-12 20:46:21 +00:00
|
|
|
if not date:
|
|
|
|
logger.warn("A date is needed for calculating stats. Exiting")
|
|
|
|
return None
|
|
|
|
|
|
|
|
# First kill the stats for the selected date
|
2017-12-13 13:08:29 +00:00
|
|
|
deleted_counter = session.query(ReceiverStats) \
|
2017-12-12 20:46:21 +00:00
|
|
|
.filter(ReceiverStats.date == date) \
|
|
|
|
.delete()
|
|
|
|
|
2018-01-21 20:06:27 +00:00
|
|
|
# Calculate stats, firstseen, lastseen and last values != NULL
|
2017-12-13 13:08:29 +00:00
|
|
|
receiver_stats = session.query(
|
2018-01-21 20:06:27 +00:00
|
|
|
distinct(ReceiverBeacon.receiver_id).label('receiver_id'),
|
|
|
|
func.date(ReceiverBeacon.timestamp).label('date'),
|
|
|
|
func.first_value(ReceiverBeacon.timestamp)
|
|
|
|
.over(partition_by=ReceiverBeacon.receiver_id, order_by=case([(ReceiverBeacon.timestamp == null(), None)], else_=ReceiverBeacon.timestamp).asc().nullslast())
|
|
|
|
.label('firstseen'),
|
|
|
|
func.first_value(ReceiverBeacon.timestamp)
|
|
|
|
.over(partition_by=ReceiverBeacon.receiver_id, order_by=case([(ReceiverBeacon.timestamp == null(), None)], else_=ReceiverBeacon.timestamp).desc().nullslast())
|
|
|
|
.label('lastseen'),
|
|
|
|
func.first_value(ReceiverBeacon.location_wkt)
|
|
|
|
.over(partition_by=ReceiverBeacon.receiver_id, order_by=case([(ReceiverBeacon.location_wkt == null(), None)], else_=ReceiverBeacon.timestamp).desc().nullslast())
|
|
|
|
.label('location_wkt'),
|
|
|
|
func.first_value(ReceiverBeacon.altitude)
|
|
|
|
.over(partition_by=ReceiverBeacon.receiver_id, order_by=case([(ReceiverBeacon.altitude == null(), None)], else_=ReceiverBeacon.timestamp).desc().nullslast())
|
|
|
|
.label('altitude'),
|
|
|
|
func.first_value(ReceiverBeacon.version)
|
|
|
|
.over(partition_by=ReceiverBeacon.receiver_id, order_by=case([(ReceiverBeacon.version == null(), None)], else_=ReceiverBeacon.timestamp).desc().nullslast())
|
|
|
|
.label('version'),
|
|
|
|
func.first_value(ReceiverBeacon.platform)
|
|
|
|
.over(partition_by=ReceiverBeacon.receiver_id, order_by=case([(ReceiverBeacon.platform == null(), None)], else_=ReceiverBeacon.timestamp).desc().nullslast())
|
|
|
|
.label('platform')) \
|
2017-12-12 20:46:21 +00:00
|
|
|
.subquery()
|
|
|
|
|
|
|
|
# And insert them
|
|
|
|
ins = insert(ReceiverStats).from_select(
|
2018-01-21 20:06:27 +00:00
|
|
|
[ReceiverStats.receiver_id, ReceiverStats.date, ReceiverStats.firstseen, ReceiverStats.lastseen, ReceiverStats.location_wkt, ReceiverStats.altitude, ReceiverStats.version, ReceiverStats.platform],
|
2017-12-12 20:46:21 +00:00
|
|
|
receiver_stats)
|
2017-12-13 13:08:29 +00:00
|
|
|
res = session.execute(ins)
|
2017-12-12 20:46:21 +00:00
|
|
|
insert_counter = res.rowcount
|
2017-12-13 13:08:29 +00:00
|
|
|
session.commit()
|
2018-01-21 20:06:27 +00:00
|
|
|
logger.warn("ReceiverStats for {}: {} deleted, {} inserted".format(date, deleted_counter, insert_counter))
|
|
|
|
|
|
|
|
# Update AircraftBeacon distances
|
|
|
|
upd = update(AircraftBeacon) \
|
|
|
|
.where(and_(func.date(AircraftBeacon.timestamp) == ReceiverStats.date,
|
|
|
|
AircraftBeacon.receiver_id == ReceiverStats.receiver_id,
|
|
|
|
AircraftBeacon.distance == null())) \
|
|
|
|
.values({"distance": func.ST_Distance_Sphere(AircraftBeacon.location_wkt, ReceiverStats.location_wkt)})
|
|
|
|
|
|
|
|
result = session.execute(upd)
|
|
|
|
update_counter = result.rowcount
|
|
|
|
session.commit()
|
|
|
|
logger.warn("Updated {} AircraftBeacons".format(update_counter))
|
2017-12-12 20:46:21 +00:00
|
|
|
|
2018-01-21 20:06:27 +00:00
|
|
|
return "ReceiverStats for {}: {} deleted, {} inserted, AircraftBeacons: {} updated".format(date, deleted_counter, insert_counter, update_counter)
|