Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Development hints

## SQL Statements

SELECT sum(pkw), count(pkw), max(pkw), startuhrzeit::time FROM public.zeitintervall
where startuhrzeit between '2026-03-05' and '2026-03-06'
group by startuhrzeit::time order by startuhrzeit::time ASC limit 300;

SELECT sum(pkw)/(DATE_PART('day', '2026-03-06'::timestamp - '2026-03-05'::timestamp) + 1),
startuhrzeit::time
FROM public.zeitintervall
where startuhrzeit between '2026-03-05' and '2026-03-07' group by startuhrzeit::time
order by startuhrzeit::time ASC;

SELECT pkw, startuhrzeit::time, startuhrzeit::date,
DATE_PART('day', '2026-03-06'::timestamp - '2026-03-05'::timestamp)+1 FROM public.zeitintervall
where startuhrzeit between '2026-03-05' and '2026-03-07'
order by startuhrzeit::time ASC;

select sum(sumpkw),count(startuhrzeit::time), startuhrzeit::time from (
select sum(pkw) as sumpkw, startuhrzeit
FROM public.zeitintervall
where startuhrzeit between '2026-03-05' and '2026-03-12' and EXTRACT(DOW FROM startuhrzeit) IN (1, 2, 3, 4, 5)
and zaehlung_id = '339f992e-0925-4f6d-9e75-099bc520ad2c' group by startuhrzeit)
group by startuhrzeit::time order by startuhrzeit::time ASC;

Comment on lines +5 to +26
select sum(sumpkw),count(startuhrzeit::time), startuhrzeit::time from (
select sum(pkw) as sumpkw, startuhrzeit
FROM public.zeitintervall
where startuhrzeit between '2026-03-05' and '2026-03-12' and EXTRACT(DOW FROM startuhrzeit) IN (1, 2, 3, 4, 5) and type = 'STUNDE_VIERTEL'
and zaehlung_id = '339f992e-0925-4f6d-9e75-099bc520ad2c' group by startuhrzeit)
group by startuhrzeit::time order by startuhrzeit::time ASC;

select
round(sum(pkw)/count(startuhrzeit::time)) as pkw,
round(sum(lkw)/count(startuhrzeit::time)) as lkw,
round(sum (lastzuege)/count(startuhrzeit::time)) as lastzuege,
round(sum(busse)/count(startuhrzeit::time)) as busse,
round(sum(kraftraeder)/count(startuhrzeit::time)) as kraftraeder,
round(sum(fahrradfahrer)/count(startuhrzeit::time)) as fahrradfahrer,
round(sum(fussgaenger)/count(startuhrzeit::time)) as fussgaenger,
startuhrzeit::time,
endeuhrzeit::time
from (
select
sum(pkw) as pkw,
sum(lkw) as lkw,
sum (lastzuege) as lastzuege,
sum(busse) as busse,
sum(kraftraeder) as kraftraeder,
sum(fahrradfahrer) as fahrradfahrer,
sum(fussgaenger) as fussgaenger,
startuhrzeit,
endeuhrzeit
FROM public.zeitintervall
where startuhrzeit between '2026-03-05 00:00:00' and '2026-03-06 23:59:59' and EXTRACT(DOW FROM startuhrzeit) IN (1, 2, 3, 4, 5) and type = 'STUNDE_VIERTEL'
and zaehlung_id = '339f992e-0925-4f6d-9e75-099bc520ad2c' group by startuhrzeit, endeuhrzeit)
group by startuhrzeit::time, endeuhrzeit::time order by startuhrzeit::time ASC

select
zaehlung_id,
round(sum(pkw)/count(startuhrzeit::time)) as pkw,
round(sum(lkw)/count(startuhrzeit::time)) as lkw,
round(sum (lastzuege)/count(startuhrzeit::time)) as lastzuege,
round(sum(busse)/count(startuhrzeit::time)) as busse,
round(sum(kraftraeder)/count(startuhrzeit::time)) as kraftraeder,
round(sum(fahrradfahrer)/count(startuhrzeit::time)) as fahrradfahrer,
round(sum(fussgaenger)/count(startuhrzeit::time)) as fussgaenger,
round(sum(hochrechnung_hochrechnungkfz)/count(startuhrzeit::time),2) as hochrechnungkfz,
round(sum(hochrechnung_hochrechnunggv)/count(startuhrzeit::time),2) as hochrechnunggv,
round(sum(hochrechnung_hochrechnungsv)/count(startuhrzeit::time),2) as hochrechnungsv,
round(sum(hochrechnungrad)/count(startuhrzeit::time)) as hochrechnungrad,
(CURRENT_DATE + startuhrzeit::time) as startUhrzeit,
(CURRENT_DATE + endeuhrzeit::time) as endeUhrzeit
from (
select
zaehlung_id,
sum(pkw) as pkw,
sum(lkw) as lkw,
sum (lastzuege) as lastzuege,
sum(busse) as busse,
sum(kraftraeder) as kraftraeder,
sum(fahrradfahrer) as fahrradfahrer,
sum(fussgaenger) as fussgaenger,
sum(hochrechnung_hochrechnungkfz) as hochrechnung_hochrechnungkfz,
sum(hochrechnung_hochrechnunggv) as hochrechnung_hochrechnunggv,
sum(hochrechnung_hochrechnungsv) as hochrechnung_hochrechnungsv,
sum(hochrechnungrad) as hochrechnungrad,
startuhrzeit,
endeuhrzeit
FROM public.zeitintervall
where startuhrzeit between '2026-03-05 00:00:00' and '2026-03-06 23:59:59' and EXTRACT(DOW FROM startuhrzeit) IN (1, 2, 3, 4, 5) and type = 'STUNDE_VIERTEL'
and zaehlung_id = '339f992e-0925-4f6d-9e75-099bc520ad2c' group by startuhrzeit, endeuhrzeit, zaehlung_id)
group by startuhrzeit::time, endeuhrzeit::time, zaehlung_id order by startUhrzeit ASC
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public ResponseEntity<LadeProcessedZaehldatenDTO> ladeZaehldatenProcessed(
zaehlungId,
options);
log.info("laden der Daten abgeschlossen.");
log.debug("Zähldaten: {}", processedZaehldaten.toString());
return ResponseEntity.ok(processedZaehldaten);
} catch (final DataNotFoundException exception) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, exception.getMessage());
Expand Down
88 changes: 88 additions & 0 deletions src/main/java/de/muenchen/dave/domain/Zeitintervall.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.AttributeOverrides;
import jakarta.persistence.Column;
import jakarta.persistence.ColumnResult;
import jakarta.persistence.ConstructorResult;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Index;
import jakarta.persistence.NamedNativeQuery;
import jakarta.persistence.SqlResultSetMapping;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
import lombok.AllArgsConstructor;
Expand All @@ -28,6 +33,68 @@
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;

@NamedNativeQuery(
name = "Zeitintervall.findWeekdayAverageByZaehlungIdOrderBySortingIndexAsc",
query = "select \n" + //
"\tzaehlung_id, \n" + //
"\tround(sum(pkw)/count(startuhrzeit::time)) as pkw, \n" + //
"\tround(sum(lkw)/count(startuhrzeit::time)) as lkw,\n" + //
"\tround(sum (lastzuege)/count(startuhrzeit::time)) as lastzuege,\n" + //
"\tround(sum(busse)/count(startuhrzeit::time)) as busse,\n" + //
"\tround(sum(kraftraeder)/count(startuhrzeit::time)) as kraftraeder,\n" + //
"\tround(sum(fahrradfahrer)/count(startuhrzeit::time)) as fahrradfahrer,\n" + //
"\tround(sum(fussgaenger)/count(startuhrzeit::time)) as fussgaenger, \n" + //
"\tround(sum(hochrechnung_hochrechnungkfz)/count(startuhrzeit::time),2) as hochrechnungkfz,\n" + //
"\tround(sum(hochrechnung_hochrechnunggv)/count(startuhrzeit::time),2) as hochrechnunggv,\n" + //
"\tround(sum(hochrechnung_hochrechnungsv)/count(startuhrzeit::time),2) as hochrechnungsv,\n" + //
"\tround(sum(hochrechnungrad)/count(startuhrzeit::time)) as hochrechnungrad,\n" + //
Comment on lines +40 to +50
"\tCURRENT_DATE + startuhrzeit::time as startUhrzeit, \n" + //
"\tCURRENT_DATE + endeuhrzeit::time as endeUhrzeit \n" + //
"from (\n" + //
"select \n" + //
"\tzaehlung_id, \n" + //
"\tsum(pkw) as pkw, \n" + //
"\tsum(lkw) as lkw,\n" + //
"\tsum (lastzuege) as lastzuege,\n" + //
"\tsum(busse) as busse,\n" + //
"\tsum(kraftraeder) as kraftraeder,\n" + //
"\tsum(fahrradfahrer) as fahrradfahrer,\n" + //
"\tsum(fussgaenger) as fussgaenger, \n" + //
"\tsum(hochrechnung_hochrechnungkfz) as hochrechnung_hochrechnungkfz,\n" + //
"\tsum(hochrechnung_hochrechnunggv) as hochrechnung_hochrechnunggv,\n" + //
"\tsum(hochrechnung_hochrechnungsv) as hochrechnung_hochrechnungsv,\n" + //
"\tsum(hochrechnungrad) as hochrechnungrad,\n" + //
"\tstartuhrzeit, \n" + //
"\tendeuhrzeit\n" + //
"FROM public.zeitintervall \n" + //
"where startuhrzeit between :start and :ende and EXTRACT(DOW FROM startuhrzeit) IN (:tagestyp) \n" + //
"\tand zaehlung_id = :zaehlungId \n" + //
"\tand fahrbeziehung_von IN (:vonKnotenarm) and fahrbeziehung_nach IN (:nachKnotenarm) group by startuhrzeit, endeuhrzeit, zaehlung_id) \n" + //
"\tgroup by startuhrzeit::time, endeuhrzeit::time, zaehlung_id order by startUhrzeit ASC",
resultSetMapping = "Mapping.Zeitintervall"
)
@SqlResultSetMapping(
name = "Mapping.Zeitintervall",
classes = @ConstructorResult(
targetClass = Zeitintervall.class,
columns = {
@ColumnResult(name = "zaehlung_id", type = String.class),
@ColumnResult(name = "pkw", type = Integer.class),
@ColumnResult(name = "lkw", type = Integer.class),
@ColumnResult(name = "lastzuege", type = Integer.class),
@ColumnResult(name = "busse", type = Integer.class),
@ColumnResult(name = "kraftraeder", type = Integer.class),
@ColumnResult(name = "fahrradfahrer", type = Integer.class),
@ColumnResult(name = "fussgaenger", type = Integer.class),
@ColumnResult(name = "hochrechnungkfz", type = BigDecimal.class),
@ColumnResult(name = "hochrechnunggv", type = BigDecimal.class),
@ColumnResult(name = "hochrechnungsv", type = BigDecimal.class),
@ColumnResult(name = "hochrechnungrad", type = Integer.class),
@ColumnResult(name = "startUhrzeit", type = LocalDateTime.class),
@ColumnResult(name = "endeUhrzeit", type = LocalDateTime.class)
}
)
)
@Entity
// Definition of getter, setter, ...
@Getter
Expand All @@ -51,6 +118,27 @@
)
public class Zeitintervall extends BaseEntity {

public Zeitintervall(String zaehlung_id, Integer pkw, Integer lkw, Integer lastzuege, Integer busse, Integer kraftraeder,
Integer fahrradfahrer, Integer fussgaenger, BigDecimal hochrechnungkfz, BigDecimal hochrechnunggv, BigDecimal hochrechnungsv,
Integer hochrechnungrad, LocalDateTime startUhrzeit, LocalDateTime endeUhrzeit) {
this.zaehlungId = UUID.fromString(zaehlung_id);
this.pkw = pkw;
this.lkw = lkw;
this.lastzuege = lastzuege;
this.busse = busse;
this.kraftraeder = kraftraeder;
this.fahrradfahrer = fahrradfahrer;
this.fussgaenger = fussgaenger;
this.startUhrzeit = startUhrzeit;
this.endeUhrzeit = endeUhrzeit;
this.fahrbeziehung = new Fahrbeziehung();
this.hochrechnung = new Hochrechnung();
this.hochrechnung.setHochrechnungKfz(hochrechnungkfz);
this.hochrechnung.setHochrechnungGv(hochrechnunggv);
this.hochrechnung.setHochrechnungSv(hochrechnungsv);
this.hochrechnung.setHochrechnungRad(hochrechnungrad);
}

@Column(name = "zaehlung_id", nullable = false)
@JdbcTypeCode(SqlTypes.VARCHAR)
private UUID zaehlungId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.UUID;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface ZeitintervallRepository extends JpaRepository<Zeitintervall, UUID> { //NOSONAR

Expand Down Expand Up @@ -70,6 +71,15 @@ List<Zeitintervall> findByZaehlungIdAndStartUhrzeitGreaterThanEqualAndEndeUhrzei
final LocalDateTime endeUhrzeit,
final FahrbewegungKreisverkehr fahrbewegungKreisverkehr);

@Query(nativeQuery = true)
List<Zeitintervall> findWeekdayAverageByZaehlungIdOrderBySortingIndexAsc(
final String zaehlungId,
final LocalDateTime start,
final LocalDateTime ende,
final List<Integer> vonKnotenarm,
final List<Integer> nachKnotenarm,
final List<Integer> tagestyp);
Comment on lines +74 to +81

Zeitintervall findByZaehlungIdAndTypeAndFahrbeziehungVonAndFahrbeziehungNachAndStartUhrzeitGreaterThanEqualAndEndeUhrzeitLessThanEqualAndFahrbeziehungFahrbewegungKreisverkehrIsNull(
final UUID zaehlungId,
final TypeZeitintervall type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.SetUtils;
import org.apache.commons.lang3.BooleanUtils;
Expand Down Expand Up @@ -324,22 +325,67 @@ public LadeZaehldatenTableDTO ladeZaehldaten(final UUID zaehlungId,
final OptionsDTO options) throws DataNotFoundException {

final LadeZaehldatenTableDTO ladeZaehldatenTable = new LadeZaehldatenTableDTO();
final List<Zeitintervall> zeitintervalle;
List<LadeZaehldatumDTO> ladeZaehldaten;
final Zaehlung zaehlung = indexService.getZaehlung(zaehlungId.toString());
if (StringUtils.contains(options.getZeitauswahl(), ZEITAUSWAHL_SPITZENSTUNDE)) {
zeitintervalle = extractZeitintervalleForSpitzenstunde(zaehlungId, zaehlung.getZaehldauer(), zaehlung.getKreisverkehr(), options);
} else {
zeitintervalle = extractZeitintervalle(zaehlungId, zaehlung.getZaehldauer(), zaehlung.getKreisverkehr(), options);
}
final PkwEinheit pkwEinheit = zaehlung.getPkwEinheit();
List<LadeZaehldatumDTO> ladeZaehldaten = zeitintervalle.stream()
.map(zeitintervall -> mapToZaehldatum(zeitintervall, pkwEinheit, options))
.collect(Collectors.toList());
if (StringUtils.contains(options.getZeitauswahl(), ZEITAUSWAHL_SPITZENSTUNDE)) {
List<Zeitintervall> zeitintervalle = extractZeitintervalleForSpitzenstunde(zaehlungId, zaehlung.getZaehldauer(), zaehlung.getKreisverkehr(),
options);
ladeZaehldaten = zeitintervalle.stream()
.map(zeitintervall -> mapToZaehldatum(zeitintervall, pkwEinheit, options))
.collect(Collectors.toList());
} else if (zaehlung.getDauerzaehlung() && options.getZeitraum().size() == 2
&& StringUtils.equals(options.getZeitauswahl(), LadeZaehldatenService.ZEITAUSWAHL_ZEITRAUM)) {
List<Zeitintervall> zeitintervalle = extractZeitintervalleWochentagsdurchschnitt(zaehlungId, options);
ladeZaehldaten = zeitintervalle.stream()
.map(zeitintervall -> mapToZaehldatum(zeitintervall, pkwEinheit, options))
.collect(Collectors.toList());
} else {
List<Zeitintervall> zeitintervalle = extractZeitintervalle(zaehlungId, zaehlung.getZaehldauer(), zaehlung.getKreisverkehr(), options);
Comment on lines +337 to +344
ladeZaehldaten = zeitintervalle.stream()
.map(zeitintervall -> mapToZaehldatum(zeitintervall, pkwEinheit, options))
.collect(Collectors.toList());
}

ladeZaehldatenTable.setZaehldaten(ladeZaehldaten);
log.debug("Anzahl der Zaehldaten: {}", ladeZaehldatenTable.getZaehldaten().size());
return ladeZaehldatenTable;
}

private List<Zeitintervall> extractZeitintervalleWochentagsdurchschnitt(final UUID zaehlungId,
final OptionsDTO options) throws DataNotFoundException {
LocalDateTime start = options.getZeitraum().get(0).atTime(0, 0, 0);
LocalDateTime end = options.getZeitraum().get(1).atTime(23, 59, 59);
List<Integer> vonKnotenarm = IntStream.rangeClosed(1, 8).boxed().toList();
List<Integer> nachKnotenarm = IntStream.rangeClosed(1, 8).boxed().toList();

if (options.getBeideRichtungen() && options.getVonKnotenarm() != null && options.getNachKnotenarm() != null) {
vonKnotenarm = List.of(options.getVonKnotenarm(), options.getNachKnotenarm()).stream().filter(val -> val != null).collect(Collectors.toList());
nachKnotenarm = List.of(options.getVonKnotenarm(), options.getNachKnotenarm());
} else if (options.getVonKnotenarm() != null) {
vonKnotenarm = List.of(options.getVonKnotenarm());
if (options.getBeideRichtungen() != null && options.getNachKnotenarm() != null) {
vonKnotenarm.add(options.getNachKnotenarm());
}
} else if (options.getNachKnotenarm() != null) {
nachKnotenarm = List.of(options.getNachKnotenarm());
if (options.getBeideRichtungen() != null && options.getVonKnotenarm() != null) {
vonKnotenarm.add(options.getVonKnotenarm());
}
}
List<Integer> tagestyp = List.of(1, 2, 3, 4, 5);
List<Zeitintervall> zi = zeitintervallRepository.findWeekdayAverageByZaehlungIdOrderBySortingIndexAsc(
zaehlungId.toString(),
start,
end,
vonKnotenarm,
nachKnotenarm,
tagestyp);
log.debug("Size of extracted Zeitintervalle for Wochentagsdurchschnitt: {}", zi.size());
List<Zeitintervall> allZeitintervalle = zeitintervallPersistierungsService.aufbereitenUndPersistieren(zi, false);
return allZeitintervalle;
}

private List<Zeitintervall> extractZeitintervalle(final UUID zaehlungId,
final String zaehldauer,
final Boolean isKreisverkehr,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ public List<Zeitintervall> aufbereitenForZeitraum(final List<Zeitintervall> zeit
allZeitintervalle.addAll(summierteZeitbloecke);
allZeitintervalle.addAll(kiZeitintervalle);

for (Zeitintervall zeitintervall : allZeitintervalle) {
log.debug(zeitintervall.getFahrbeziehung() + " " + zeitintervall.getType() + " " + zeitintervall.getStartUhrzeit() + " "
+ zeitintervall.getEndeUhrzeit() + " " + zeitintervall.getPkw());
}
//for (Zeitintervall zeitintervall : allZeitintervalle) {
// log.debug(zeitintervall.getFahrbeziehung() + " " + zeitintervall.getType() + " " + zeitintervall.getStartUhrzeit() + " "
// + zeitintervall.getEndeUhrzeit() + " " + zeitintervall.getPkw());
//}
Comment on lines +108 to +111

return allZeitintervalle;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
import de.muenchen.dave.repositories.elasticsearch.ZaehlstelleIndex;
import de.muenchen.dave.repositories.relationaldb.CityDistrictRepository;
import de.muenchen.dave.repositories.relationaldb.ZaehlstelleRepository;
import de.muenchen.dave.repositories.relationaldb.ZeitintervallRepository;
import de.muenchen.dave.services.ConfigurationService;
import de.muenchen.dave.services.ZaehlstelleIndexService;
import de.muenchen.dave.services.persist.ExternalDetectorService;
import de.muenchen.elasticimpl.CustomSuggestIndexElasticRepository;
import de.muenchen.elasticimpl.MessstelleIndexElasticRepository;
import de.muenchen.elasticimpl.ZaehlstelleIndexElasticRepository;
Expand Down Expand Up @@ -61,6 +64,12 @@ public class StadtbezirkMapperTest {
@MockitoBean
private ZaehlstelleRepository zaehlstelleRepository;

@MockitoBean
private ZaehlstelleIndexService zaehlstelleIndexService;

@MockitoBean
private ExternalDetectorService externalDetectorService;

@MockitoBean
private MessstelleRepository messstelleRepository;

Expand All @@ -72,6 +81,9 @@ public class StadtbezirkMapperTest {
@MockitoBean
private CustomSuggestIndex customSuggestIndex;

@MockitoBean
private ZeitintervallRepository zeitintervallRepository;

@BeforeEach
private void beforeEach() {

Expand Down
Loading