add median support
This commit is contained in:
parent
0dccca5b03
commit
451063dfc1
4 changed files with 349 additions and 487 deletions
|
@ -1 +1,2 @@
|
|||
db/
|
||||
.git/
|
||||
|
|
1
init.sql
1
init.sql
|
@ -30,6 +30,7 @@ CREATE TABLE IF NOT EXISTS delay_stats (
|
|||
total_trips INT,
|
||||
delayed_trips INT,
|
||||
avg_delay FLOAT,
|
||||
median_delay FLOAT,
|
||||
last_updated DATETIME,
|
||||
INDEX idx_fahrt_nr (fahrt_nr)
|
||||
);
|
||||
|
|
74
main.go
74
main.go
|
@ -10,6 +10,7 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -281,6 +282,18 @@ func updateTodayDelayStats(db *sql.DB, fahrtNr, trainName string, delay int, tim
|
|||
}
|
||||
}
|
||||
|
||||
func calculateMedian(delays []int) float64 {
|
||||
sort.Ints(delays)
|
||||
length := len(delays)
|
||||
if length == 0 {
|
||||
return 0
|
||||
}
|
||||
if length%2 == 0 {
|
||||
return float64(delays[length/2-1]+delays[length/2]) / 2
|
||||
}
|
||||
return float64(delays[length/2])
|
||||
}
|
||||
|
||||
func transferDailyDelayStats(db *sql.DB) {
|
||||
log.Println("Starte tägliche Übertragung der Verspätungsstatistiken")
|
||||
|
||||
|
@ -291,8 +304,7 @@ func transferDailyDelayStats(db *sql.DB) {
|
|||
}
|
||||
defer rows.Close()
|
||||
|
||||
var totalTransferred, totalUpdated, totalInserted int
|
||||
|
||||
delayMap := make(map[string][]int)
|
||||
for rows.Next() {
|
||||
var fahrtNr, trainName string
|
||||
var delay int
|
||||
|
@ -300,43 +312,40 @@ func transferDailyDelayStats(db *sql.DB) {
|
|||
log.Printf("Fehler beim Scannen der Verspätungsdaten: %v\n", err)
|
||||
continue
|
||||
}
|
||||
delayMap[fahrtNr] = append(delayMap[fahrtNr], delay)
|
||||
}
|
||||
|
||||
for fahrtNr, delays := range delayMap {
|
||||
avgDelay := calculateAverage(delays)
|
||||
medianDelay := calculateMedian(delays)
|
||||
totalTrips := len(delays)
|
||||
delayedTrips := countDelayedTrips(delays)
|
||||
|
||||
var existingID string
|
||||
err := db.QueryRow("SELECT id FROM delay_stats WHERE fahrt_nr = ?", fahrtNr).Scan(&existingID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
// Kein existierender Eintrag, führe INSERT aus
|
||||
_, err = db.Exec(`
|
||||
INSERT INTO delay_stats (id, fahrt_nr, total_trips, delayed_trips, avg_delay, last_updated)
|
||||
VALUES (UUID(), ?, 1, ?, ?, NOW())
|
||||
`, fahrtNr, delay > 300, delay)
|
||||
if err != nil {
|
||||
log.Printf("Fehler beim Einfügen der Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err)
|
||||
} else {
|
||||
totalInserted++
|
||||
log.Printf("Neue Verspätungsstatistik eingefügt für FahrtNr %s (Zug: %s, Verspätung: %d)\n", fahrtNr, trainName, delay)
|
||||
}
|
||||
INSERT INTO delay_stats (id, fahrt_nr, total_trips, delayed_trips, avg_delay, median_delay, last_updated)
|
||||
VALUES (UUID(), ?, ?, ?, ?, ?, NOW())
|
||||
`, fahrtNr, totalTrips, delayedTrips, avgDelay, medianDelay)
|
||||
} else if err == nil {
|
||||
// Existierender Eintrag gefunden, führe UPDATE aus
|
||||
_, err = db.Exec(`
|
||||
UPDATE delay_stats
|
||||
SET total_trips = total_trips + 1,
|
||||
SET total_trips = total_trips + ?,
|
||||
delayed_trips = delayed_trips + ?,
|
||||
avg_delay = ((avg_delay * total_trips) + ?) / (total_trips + 1),
|
||||
avg_delay = ((avg_delay * total_trips) + ?) / (total_trips + ?),
|
||||
median_delay = ?,
|
||||
last_updated = NOW()
|
||||
WHERE id = ?
|
||||
`, delay > 300, delay, existingID)
|
||||
`, totalTrips, delayedTrips, avgDelay*float64(totalTrips), totalTrips, medianDelay, existingID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Fehler beim Aktualisieren der Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err)
|
||||
} else {
|
||||
totalUpdated++
|
||||
log.Printf("Verspätungsstatistik aktualisiert für FahrtNr %s (Zug: %s, Verspätung: %d)\n", fahrtNr, trainName, delay)
|
||||
log.Printf("Verspätungsstatistik aktualisiert für FahrtNr %s (Durchschnitt: %.2f, Median: %.2f)\n", fahrtNr, avgDelay, medianDelay)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Fehler beim Überprüfen der Verspätungsstatistiken für FahrtNr %s: %v\n", fahrtNr, err)
|
||||
}
|
||||
|
||||
totalTransferred++
|
||||
}
|
||||
|
||||
// Löschen Sie die heutigen Statistiken nach der Übertragung
|
||||
|
@ -347,8 +356,24 @@ func transferDailyDelayStats(db *sql.DB) {
|
|||
rowsAffected, _ := result.RowsAffected()
|
||||
log.Printf("%d Einträge aus today_delay_stats gelöscht\n", rowsAffected)
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Tägliche Übertragung abgeschlossen. Gesamt: %d, Eingefügt: %d, Aktualisiert: %d\n", totalTransferred, totalInserted, totalUpdated)
|
||||
func calculateAverage(delays []int) float64 {
|
||||
sum := 0
|
||||
for _, delay := range delays {
|
||||
sum += delay
|
||||
}
|
||||
return float64(sum) / float64(len(delays))
|
||||
}
|
||||
|
||||
func countDelayedTrips(delays []int) int {
|
||||
count := 0
|
||||
for _, delay := range delays {
|
||||
if delay > 300 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func calculateCurrentPosition(trip *TripDetails, currentTime time.Time) (float64, float64) {
|
||||
|
@ -431,4 +456,3 @@ func logDatabaseStats(db *sql.DB) {
|
|||
}
|
||||
log.Printf("Aktuelle Anzahl der Einträge in der Datenbank: %d\n", count)
|
||||
}
|
||||
|
||||
|
|
164
main.go.old
164
main.go.old
|
@ -1,164 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Departure struct {
|
||||
CurrentTripPosition struct {
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
} `json:"currentTripPosition"`
|
||||
When time.Time `json:"when"`
|
||||
Line struct {
|
||||
Name string `json:"name"`
|
||||
FahrtNr string `json:"fahrtNr"`
|
||||
} `json:"line"`
|
||||
}
|
||||
|
||||
type APIResponse struct {
|
||||
Departures []Departure `json:"departures"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
|
||||
log.Println("Anwendung gestartet")
|
||||
|
||||
dbDSN := os.Getenv("DB_DSN")
|
||||
apiBaseURL := os.Getenv("API_BASE_URL")
|
||||
maxResults, err := strconv.Atoi(os.Getenv("MAX_RESULTS"))
|
||||
if err != nil {
|
||||
log.Fatalf("Ungültiger Wert für MAX_RESULTS: %v", err)
|
||||
}
|
||||
duration, err := strconv.Atoi(os.Getenv("DURATION"))
|
||||
if err != nil {
|
||||
log.Fatalf("Ungültiger Wert für DURATION: %v", err)
|
||||
}
|
||||
includeBus, err := strconv.ParseBool(os.Getenv("BUS"))
|
||||
if err != nil {
|
||||
log.Fatalf("Ungültiger Wert für BUS: %v", err)
|
||||
}
|
||||
includeFerry, err := strconv.ParseBool(os.Getenv("FERRY"))
|
||||
if err != nil {
|
||||
log.Fatalf("Ungültiger Wert für FERRY: %v", err)
|
||||
}
|
||||
includeTram, err := strconv.ParseBool(os.Getenv("TRAM"))
|
||||
if err != nil {
|
||||
log.Fatalf("Ungültiger Wert für TRAM: %v", err)
|
||||
}
|
||||
includeTaxi, err := strconv.ParseBool(os.Getenv("TAXI"))
|
||||
if err != nil {
|
||||
log.Fatalf("Ungültiger Wert für TAXI: %v", err)
|
||||
}
|
||||
deleteAfter, err := strconv.Atoi(os.Getenv("DELETE_AFTER_MINUTES"))
|
||||
if err != nil {
|
||||
log.Fatalf("Ungültiger Wert für DELETE_AFTER_MINUTES: %v", err)
|
||||
}
|
||||
stationIDs := strings.Split(os.Getenv("STATION_IDS"), ",")
|
||||
|
||||
db, err := sql.Open("mysql", dbDSN)
|
||||
if err != nil {
|
||||
log.Fatal("Fehler beim Verbinden mit der Datenbank: ", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
for {
|
||||
for _, stationID := range stationIDs {
|
||||
departures := fetchDepartures(apiBaseURL, stationID, maxResults, duration, includeBus, includeFerry, includeTram, includeTaxi)
|
||||
for _, dep := range departures {
|
||||
savePosition(db, dep)
|
||||
}
|
||||
}
|
||||
deleteOldEntries(db, deleteAfter)
|
||||
time.Sleep(1 * time.Minute)
|
||||
}
|
||||
}
|
||||
|
||||
func fetchDepartures(apiBaseURL, stationID string, maxResults, duration int, includeBus, includeFerry, includeTram, includeTaxi bool) []Departure {
|
||||
url := fmt.Sprintf("%s/stops/%s/departures?results=%d&duration=%d&bus=%t&ferry=%t&tram=%t&taxi=%t",
|
||||
apiBaseURL, stationID, maxResults, duration, includeBus, includeFerry, includeTram, includeTaxi)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Printf("Fehler beim Abrufen der Abfahrten für Station %s: %v\n", stationID, err)
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("Fehler beim Lesen der Antwort für Station %s: %v\n", stationID, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(body) == 0 {
|
||||
log.Printf("Leere Antwort vom Server für Station %s erhalten\n", stationID)
|
||||
return nil
|
||||
}
|
||||
|
||||
var response APIResponse
|
||||
err = json.Unmarshal(body, &response)
|
||||
if err != nil {
|
||||
log.Printf("Fehler beim Dekodieren der Abfahrten für Station %s: %v\nAntwort-Body: %s\n", stationID, err, string(body))
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("Erfolgreich %d Abfahrten für Station %s abgerufen\n", len(response.Departures), stationID)
|
||||
return response.Departures
|
||||
}
|
||||
|
||||
func savePosition(db *sql.DB, dep Departure) {
|
||||
if dep.CurrentTripPosition.Latitude == 0 && dep.CurrentTripPosition.Longitude == 0 {
|
||||
log.Println("Keine gültige Position verfügbar")
|
||||
return
|
||||
}
|
||||
|
||||
today := time.Now().Format("2006-01-02")
|
||||
|
||||
var existingID string
|
||||
err := db.QueryRow("SELECT id FROM trips WHERE fahrt_nr = ? AND DATE(timestamp) = ?", dep.Line.FahrtNr, today).Scan(&existingID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
id := uuid.New().String()
|
||||
_, err = db.Exec("INSERT INTO trips (id, latitude, longitude, timestamp, train_name, fahrt_nr) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
id, dep.CurrentTripPosition.Latitude, dep.CurrentTripPosition.Longitude, dep.When, dep.Line.Name, dep.Line.FahrtNr)
|
||||
if err != nil {
|
||||
log.Printf("Fehler beim Speichern der neuen Position: %v\n", err)
|
||||
} else {
|
||||
log.Printf("Neue Position gespeichert (ID: %s, Zug: %s, FahrtNr: %s)\n", id, dep.Line.Name, dep.Line.FahrtNr)
|
||||
}
|
||||
} else if err == nil {
|
||||
_, err = db.Exec("UPDATE trips SET latitude = ?, longitude = ?, timestamp = ?, train_name = ? WHERE id = ?",
|
||||
dep.CurrentTripPosition.Latitude, dep.CurrentTripPosition.Longitude, dep.When, dep.Line.Name, existingID)
|
||||
if err != nil {
|
||||
log.Printf("Fehler beim Aktualisieren der Position: %v\n", err)
|
||||
} else {
|
||||
log.Printf("Position aktualisiert (ID: %s, Zug: %s, FahrtNr: %s)\n", existingID, dep.Line.Name, dep.Line.FahrtNr)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Fehler bei der Überprüfung des existierenden Eintrags: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteOldEntries(db *sql.DB, deleteAfterMinutes int) {
|
||||
deleteTime := time.Now().Add(time.Duration(-deleteAfterMinutes) * time.Minute)
|
||||
result, err := db.Exec("DELETE FROM trips WHERE timestamp < ?", deleteTime)
|
||||
if err != nil {
|
||||
log.Printf("Fehler beim Löschen alter Einträge: %v\n", err)
|
||||
return
|
||||
}
|
||||
rowsAffected, _ := result.RowsAffected()
|
||||
log.Printf("%d alte Einträge gelöscht\n", rowsAffected)
|
||||
}
|
Loading…
Add table
Reference in a new issue