Aggregation
This commit is contained in:
parent
c998d79c16
commit
3782c10693
23
src/main/java/de/ph87/data/series/AggregationWrapperDto.java
Normal file
23
src/main/java/de/ph87/data/series/AggregationWrapperDto.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package de.ph87.data.series;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class AggregationWrapperDto {
|
||||||
|
|
||||||
|
public final Alignment alignment;
|
||||||
|
|
||||||
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
|
public final List<IAggregationDto> aggregations;
|
||||||
|
|
||||||
|
public AggregationWrapperDto(final Alignment alignment, final ZonedDateTime date, final List<IAggregationDto> aggregations) {
|
||||||
|
this.alignment = alignment;
|
||||||
|
this.date = date;
|
||||||
|
this.aggregations = aggregations;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -19,8 +19,13 @@ public class Aligned {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public Aligned minus(final long offset) {
|
public Aligned plus(final long amount) {
|
||||||
return new Aligned(alignment, alignment.plus.apply(date, -offset));
|
return new Aligned(alignment, alignment.plus(date, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Aligned minus(final long amount) {
|
||||||
|
return plus(-amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,27 +7,27 @@ import java.time.temporal.*;
|
|||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
|
|
||||||
public enum Alignment {
|
public enum Alignment {
|
||||||
FIVE(Duration.ofMinutes(5), t -> t.truncatedTo(ChronoUnit.MINUTES).minusMinutes(t.getMinute() % 5), (t, a) -> t.plusMinutes(5 * a)),
|
FIVE(t -> t.truncatedTo(ChronoUnit.MINUTES).minusMinutes(t.getMinute() % 5), Duration.ofMinutes(5), Duration.ofMinutes(5)),
|
||||||
HOUR(Duration.ofHours(1), t -> t.truncatedTo(ChronoUnit.HOURS), ZonedDateTime::plusHours),
|
HOUR(t -> t.truncatedTo(ChronoUnit.HOURS), Duration.ofHours(1), Duration.ofHours(1)),
|
||||||
DAY(Duration.ofDays(1), t -> t.truncatedTo(ChronoUnit.DAYS), ZonedDateTime::plusDays),
|
DAY(t -> t.truncatedTo(ChronoUnit.DAYS), Duration.ofDays(1), Duration.ofDays(1)),
|
||||||
WEEK(Duration.ofDays(7), t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfWeek().getValue() - 1), ZonedDateTime::plusWeeks),
|
WEEK(t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfWeek().getValue() - 1), Period.ofWeeks(1), Duration.ofDays(7)),
|
||||||
MONTH(Duration.ofDays(31), t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfMonth() - 1), ZonedDateTime::plusMonths),
|
MONTH(t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfMonth() - 1), Period.ofMonths(1), Duration.ofDays(31)),
|
||||||
YEAR(Duration.ofDays(366), t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfYear() - 1), ZonedDateTime::plusYears),
|
YEAR(t -> t.truncatedTo(ChronoUnit.DAYS).minusDays(t.getDayOfYear() - 1), Period.ofYears(1), Duration.ofDays(366)),
|
||||||
;
|
;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public final Duration maxDuration;
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final Function<ZonedDateTime, ZonedDateTime> align;
|
public final Function<ZonedDateTime, ZonedDateTime> align;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final BiFunction<ZonedDateTime, Long, ZonedDateTime> plus;
|
public final TemporalAmount amount;
|
||||||
|
|
||||||
Alignment(@NonNull final Duration maxDuration, @NonNull final Function<@NonNull ZonedDateTime, @NonNull ZonedDateTime> align, @NonNull final BiFunction<@NonNull ZonedDateTime, @NonNull Long, @NonNull ZonedDateTime> plus) {
|
@NonNull
|
||||||
|
public final Duration maxDuration;
|
||||||
|
|
||||||
|
Alignment(@NonNull final Function<@NonNull ZonedDateTime, @NonNull ZonedDateTime> align, @NonNull final TemporalAmount amount, @NonNull final Duration maxDuration) {
|
||||||
this.maxDuration = maxDuration;
|
this.maxDuration = maxDuration;
|
||||||
this.align = align;
|
this.align = align;
|
||||||
this.plus = plus;
|
this.amount = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -35,4 +35,25 @@ public enum Alignment {
|
|||||||
return new Aligned(this, date);
|
return new Aligned(this, date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public ZonedDateTime plus(@NonNull final ZonedDateTime date, final long amount) {
|
||||||
|
return date.plus(multiplyAmount(amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public ZonedDateTime minus(@NonNull final ZonedDateTime date, final long amount) {
|
||||||
|
return plus(date, -amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public TemporalAmount multiplyAmount(final long amount) {
|
||||||
|
if (this.amount instanceof final Duration duration) {
|
||||||
|
return duration.multipliedBy(amount);
|
||||||
|
} else if (this.amount instanceof final Period period) {
|
||||||
|
return period.multipliedBy((int) amount);
|
||||||
|
}
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/main/java/de/ph87/data/series/IAggregationDto.java
Normal file
10
src/main/java/de/ph87/data/series/IAggregationDto.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package de.ph87.data.series;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
public interface IAggregationDto {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
SeriesDto getSeries();
|
||||||
|
|
||||||
|
}
|
||||||
31
src/main/java/de/ph87/data/series/SeriesController.java
Normal file
31
src/main/java/de/ph87/data/series/SeriesController.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package de.ph87.data.series;
|
||||||
|
|
||||||
|
import de.ph87.data.series.meter.*;
|
||||||
|
import de.ph87.data.series.varying.*;
|
||||||
|
import lombok.*;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("Series")
|
||||||
|
public class SeriesController {
|
||||||
|
|
||||||
|
private final MeterService meterService;
|
||||||
|
|
||||||
|
private final VaryingService varyingService;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@GetMapping("agg/all/{alignmentName}/{offsetAmount}")
|
||||||
|
public AggregationWrapperDto agg(@PathVariable final String alignmentName, @PathVariable final long offsetAmount) {
|
||||||
|
final Alignment alignment = Alignment.valueOf(alignmentName);
|
||||||
|
final ZonedDateTime date = alignment.align(ZonedDateTime.now()).minus(offsetAmount).date;
|
||||||
|
final List<IAggregationDto> aggregations = new ArrayList<>();
|
||||||
|
aggregations.addAll(meterService.findAllAggregations(alignment, date));
|
||||||
|
aggregations.addAll(varyingService.findAllAggregations(alignment, date));
|
||||||
|
return new AggregationWrapperDto(alignment, date, aggregations);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -48,7 +48,7 @@ public class SeriesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private SeriesDto toDto(@NonNull final Series series) {
|
public SeriesDto toDto(@NonNull final Series series) {
|
||||||
return new SeriesDto(series);
|
return new SeriesDto(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
package de.ph87.data.series.meter;
|
||||||
|
|
||||||
|
import de.ph87.data.series.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class MeterAggregation {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final Series series;
|
||||||
|
|
||||||
|
public final double delta;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package de.ph87.data.series.meter;
|
||||||
|
|
||||||
|
import de.ph87.data.series.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class MeterAggregationDto implements IAggregationDto {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final SeriesDto series;
|
||||||
|
|
||||||
|
public final double delta;
|
||||||
|
|
||||||
|
public MeterAggregationDto(@NonNull final MeterAggregation meterAggregation, @NonNull final SeriesDto series) {
|
||||||
|
this.series = series;
|
||||||
|
this.delta = meterAggregation.delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ import org.springframework.context.event.EventListener;
|
|||||||
import org.springframework.stereotype.*;
|
import org.springframework.stereotype.*;
|
||||||
import org.springframework.transaction.annotation.*;
|
import org.springframework.transaction.annotation.*;
|
||||||
|
|
||||||
|
import java.time.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.*;
|
import java.util.stream.*;
|
||||||
|
|
||||||
@ -75,14 +76,7 @@ public class MeterService {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<GraphPoint> getPoints(@NonNull final SeriesDto series, @NonNull final Aligned begin, @NonNull final Aligned end) {
|
public List<GraphPoint> getPoints(@NonNull final SeriesDto series, @NonNull final Aligned begin, @NonNull final Aligned end) {
|
||||||
final List<? extends MeterValue> graphPoints = switch (begin.alignment) {
|
final List<? extends MeterValue> graphPoints = findRepository(begin.alignment).findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
||||||
case FIVE -> meterFiveRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
|
||||||
case HOUR -> meterHourRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
|
||||||
case DAY -> meterDayRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
|
||||||
case WEEK -> meterWeekRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
|
||||||
case MONTH -> meterMonthRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
|
||||||
case YEAR -> meterYearRepository.findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(series.id, begin.date, end.date);
|
|
||||||
};
|
|
||||||
final List<GraphPoint> points = graphPoints.stream().map(meterValue -> new GraphPoint(meterValue.getId().getDate(), meterValue.getMax() - meterValue.getMin())).collect(Collectors.toCollection(LinkedList::new));
|
final List<GraphPoint> points = graphPoints.stream().map(meterValue -> new GraphPoint(meterValue.getId().getDate(), meterValue.getMax() - meterValue.getMin())).collect(Collectors.toCollection(LinkedList::new));
|
||||||
for (int i = 0; i < points.size() - 1; i++) {
|
for (int i = 0; i < points.size() - 1; i++) {
|
||||||
if (points.get(i).date.compareTo(points.get(i + 1).date) == 0) {
|
if (points.get(i).date.compareTo(points.get(i + 1).date) == 0) {
|
||||||
@ -94,4 +88,26 @@ public class MeterService {
|
|||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public List<MeterAggregationDto> findAllAggregations(@NonNull final Alignment alignment, @NonNull final ZonedDateTime date) {
|
||||||
|
return findRepository(alignment).findAllDeltaSum(date).stream().map(this::toDto).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private MeterAggregationDto toDto(@NonNull final MeterAggregation meterAggregation) {
|
||||||
|
return new MeterAggregationDto(meterAggregation, seriesService.toDto(meterAggregation.series));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private MeterValueRepository<?> findRepository(@NonNull final Alignment alignment) {
|
||||||
|
return switch (alignment) {
|
||||||
|
case FIVE -> meterFiveRepository;
|
||||||
|
case HOUR -> meterHourRepository;
|
||||||
|
case DAY -> meterDayRepository;
|
||||||
|
case WEEK -> meterWeekRepository;
|
||||||
|
case MONTH -> meterMonthRepository;
|
||||||
|
case YEAR -> meterYearRepository;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package de.ph87.data.series.meter;
|
package de.ph87.data.series.meter;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
import org.springframework.data.jpa.repository.*;
|
||||||
import org.springframework.data.repository.*;
|
import org.springframework.data.repository.*;
|
||||||
|
|
||||||
import java.time.*;
|
import java.time.*;
|
||||||
@ -11,4 +12,7 @@ public interface MeterValueRepository<T extends MeterValue> extends ListCrudRepo
|
|||||||
|
|
||||||
List<T> findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(long id, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
List<T> findAllByIdMeterSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqualOrderByIdDate(long id, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
||||||
|
|
||||||
|
@Query("select new de.ph87.data.series.meter.MeterAggregation(m.id.meter.series, sum(m.max - m.min)) from #{#entityName} m where m.id.date = :date group by m.id.meter.series")
|
||||||
|
List<MeterAggregation> findAllDeltaSum(@NonNull ZonedDateTime date);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
package de.ph87.data.series.varying;
|
||||||
|
|
||||||
|
import de.ph87.data.series.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class VaryingAggregation {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final Series series;
|
||||||
|
|
||||||
|
public final double min;
|
||||||
|
|
||||||
|
public final double avg;
|
||||||
|
|
||||||
|
public final double max;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package de.ph87.data.series.varying;
|
||||||
|
|
||||||
|
import de.ph87.data.series.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class VaryingAggregationDto implements IAggregationDto {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final SeriesDto series;
|
||||||
|
|
||||||
|
public final double min;
|
||||||
|
|
||||||
|
public final double avg;
|
||||||
|
|
||||||
|
public final double max;
|
||||||
|
|
||||||
|
public VaryingAggregationDto(@NonNull final VaryingAggregation varyingAggregation, @NonNull final SeriesDto series) {
|
||||||
|
this.series = series;
|
||||||
|
this.min = varyingAggregation.min;
|
||||||
|
this.avg = varyingAggregation.avg;
|
||||||
|
this.max = varyingAggregation.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package de.ph87.data.series.varying;
|
package de.ph87.data.series.varying;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
import org.springframework.data.jpa.repository.*;
|
||||||
import org.springframework.data.repository.*;
|
import org.springframework.data.repository.*;
|
||||||
|
|
||||||
import java.time.*;
|
import java.time.*;
|
||||||
@ -11,4 +12,7 @@ public interface VaryingRepository<T extends Varying> extends ListCrudRepository
|
|||||||
|
|
||||||
List<T> findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(long id, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
List<T> findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(long id, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
||||||
|
|
||||||
|
@Query("select new de.ph87.data.series.varying.VaryingAggregation(m.id.series, m.min, m.avg, m.max) from #{#entityName} m where m.id.date = :date")
|
||||||
|
List<VaryingAggregation> findAllDeltaSum(@NonNull ZonedDateTime date);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import org.springframework.context.event.EventListener;
|
|||||||
import org.springframework.stereotype.*;
|
import org.springframework.stereotype.*;
|
||||||
import org.springframework.transaction.annotation.*;
|
import org.springframework.transaction.annotation.*;
|
||||||
|
|
||||||
|
import java.time.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -61,15 +62,33 @@ public class VaryingService {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<GraphPoint> getPoints(@NonNull final SeriesDto series, @NonNull final Aligned begin, @NonNull final Aligned end) {
|
public List<GraphPoint> getPoints(@NonNull final SeriesDto series, @NonNull final Aligned begin, @NonNull final Aligned end) {
|
||||||
final List<? extends Varying> graphPoints = switch (begin.alignment) {
|
return findRepository(begin.alignment)
|
||||||
case FIVE -> varyingFiveRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date)
|
||||||
case HOUR -> varyingHourRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
.stream()
|
||||||
case DAY -> varyingDayRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
.map(v -> new GraphPoint(v.getId().getDate(), v.getAvg()))
|
||||||
case WEEK -> varyingWeekRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
.toList();
|
||||||
case MONTH -> varyingMonthRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
}
|
||||||
case YEAR -> varyingYearRepository.findAllByIdSeriesIdAndIdDateGreaterThanEqualAndIdDateLessThanEqual(series.id, begin.date, end.date);
|
|
||||||
|
@NonNull
|
||||||
|
public List<VaryingAggregationDto> findAllAggregations(@NonNull final Alignment alignment, @NonNull final ZonedDateTime date) {
|
||||||
|
return findRepository(alignment).findAllDeltaSum(date).stream().map(this::toDto).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private VaryingAggregationDto toDto(@NonNull final VaryingAggregation varyingAggregation) {
|
||||||
|
return new VaryingAggregationDto(varyingAggregation, seriesService.toDto(varyingAggregation.series));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private VaryingRepository<?> findRepository(@NonNull final Alignment alignment) {
|
||||||
|
return switch (alignment) {
|
||||||
|
case FIVE -> varyingFiveRepository;
|
||||||
|
case HOUR -> varyingHourRepository;
|
||||||
|
case DAY -> varyingDayRepository;
|
||||||
|
case WEEK -> varyingWeekRepository;
|
||||||
|
case MONTH -> varyingMonthRepository;
|
||||||
|
case YEAR -> varyingYearRepository;
|
||||||
};
|
};
|
||||||
return graphPoints.stream().map(v -> new GraphPoint(v.getId().getDate(), v.getAvg())).toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user