CoolFace
Apppublic

sakthivikram/geo-location

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
AnalyticsService.java233 linesDownload Raw Back to service
1package com.georeport.service;2 3import com.georeport.dto.AnalyticsResponse;4import com.georeport.entity.Issue;5import com.georeport.entity.IssueStatus;6import com.georeport.repository.IssueRepository;7import org.springframework.beans.factory.annotation.Autowired;8import org.springframework.stereotype.Service;9import org.springframework.transaction.annotation.Transactional;10 11import org.springframework.data.domain.PageRequest;12import org.springframework.data.domain.Sort;13import java.time.Duration;14import java.time.LocalDate;15import java.time.LocalDateTime;16import java.util.*;17import java.util.stream.Collectors;18 19/**20 * Service for generating analytics data for the admin dashboard.21 */22@Service23public class AnalyticsService {24 25        @Autowired26        private IssueRepository issueRepository;27 28        /**29         * Get comprehensive analytics data30         */31        @Transactional(readOnly = true)32        public AnalyticsResponse getAnalytics(LocalDateTime startDate, LocalDateTime endDate) {33                // If no date range provided, use last 30 days as default for detailed metrics34                LocalDateTime actualStart = (startDate != null) ? startDate : LocalDateTime.now().minusDays(30);35                LocalDateTime actualEnd = (endDate != null) ? endDate : LocalDateTime.now();36 37                // Fetch metrics using optimized repository queries instead of fetching ALL38                // issues39                List<Object[]> statusCounts = issueRepository.getIssueCountByStatusSince(actualStart);40                Map<String, Long> byStatus = new HashMap<>();41                for (Object[] row : statusCounts) {42                        byStatus.put(((IssueStatus) row[0]).name(), (Long) row[1]);43                }44 45                List<Issue> filteredIssues = issueRepository.findWithFilters(null, null, null, actualStart, actualEnd,46                                PageRequest.of(0, 1000, Sort.by("createdAt").descending())).getContent();47 48                return AnalyticsResponse.builder()49                                .byStatus(byStatus)50                                .byCategory(getCountByCategory(filteredIssues))51                                .byPriority(getCountByPriority(filteredIssues))52                                .byWard(getCountByWard(filteredIssues))53                                .issueTrends(getIssueTrends(filteredIssues))54                                .avgResolutionTimeByCategory(getAvgResolutionTimeByCategory(filteredIssues))55                                .hotspots(getHotspots(filteredIssues))56                                .overall(getOverallStatsOptimized(actualStart)) // Use optimized stats57                                .build();58        }59 60        /**61         * Get issue trends (issues per day for last 30 days)62         */63        @Transactional(readOnly = true)64        public Map<String, Long> getTrends(int days) {65                LocalDateTime startDate = LocalDateTime.now().minusDays(days);66                List<Issue> issues = issueRepository.findAll().stream()67                                .filter(i -> i.getCreatedAt() != null && i.getCreatedAt().isAfter(startDate))68                                .collect(Collectors.toList());69 70                return getIssueTrends(issues);71        }72 73        /**74         * Get category distribution75         */76        @Transactional(readOnly = true)77        public Map<String, Long> getCategoryDistribution() {78                return getCountByCategory(issueRepository.findAll());79        }80 81        /**82         * Get average resolution time by category83         */84        @Transactional(readOnly = true)85        public Map<String, Double> getResolutionTimes() {86                return getAvgResolutionTimeByCategory(issueRepository.findAll());87        }88 89        /**90         * Get hotspot data for heatmap91         */92        @Transactional(readOnly = true)93        public List<AnalyticsResponse.HotspotData> getHotspotData() {94                return getHotspots(issueRepository.findAll());95        }96 97        // Helper methods98 99        private Map<String, Long> getCountByStatus(List<Issue> issues) {100                return issues.stream()101                                .filter(i -> i.getStatus() != null)102                                .collect(Collectors.groupingBy(103                                                i -> i.getStatus().name(),104                                                Collectors.counting()));105        }106 107        private Map<String, Long> getCountByCategory(List<Issue> issues) {108                return issues.stream()109                                .filter(i -> i.getCategory() != null)110                                .collect(Collectors.groupingBy(111                                                i -> i.getCategory().getName(),112                                                Collectors.counting()));113        }114 115        private Map<String, Long> getCountByPriority(List<Issue> issues) {116                return issues.stream()117                                .filter(i -> i.getPriority() != null)118                                .collect(Collectors.groupingBy(119                                                i -> i.getPriority().name(),120                                                Collectors.counting()));121        }122 123        private Map<String, Long> getCountByWard(List<Issue> issues) {124                return issues.stream()125                                .filter(i -> i.getWard() != null && !i.getWard().trim().isEmpty())126                                .collect(Collectors.groupingBy(127                                                Issue::getWard,128                                                Collectors.counting()));129        }130 131        private Map<String, Long> getIssueTrends(List<Issue> issues) {132                Map<String, Long> trends = new LinkedHashMap<>();133 134                // Get last 30 days135                LocalDate today = LocalDate.now();136                for (int i = 29; i >= 0; i--) {137                        LocalDate date = today.minusDays(i);138                        trends.put(date.toString(), 0L);139                }140 141                // Count issues per day142                issues.stream()143                                .filter(i -> i.getCreatedAt() != null)144                                .forEach(issue -> {145                                        String dateKey = issue.getCreatedAt().toLocalDate().toString();146                                        if (trends.containsKey(dateKey)) {147                                                trends.put(dateKey, trends.get(dateKey) + 1);148                                        }149                                });150 151                return trends;152        }153 154        private Map<String, Double> getAvgResolutionTimeByCategory(List<Issue> issues) {155                Map<String, List<Double>> resolutionTimes = new HashMap<>();156 157                issues.stream()158                                .filter(i -> i.getStatus() == IssueStatus.RESOLVED &&159                                                i.getCreatedAt() != null &&160                                                i.getResolvedAt() != null &&161                                                i.getCategory() != null)162                                .forEach(issue -> {163                                        Duration duration = Duration.between(issue.getCreatedAt(),164                                                        issue.getResolvedAt());165                                        double hours = duration.toHours();166                                        String category = issue.getCategory().getName();167 168                                        resolutionTimes.computeIfAbsent(category, k -> new ArrayList<>()).add(hours);169                                });170 171                return resolutionTimes.entrySet().stream()172                                .collect(Collectors.toMap(173                                                Map.Entry::getKey,174                                                e -> e.getValue().stream().mapToDouble(Double::doubleValue).average()175                                                                .orElse(0.0)));176        }177 178        private List<AnalyticsResponse.HotspotData> getHotspots(List<Issue> issues) {179                // Group issues by approximate location (grid-based clustering)180                Map<String, List<Issue>> locationGroups = new HashMap<>();181                double gridSize = 0.01; // ~1km grid182 183                issues.stream()184                                .filter(i -> i.getLatitude() != null && i.getLongitude() != null)185                                .forEach(issue -> {186                                        double gridLat = Math.round(issue.getLatitude() / gridSize) * gridSize;187                                        double gridLng = Math.round(issue.getLongitude() / gridSize) * gridSize;188                                        String key = gridLat + "," + gridLng;189                                        locationGroups.computeIfAbsent(key, k -> new ArrayList<>()).add(issue);190                                });191 192                return locationGroups.entrySet().stream()193                                .map(entry -> {194                                        String[] coords = entry.getKey().split(",");195                                        return AnalyticsResponse.HotspotData.builder()196                                                        .latitude(Double.parseDouble(coords[0]))197                                                        .longitude(Double.parseDouble(coords[1]))198                                                        .count((long) entry.getValue().size())199                                                        .build();200                                })201                                .sorted((a, b) -> Long.compare(b.getCount(), a.getCount()))202                                .limit(100) // Top 100 hotspots203                                .collect(Collectors.toList());204        }205 206        private AnalyticsResponse.OverallStats getOverallStatsOptimized(LocalDateTime since) {207                long total = issueRepository.count();208 209                LocalDateTime monthStart = LocalDateTime.now().withDayOfMonth(1).withHour(0).withMinute(0);210                LocalDateTime weekStart = LocalDateTime.now().minusDays(7);211 212                long resolvedThisMonth = issueRepository.countByStatusAndResolvedAtBetween(IssueStatus.RESOLVED,213                                monthStart, LocalDateTime.now());214                long newThisWeek = issueRepository.countByCreatedAtBetween(weekStart, LocalDateTime.now());215 216                Double avgResolutionHours = issueRepository217                                .getAverageResolutionTimeSince(LocalDateTime.now().minusMonths(6));218 219                long resolved = issueRepository.countByStatus(IssueStatus.RESOLVED);220                double resolutionRate = total > 0 ? (resolved * 100.0 / total) : 0.0;221 222                return AnalyticsResponse.OverallStats.builder()223                                .totalIssues(total)224                                .resolvedThisMonth(resolvedThisMonth)225                                .newThisWeek(newThisWeek)226                                .avgResolutionTimeHours(avgResolutionHours != null227                                                ? Math.round(avgResolutionHours * 10.0) / 10.0228                                                : 0.0)229                                .resolutionRate(Math.round(resolutionRate * 10.0) / 10.0)230                                .build();231        }232}233