From 0d59b6e7f48770920be7d7bc413adf530eb5e106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Fri, 28 Dec 2018 19:53:04 +0100 Subject: [PATCH] convertstats --- .../management/commands/convertstats.py | 19 ++ src/c3nav/mapdata/utils/cache/stats.py | 175 ++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 src/c3nav/mapdata/management/commands/convertstats.py diff --git a/src/c3nav/mapdata/management/commands/convertstats.py b/src/c3nav/mapdata/management/commands/convertstats.py new file mode 100644 index 00000000..b2aaecbb --- /dev/null +++ b/src/c3nav/mapdata/management/commands/convertstats.py @@ -0,0 +1,19 @@ +import argparse +import json + +from django.core.management.base import BaseCommand +from django.utils.translation import ugettext_lazy as _ + +from c3nav.mapdata.utils.cache.stats import convert_stats + + +class Command(BaseCommand): + help = 'convert stats file' + + def add_arguments(self, parser): + parser.add_argument('statsfile', type=argparse.FileType('r'), help=_('stats file to convert')) + + def handle(self, *args, **options): + data = json.load(options['statsfile']) + result = convert_stats(data) + print(json.dumps(result, indent=4)) diff --git a/src/c3nav/mapdata/utils/cache/stats.py b/src/c3nav/mapdata/utils/cache/stats.py index 8ac5daf3..9492f30d 100644 --- a/src/c3nav/mapdata/utils/cache/stats.py +++ b/src/c3nav/mapdata/utils/cache/stats.py @@ -1,5 +1,15 @@ +from operator import itemgetter + +from django.contrib.auth import get_user_model from django.core.cache import cache from django.utils import timezone +from kombu.utils import cached_property + +from c3nav.control.models import UserPermissions +from c3nav.mapdata.models import Level, LocationGroup, LocationSlug, Space +from c3nav.mapdata.models.geometry.space import POI, Area, WifiMeasurement +from c3nav.mapdata.models.locations import LocationRedirect +from c3nav.mapdata.utils.locations import CustomLocation, get_location_by_id_for_request def increment_cache_key(cache_key): @@ -25,3 +35,168 @@ def stats_snapshot(reset=True): 'end_date': str(now), 'data': results } + + +def _filter_stats(tag, stats, startswith=False): + if startswith: + return (([name[0][len(tag):]]+name[1:], value) for name, value in stats if name[0].startswith(tag)) + return ((name[1:], value) for name, value in stats if name[0] == tag) + + +class FakeRequest(): + @cached_property + def user(self): + return get_user_model().objects.filter(is_superuser=True).first() + + @cached_property + def user_permissions(self): + return UserPermissions.get_for_user(self.user) + + +fake_request = FakeRequest() + + +def convert_stats(stats): + stats = [(name.split('__')[1:], value) for name, value in stats['data'].items()] + result = {} + result['locate'] = convert_locate(_filter_stats('locate', stats)) + result['location_retrieve'] = convert_location(_filter_stats('location_retrieve', stats)) + result['location_geometry'] = convert_location(_filter_stats('location_geometry', stats)) + result['route_origin'] = convert_location( + (['pk']+name, value) for name, value in _filter_stats('route_origin_', stats, startswith=True) + ) + result['route_destination'] = convert_location( + (['pk'] + name, value) for name, value in _filter_stats('route_destination_', stats, startswith=True) + ) + return result + + +def _sort_count(map, key): + map[key] = dict(sorted(map[key].items(), key=itemgetter(1), reverse=True)) + + +def convert_locate(data): + result = { + 'total': 0, + 'by_measurement_id': {}, + 'by_space': {}, + 'by_level': {}, + } + measurement_lookup = {} + for measurement in WifiMeasurement.objects.all().select_related('space', 'space__level'): + pos = CustomLocation(measurement.space.level, measurement.geometry.x, measurement.geometry.y, + permissions=set()).pk + space_slug = measurement.space.get_slug() + level_label = measurement.space.level.short_label + measurement_lookup[pos] = (measurement.pk, space_slug, level_label) + result['by_measurement_id'][measurement.pk] = 0 + result['by_space'][space_slug] = 0 + result['by_level'][level_label] = 0 + + for name, value in data: + result['total'] += value + measurement = measurement_lookup.get(name[0], None) + if measurement: + result['by_measurement_id'][measurement[0]] += value + result['by_space'][measurement[1]] += value + result['by_level'][measurement[2]] += value + + _sort_count(result, 'by_measurement_id') + _sort_count(result, 'by_space') + _sort_count(result, 'by_level') + return result + + +def convert_location(data): + result = { + 'total': 0, + 'invalid': 0, + 'locations': { + 'total': 0, + 'by_type': {}, + 'by_space': {}, + 'by_level': {}, + 'by_group': {}, + }, + 'coordinates': { + 'total': 0, + 'by_level': {}, + 'by_space': {}, + 'by_area': {}, + 'by_poi': {}, + } + } + + # fill up lists with zeros + location_slugs = {} + level_labels = {} + for location in LocationSlug.objects.all(): + location = location.get_child() + if isinstance(location, LocationRedirect): + continue + result['locations']['by_type'].setdefault(location.__class__.__name__.lower(), {})[location.get_slug()] = 0 + location_slugs[location.pk] = location.get_slug() + if isinstance(location, Level): + result['locations']['by_level'][location.short_label] = 0 + result['coordinates']['by_level'][location.short_label] = 0 + level_labels[location.pk] = location.short_label + if isinstance(location, Space): + result['locations']['by_space'][location.get_slug()] = 0 + result['coordinates']['by_space'][location.get_slug()] = 0 + if isinstance(location, Area): + if getattr(location, 'can_search', False) or getattr(location, 'can_describe', False): + result['coordinates']['by_area'][location.get_slug()] = 0 + if isinstance(location, POI): + if getattr(location, 'can_search', False) or getattr(location, 'can_describe', False): + result['coordinates']['by_poi'][location.get_slug()] = 0 + if isinstance(location, LocationGroup): + result['locations']['by_group'][location.get_slug()] = 0 + + for name, value in data: + if name[0] != 'pk' or name[0] == 'c:anywhere': + continue + location = get_location_by_id_for_request(name[1], fake_request) + result['total'] += value + if location is None: + result['invalid'] += value + continue + if isinstance(location, CustomLocation): + location.x += 1.5 + location.y += 1.5 + result['coordinates']['total'] += value + result['coordinates']['by_level'][location_slugs[location.level.pk]] += value + if location.space is None: + continue + result['coordinates']['by_space'][location_slugs[location.space.pk]] += value + for area in location.areas: + result['coordinates']['by_area'][location_slugs[area.pk]] += value + if location.near_area: + result['coordinates']['by_area'][location_slugs[location.near_area.pk]] += value + if location.near_poi: + result['coordinates']['by_poi'][location_slugs[location.near_poi.pk]] += value + else: + result['locations']['total'] += value + location = getattr(location, 'target', location) + result['locations']['by_type'].setdefault(location.__class__.__name__.lower(), + {})[location.get_slug()] += value + if hasattr(location, 'space_id'): + result['locations']['by_space'][location_slugs[location.space_id]] += value + if hasattr(location, 'level_id'): + result['locations']['by_level'][level_labels[location.level_id]] += value + if hasattr(location, 'groups'): + for group in location.groups.all(): + result['locations']['by_group'][location_slugs[group.pk]] += value + + _sort_count(result['locations']['by_type'], 'level') + _sort_count(result['locations']['by_type'], 'space') + _sort_count(result['locations']['by_type'], 'area') + _sort_count(result['locations']['by_type'], 'poi') + _sort_count(result['locations']['by_type'], 'locationgroup') + _sort_count(result['locations'], 'by_space') + _sort_count(result['locations'], 'by_level') + _sort_count(result['locations'], 'by_group') + _sort_count(result['coordinates'], 'by_level') + _sort_count(result['coordinates'], 'by_space') + _sort_count(result['coordinates'], 'by_area') + _sort_count(result['coordinates'], 'by_poi') + return result