From 5baa800f9e07aaa4839a5eddd79461bd7a6c4266 Mon Sep 17 00:00:00 2001
From: Mattia Mancini <mancini@astron.nl>
Date: Tue, 23 Oct 2018 14:20:52 +0000
Subject: [PATCH] OSB-28: increase speed in quering the latestObservations

---
 .../monitoringdb/views/controllers.py         | 126 ++++++++----------
 1 file changed, 58 insertions(+), 68 deletions(-)

diff --git a/LCU/Maintenance/DBInterface/monitoringdb/views/controllers.py b/LCU/Maintenance/DBInterface/monitoringdb/views/controllers.py
index d80c7346aa1..06b580f380c 100644
--- a/LCU/Maintenance/DBInterface/monitoringdb/views/controllers.py
+++ b/LCU/Maintenance/DBInterface/monitoringdb/views/controllers.py
@@ -263,14 +263,13 @@ class ControllerLatestObservations(APIView):
     DEFAULT_STATION_GROUP = 'A'
     DEFAULT_ONLY_ERRORS = True
 
-    queryset = StationTest.objects.all()
     schema = ManualSchema(fields=[
         coreapi.Field(
             "station_group",
             required=False,
             location='query',
             schema=coreschema.Enum(['C', 'R', 'I', 'A'], description=
-            'Station group to select for choices are [C|R|I|ALL]',
+            'Station group to select for choices are [C|R|I|A]',
                                    )
         ),
         coreapi.Field(
@@ -299,19 +298,6 @@ class ControllerLatestObservations(APIView):
         except Exception as e:
             raise ValueError('cannot parse %s with format %s - %s' % (date, expected_format, e))
 
-    def compute_rtsm_observation_summary(self, rtsm_errors):
-        errors_summary = OrderedDict()
-
-        errors_summary_query = rtsm_errors.annotate(total=
-                                                    Window(expression=Count('rcu'),
-                                                           partition_by=[F(
-                                                               'error_type')])).values(
-            'error_type', 'total').distinct()
-
-        for error_summary in errors_summary_query:
-            errors_summary[error_summary['error_type']] = error_summary['total']
-        return errors_summary
-
     def validate_query_parameters(self, request):
         self.errors_only = request.query_params.get('errors_only', self.DEFAULT_ONLY_ERRORS)
         self.station_group = request.query_params.get('station_group', self.DEFAULT_STATION_GROUP)
@@ -328,62 +314,66 @@ class ControllerLatestObservations(APIView):
         except KeyError as e:
             return Response(status=status.HTTP_406_NOT_ACCEPTABLE,
                             data='Please specify both the start and the end date: %s' % (e,))
-
-        rtsm_observation_entities = RTSMObservation.objects.defer('errors').filter(
-            start_datetime__gte=self.from_date)
-        for group in self.station_group:
-            if group is not 'A':
-                rtsm_observation_entities = rtsm_observation_entities.filter(station__type=group)
-
-        # Since django preferes a ordered dict over a dict we make it happy... for now
-        response_payload = list()
-        for rtsm_observation_entity in rtsm_observation_entities.values('observation_id',
-                                                                        'start_datetime',
-                                                                        'end_datetime'). \
-                distinct().order_by('-start_datetime'):
-            observation_payload = OrderedDict()
-
-            observation_payload['observation_id'] = rtsm_observation_entity['observation_id']
-            observation_payload['start_datetime'] = rtsm_observation_entity['start_datetime']
-            observation_payload['end_datetime'] = rtsm_observation_entity['end_datetime']
-
-            rtsm_list = RTSMObservation.objects.defer('errors').filter(
-                start_datetime__gte=self.from_date,
-                observation_id=rtsm_observation_entity['observation_id'])
-            unique_modes = [item['errors_summary__mode'] for item in
-                            rtsm_list.values('errors_summary__mode').distinct()]
-
-            observation_payload['mode'] = unique_modes
-            observation_payload['total_component_errors'] = 0
-
-            station_involved_list = list()
-
-            for rtsm_entry_per_station in rtsm_list.order_by('station__name'):
-                station_summary = OrderedDict()
-                station_summary['station_name'] = rtsm_entry_per_station.station.name
-
-                station_summary['n_errors'] = \
-                    rtsm_entry_per_station.errors.values('rcu').distinct().count()
-                station_summary['component_error_summary'] = self.compute_rtsm_observation_summary(
-                    rtsm_entry_per_station.errors_summary)
-
-                station_involved_list.append(station_summary)
-
-                observation_payload['total_component_errors'] += station_summary['n_errors']
-
-            observation_payload['station_involved'] = station_involved_list
-
-            response_payload.append(observation_payload)
-        if self.errors_only and self.errors_only != 'false':
-
-            response_payload = filter(
-                lambda station_entry:
-                len(station_entry['total_component_errors']) > 0,
-                response_payload)
+        filtered_entities = RTSMObservation.objects\
+            .filter(start_datetime__gte=self.from_date)
+        if self.station_group != 'A':
+            filtered_entities = filtered_entities\
+                .filter(station__type=self.station_group)
+        if self.errors_only:
+            filtered_entities = filtered_entities.exclude(errors_summary__isnull=True)
+
+        errors_summary = filtered_entities\
+            .values('observation_id',
+                    'station__name',
+                    'start_datetime',
+                    'end_datetime',
+                    'errors_summary__error_type',
+                    'errors_summary__mode')\
+            .annotate(total=Count('errors_summary__error_type'))\
+            .order_by('observation_id', 'station__name')
+        response = dict()
+
+        for error_summary in errors_summary:
+            observation_id = error_summary['observation_id']
+            station_name = error_summary['station__name']
+            start_datetime = error_summary['start_datetime']
+            end_datetime = error_summary['end_datetime']
+            mode = error_summary['errors_summary__mode']
+            error_type = error_summary['errors_summary__error_type']
+            total = error_summary['total']
+
+            if observation_id not in response:
+                response[observation_id] = OrderedDict()
+                response[observation_id]['observation_id'] = observation_id
+                response[observation_id]['start_datetime'] = start_datetime
+                response[observation_id]['end_datetime'] = end_datetime
+
+                response[observation_id]['total_component_errors'] = 0
+                response[observation_id]['mode'] = list()
+                response[observation_id]['station_involved'] = dict()
+
+            if total == 0:
+                continue
+
+            response[observation_id]['total_component_errors'] += total
+            station_involved_summary = response[observation_id]['station_involved']
+            response[observation_id]['mode'] += [mode]\
+                if mode not in response[observation_id]['mode'] else []
+            if station_name not in station_involved_summary:
+                station_involved_summary[station_name] = OrderedDict()
+                station_involved_summary[station_name]['station_name'] = station_name
+                station_involved_summary[station_name]['n_errors'] = 0
+                station_involved_summary[station_name]['component_error_summary'] = OrderedDict()
+
+            station_involved_summary[station_name]['n_errors'] += total
+            station_involved_summary[station_name]['component_error_summary'][error_type] = total
+
+        response_payload = sorted(response.values(),
+                                  key= lambda item: item['start_datetime'],
+                                  reverse=True)
 
         return Response(status=status.HTTP_200_OK, data=response_payload)
 
-
 class ControllerStationTestStatistics(APIView):
     """
 
-- 
GitLab