Use better data types

pull/68/head
Konstantin Gründger 2018-01-21 21:06:27 +01:00
rodzic 36239be842
commit 8159646fc2
13 zmienionych plików z 126 dodań i 58 usunięć

Wyświetl plik

@ -3,7 +3,7 @@ from datetime import datetime
from celery.utils.log import get_task_logger from celery.utils.log import get_task_logger
from sqlalchemy import insert, distinct from sqlalchemy import insert, distinct
from sqlalchemy.sql import null, and_, func, or_ from sqlalchemy.sql import null, and_, func, or_, update
from sqlalchemy.sql.expression import literal_column, case from sqlalchemy.sql.expression import literal_column, case
from ogn.model import AircraftBeacon, DeviceStats, ReceiverStats from ogn.model import AircraftBeacon, DeviceStats, ReceiverStats
@ -35,7 +35,7 @@ def update_device_stats(session=None, date=None):
func.dense_rank() func.dense_rank()
.over(partition_by=AircraftBeacon.device_id, order_by=AircraftBeacon.receiver_id) .over(partition_by=AircraftBeacon.device_id, order_by=AircraftBeacon.receiver_id)
.label('dr')) \ .label('dr')) \
.filter(and_(AircraftBeacon.device_id != null(), func.date(AircraftBeacon.timestamp) == date)) \ .filter(and_(func.date(AircraftBeacon.timestamp) == date, AircraftBeacon.device_id != null())) \
.filter(or_(AircraftBeacon.error_count == 0, AircraftBeacon.error_count == null())) \ .filter(or_(AircraftBeacon.error_count == 0, AircraftBeacon.error_count == null())) \
.subquery() .subquery()
@ -89,9 +89,12 @@ def update_device_stats(session=None, date=None):
@app.task @app.task
def update_receiver_stats(date=None): def update_receiver_stats(session=None, date=None):
"""Add/update receiver stats.""" """Add/update receiver stats."""
if session is None:
session = app.session
if not date: if not date:
logger.warn("A date is needed for calculating stats. Exiting") logger.warn("A date is needed for calculating stats. Exiting")
return None return None
@ -101,25 +104,49 @@ def update_receiver_stats(date=None):
.filter(ReceiverStats.date == date) \ .filter(ReceiverStats.date == date) \
.delete() .delete()
# Calculate stats for the selected date # Calculate stats, firstseen, lastseen and last values != NULL
receiver_stats = session.query( receiver_stats = session.query(
AircraftBeacon.receiver_id, distinct(ReceiverBeacon.receiver_id).label('receiver_id'),
literal_column("'{}'".format(date)).label('date'), func.date(ReceiverBeacon.timestamp).label('date'),
func.count(AircraftBeacon.id).label('aircraft_beacon_count'), func.first_value(ReceiverBeacon.timestamp)
func.count(distinct(AircraftBeacon.device_id)).label('aircraft_count'), .over(partition_by=ReceiverBeacon.receiver_id, order_by=case([(ReceiverBeacon.timestamp == null(), None)], else_=ReceiverBeacon.timestamp).asc().nullslast())
func.max(AircraftBeacon.distance).label('max_distance')) \ .label('firstseen'),
.filter(AircraftBeacon.receiver_id != null()) \ func.first_value(ReceiverBeacon.timestamp)
.filter(func.date(AircraftBeacon.timestamp) == date) \ .over(partition_by=ReceiverBeacon.receiver_id, order_by=case([(ReceiverBeacon.timestamp == null(), None)], else_=ReceiverBeacon.timestamp).desc().nullslast())
.group_by(AircraftBeacon.receiver_id) \ .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')) \
.subquery() .subquery()
# And insert them # And insert them
ins = insert(ReceiverStats).from_select( ins = insert(ReceiverStats).from_select(
[ReceiverStats.receiver_id, ReceiverStats.date, ReceiverStats.aircraft_beacon_count, ReceiverStats.aircraft_count, ReceiverStats.max_distance], [ReceiverStats.receiver_id, ReceiverStats.date, ReceiverStats.firstseen, ReceiverStats.lastseen, ReceiverStats.location_wkt, ReceiverStats.altitude, ReceiverStats.version, ReceiverStats.platform],
receiver_stats) receiver_stats)
res = session.execute(ins) res = session.execute(ins)
insert_counter = res.rowcount insert_counter = res.rowcount
session.commit() session.commit()
logger.debug("ReceiverStats for {}: {} deleted, {} inserted".format(date, deleted_counter, insert_counter)) logger.warn("ReceiverStats for {}: {} deleted, {} inserted".format(date, deleted_counter, insert_counter))
return "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))
return "ReceiverStats for {}: {} deleted, {} inserted, AircraftBeacons: {} updated".format(date, deleted_counter, insert_counter, update_counter)

Wyświetl plik

@ -1,8 +1,8 @@
from datetime import timedelta from datetime import datetime, timedelta
from celery.utils.log import get_task_logger from celery.utils.log import get_task_logger
from sqlalchemy import and_, or_, insert, between, exists from sqlalchemy import and_, or_, insert, update, between, exists
from sqlalchemy.sql import func, null from sqlalchemy.sql import func, null
from sqlalchemy.sql.expression import case from sqlalchemy.sql.expression import case
@ -13,7 +13,7 @@ logger = get_task_logger(__name__)
@app.task @app.task
def update_takeoff_landings(session=None): def update_takeoff_landings(session=None, date=None):
"""Compute takeoffs and landings.""" """Compute takeoffs and landings."""
logger.info("Compute takeoffs and landings.") logger.info("Compute takeoffs and landings.")
@ -43,10 +43,20 @@ def update_takeoff_landings(session=None):
AircraftBeacon.receiver_id) AircraftBeacon.receiver_id)
# make a query with current, previous and next position # make a query with current, previous and next position
beacon_selection = session.query(AircraftBeacon.id) \ if date is None:
.order_by(AircraftBeacon.timestamp) \ beacon_selection = session.query(AircraftBeacon.id) \
.limit(1000000) \ .filter(AircraftBeacon.status == 0) \
.subquery() .order_by(AircraftBeacon.timestamp) \
.subquery()
else:
my_day = datetime.strptime(date, '%Y-%m-%d')
beacon_selection = session.query(AircraftBeacon.id) \
.filter(and_(AircraftBeacon.status == 0,
AircraftBeacon.timestamp >= my_day - timedelta(minutes=5),
AircraftBeacon.timestamp < my_day + timedelta(days=1, minutes=5))) \
.order_by(AircraftBeacon.timestamp) \
.limit(100000) \
.subquery()
sq = session.query( sq = session.query(
AircraftBeacon.id, AircraftBeacon.id,
@ -78,6 +88,9 @@ def update_takeoff_landings(session=None):
.filter(sq.c.device_id_prev == sq.c.device_id == sq.c.device_id_next) \ .filter(sq.c.device_id_prev == sq.c.device_id == sq.c.device_id_next) \
.subquery() .subquery()
logger.warn(sq2)
return
# find possible takeoffs and landings # find possible takeoffs and landings
sq3 = session.query( sq3 = session.query(
sq2.c.id, sq2.c.id,
@ -129,9 +142,17 @@ def update_takeoff_landings(session=None):
TakeoffLanding.airport_id), TakeoffLanding.airport_id),
takeoff_landing_query) takeoff_landing_query)
result = session.execute(ins) result = session.execute(ins)
counter = result.rowcount insert_counter = result.rowcount
logger.warn("Inserted {} TakeoffLandings".format(insert_counter))
# Set calculated beacons as 'used'
upd = update(AircraftBeacon) \
.where(AircraftBeacon.id == sq2.c.id) \
.values({"status": 1})
result = session.execute(upd)
update_counter = result.rowcount
session.commit() session.commit()
logger.debug("Inserted {} TakeoffLandings".format(counter)) logger.warn("Updated {} AircraftBeacons".format(update_counter))
return "Inserted {} TakeoffLandings".format(counter) return "Inserted {} TakeoffLandings, updated {} AircraftBeacons".format(insert_counter, update_counter)

Wyświetl plik

@ -112,9 +112,11 @@ def convert(sourcefile, path=''):
def drop_indices(): def drop_indices():
"""Drop indices of AircraftBeacon.""" """Drop indices of AircraftBeacon."""
session.execute(""" session.execute("""
DROP INDEX IF EXISTS idx_aircraft_beacons_location; DROP INDEX IF EXISTS ix_aircraft_beacons_receiver_id_receiver_name;
DROP INDEX IF EXISTS ix_aircraft_beacons_receiver_id; DROP INDEX IF EXISTS ix_aircraft_beacons_device_id_address;
DROP INDEX IF EXISTS ix_aircraft_beacons_device_id; DROP INDEX IF EXISTS ix_aircraft_beacons_device_id_timestamp;
DROP INDEX IF EXISTS ix_aircraft_beacons_location;
DROP INDEX IF EXISTS ix_aircraft_beacons_location_mgrs;
DROP INDEX IF EXISTS ix_aircraft_beacons_timestamp; DROP INDEX IF EXISTS ix_aircraft_beacons_timestamp;
""") """)
print("Dropped indices of AircraftBeacon") print("Dropped indices of AircraftBeacon")
@ -130,10 +132,12 @@ def drop_indices():
def create_indices(): def create_indices():
"""Create indices for AircraftBeacon.""" """Create indices for AircraftBeacon."""
session.execute(""" session.execute("""
CREATE INDEX idx_aircraft_beacon_location ON aircraft_beacons USING GIST(location); CREATE INDEX ix_aircraft_beacons_receiver_id_receiver_name ON aircraft_beacons USING BTREE(receiver_id, receiver_name);
CREATE INDEX ix_aircraft_beacon_receiver_id ON aircraft_beacons USING BTREE(receiver_id); CREATE INDEX ix_aircraft_beacons_device_id_address ON aircraft_beacons USING BTREE(device_id, address);
CREATE INDEX ix_aircraft_beacon_device_id ON aircraft_beacons USING BTREE(device_id); CREATE INDEX ix_aircraft_beacons_device_id_timestamp ON aircraft_beacons USING BTREE(device_id, timestamp);
CREATE INDEX ix_aircraft_beacon_timestamp ON aircraft_beacons USING BTREE(timestamp); CREATE INDEX ix_aircraft_beacons_location ON aircraft_beacons USING GIST(location);
CREATE INDEX ix_aircraft_beacons_date_receiver_id_distance ON aircraft_beacons USING btree((timestamp::date), receiver_id, distance)
""") """)
print("Created indices for AircraftBeacon") print("Created indices for AircraftBeacon")

Wyświetl plik

@ -1,6 +1,6 @@
from sqlalchemy import Column, String, Integer, Float, Boolean, SmallInteger, ForeignKey, Index from sqlalchemy import Column, String, Integer, Float, Boolean, SmallInteger, ForeignKey, Index
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from .beacon import Beacon from .beacon import Beacon
@ -24,6 +24,7 @@ class AircraftBeacon(Beacon):
real_address = Column(String(6)) real_address = Column(String(6))
signal_power = Column(Float(precision=2)) signal_power = Column(Float(precision=2))
# Not so very important data
proximity = None proximity = None
gps_satellites = None gps_satellites = None
gps_quality = None gps_quality = None
@ -51,6 +52,9 @@ class AircraftBeacon(Beacon):
# Multi-column indices # Multi-column indices
Index('ix_aircraft_beacons_receiver_id_receiver_name', 'receiver_id', 'receiver_name') Index('ix_aircraft_beacons_receiver_id_receiver_name', 'receiver_id', 'receiver_name')
Index('ix_aircraft_beacons_device_id_address', 'device_id', 'address') Index('ix_aircraft_beacons_device_id_address', 'device_id', 'address')
Index('ix_aircraft_beacons_device_id_timestamp', 'device_id', 'timestamp')
#Index('ix_aircraft_beacons_date_receiver_id_distance', func.date(self.timestamp), 'receiver_id', 'distance')
def __repr__(self): def __repr__(self):
return "<AircraftBeacon %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s>" % ( return "<AircraftBeacon %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s>" % (

Wyświetl plik

@ -11,16 +11,16 @@ class Airport(Base):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
location_wkt = Column('location', Geometry('POINT', srid=4326)) location_wkt = Column('location', Geometry('POINT', srid=4326))
altitude = Column(Integer) altitude = Column(Float(precision=2))
name = Column(String, index=True) name = Column(String, index=True)
code = Column(String(6)) code = Column(String(6))
country_code = Column(String(2)) country_code = Column(String(2))
style = Column(SmallInteger) style = Column(SmallInteger)
description = Column(String) description = Column(String)
runway_direction = Column(Integer) runway_direction = Column(SmallInteger)
runway_length = Column(Integer) runway_length = Column(SmallInteger)
frequency = Column(Float) frequency = Column(Float(precision=2))
def __repr__(self): def __repr__(self):
return "<Airport %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,% s>" % ( return "<Airport %s: %s,%s,%s,%s,%s,%s,%s,%s,%s,% s>" % (

Wyświetl plik

@ -1,6 +1,6 @@
from geoalchemy2.shape import to_shape from geoalchemy2.shape import to_shape
from geoalchemy2.types import Geometry from geoalchemy2.types import Geometry
from sqlalchemy import Column, String, Integer, Float, DateTime from sqlalchemy import Column, String, Integer, SmallInteger, Float, DateTime
from sqlalchemy.ext.declarative import AbstractConcreteBase from sqlalchemy.ext.declarative import AbstractConcreteBase
from .base import Base from .base import Base
@ -20,7 +20,7 @@ class Beacon(AbstractConcreteBase, Base):
timestamp = Column(DateTime, index=True) timestamp = Column(DateTime, index=True)
symboltable = None symboltable = None
symbolcode = None symbolcode = None
track = Column(Integer) track = Column(SmallInteger)
ground_speed = Column(Float(precision=2)) ground_speed = Column(Float(precision=2))
comment = None comment = None

Wyświetl plik

@ -14,7 +14,7 @@ class Device(Base):
lastseen = Column(DateTime, index=True) lastseen = Column(DateTime, index=True)
aircraft_type = Column(SmallInteger, index=True) aircraft_type = Column(SmallInteger, index=True)
stealth = Column(Boolean) stealth = Column(Boolean)
software_version = Column(Float) software_version = Column(Float(precision=2))
hardware_version = Column(SmallInteger) hardware_version = Column(SmallInteger)
real_address = Column(String(6)) real_address = Column(String(6))

Wyświetl plik

@ -10,17 +10,21 @@ class DeviceStats(Base):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
date = Column(Date) date = Column(Date)
max_altitude = Column(Float)
receiver_count = Column(Integer) # Statistic data
max_altitude = Column(Float(precision=2))
receiver_count = Column(SmallInteger)
aircraft_beacon_count = Column(Integer) aircraft_beacon_count = Column(Integer)
firstseen = Column(DateTime) firstseen = Column(DateTime)
lastseen = Column(DateTime) lastseen = Column(DateTime)
aircraft_type = Column(SmallInteger) aircraft_type = Column(SmallInteger)
stealth = Column(Boolean) stealth = Column(Boolean)
software_version = Column(Float) software_version = Column(Float(precision=2))
hardware_version = Column(SmallInteger) hardware_version = Column(SmallInteger)
real_address = Column(String(6)) real_address = Column(String(6))
ambiguous = Column(Boolean)
# Relations # Relations
device_id = Column(Integer, ForeignKey('devices.id', ondelete='SET NULL'), index=True) device_id = Column(Integer, ForeignKey('devices.id', ondelete='SET NULL'), index=True)
device = relationship('Device', foreign_keys=[device_id], backref='stats') device = relationship('Device', foreign_keys=[device_id], backref='stats')

Wyświetl plik

@ -1,4 +1,4 @@
from sqlalchemy import Integer, DateTime, Column, ForeignKey, case, null from sqlalchemy import Integer, SmallInteger, Float, DateTime, Column, ForeignKey, case, null
from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
@ -12,10 +12,10 @@ class Logbook(Base):
reftime = Column(DateTime, index=True) reftime = Column(DateTime, index=True)
takeoff_timestamp = Column(DateTime) takeoff_timestamp = Column(DateTime)
takeoff_track = Column(Integer) takeoff_track = Column(SmallInteger)
landing_timestamp = Column(DateTime) landing_timestamp = Column(DateTime)
landing_track = Column(Integer) landing_track = Column(SmallInteger)
max_altitude = Column(Integer) max_altitude = Column(Float(precision=2))
# Relations # Relations
takeoff_airport_id = Column(Integer, ForeignKey('airports.id', ondelete='CASCADE'), index=True) takeoff_airport_id = Column(Integer, ForeignKey('airports.id', ondelete='CASCADE'), index=True)

Wyświetl plik

@ -1,6 +1,6 @@
from geoalchemy2.shape import to_shape from geoalchemy2.shape import to_shape
from geoalchemy2.types import Geometry from geoalchemy2.types import Geometry
from sqlalchemy import Column, String, Integer, DateTime from sqlalchemy import Column, Float, String, Integer, DateTime
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from .base import Base from .base import Base
@ -13,7 +13,7 @@ class Receiver(Base):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
location_wkt = Column('location', Geometry('POINT', srid=4326)) location_wkt = Column('location', Geometry('POINT', srid=4326))
altitude = Column(Integer) altitude = Column(Float(precision=2))
name = Column(String(9)) name = Column(String(9))
firstseen = Column(DateTime, index=True) firstseen = Column(DateTime, index=True)

Wyświetl plik

@ -1,4 +1,4 @@
from sqlalchemy import Column, String, Integer, Float, Date, ForeignKey, Index from sqlalchemy import Column, String, Integer, SmallInteger, Float, Date, ForeignKey, Index
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
@ -13,11 +13,11 @@ class ReceiverCoverage(Base):
date = Column(Date, primary_key=True) date = Column(Date, primary_key=True)
max_signal_quality = Column(Float) max_signal_quality = Column(Float)
max_altitude = Column(Integer) max_altitude = Column(Float(precision=2))
min_altitude = Column(Integer) min_altitude = Column(Float(precision=2))
aircraft_beacon_count = Column(Integer) aircraft_beacon_count = Column(Integer)
device_count = Column(Integer) device_count = Column(SmallInteger)
# Relations # Relations
receiver = relationship('Receiver', foreign_keys=[receiver_id], backref='receiver_coverages') receiver = relationship('Receiver', foreign_keys=[receiver_id], backref='receiver_coverages')

Wyświetl plik

@ -1,5 +1,6 @@
from sqlalchemy import Column, Integer, Date, Float, ForeignKey from sqlalchemy import Column, Integer, SmallInteger, Date, Float, ForeignKey, DateTime, String
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from geoalchemy2.types import Geometry
from .base import Base from .base import Base
@ -10,10 +11,17 @@ class ReceiverStats(Base):
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
date = Column(Date) date = Column(Date)
# Statistic data
aircraft_beacon_count = Column(Integer) aircraft_beacon_count = Column(Integer)
receiver_beacon_count = Column(Integer) aircraft_count = Column(SmallInteger)
aircraft_count = Column(Integer)
max_distance = Column(Float) max_distance = Column(Float)
firstseen = Column(DateTime, index=True)
lastseen = Column(DateTime, index=True)
location_wkt = Column('location', Geometry('POINT', srid=4326))
altitude = Column(Float(precision=2))
version = Column(String)
platform = Column(String)
# Relations # Relations
receiver_id = Column(Integer, ForeignKey('receivers.id', ondelete='SET NULL'), index=True) receiver_id = Column(Integer, ForeignKey('receivers.id', ondelete='SET NULL'), index=True)

Wyświetl plik

@ -1,4 +1,4 @@
from sqlalchemy import Boolean, Column, Integer, DateTime, ForeignKey from sqlalchemy import Boolean, Column, Integer, SmallInteger, DateTime, ForeignKey
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from .base import Base from .base import Base
@ -12,7 +12,7 @@ class TakeoffLanding(Base):
timestamp = Column(DateTime, primary_key=True) timestamp = Column(DateTime, primary_key=True)
is_takeoff = Column(Boolean) is_takeoff = Column(Boolean)
track = Column(Integer) track = Column(SmallInteger)
# Relations # Relations
airport = relationship('Airport', foreign_keys=[airport_id], backref='takeoff_landings') airport = relationship('Airport', foreign_keys=[airport_id], backref='takeoff_landings')