fix: materialize stationary yutong daily mileage
This commit is contained in:
@@ -35,6 +35,7 @@ type config struct {
|
||||
Reset bool
|
||||
Debug bool
|
||||
EventTimeFullScan bool
|
||||
StationaryCarry bool
|
||||
ProgressEvery int64
|
||||
BaselineLookback int
|
||||
Location *time.Location
|
||||
@@ -453,7 +454,8 @@ func addRealtimeLocationFallbackAggregates(ctx context.Context, mysqlDB *sql.DB,
|
||||
return added, err
|
||||
}
|
||||
for vin, currentSources := range current {
|
||||
for _, currentRow := range currentSources {
|
||||
for i := range currentSources {
|
||||
currentRow := currentSources[i]
|
||||
key := vin + "|" + date + "|" + string(protocol) + "|" + currentRow.SourceKey
|
||||
if _, exists := aggregates[key]; exists {
|
||||
continue
|
||||
@@ -462,8 +464,22 @@ func addRealtimeLocationFallbackAggregates(ctx context.Context, mysqlDB *sql.DB,
|
||||
if err != nil {
|
||||
return added, err
|
||||
}
|
||||
if cfg.StationaryCarry && !hasPrevious {
|
||||
continue
|
||||
}
|
||||
if cfg.StationaryCarry {
|
||||
// A sparse Yutong location frame can retain an older
|
||||
// realtime odometer than the durable daily baseline.
|
||||
// Stationary carry-forward represents an explicit zero
|
||||
// day, so both ends must use the latest trusted baseline.
|
||||
currentRow.FirstTotalKM = previousRow.TotalKM
|
||||
currentRow.TotalKM = previousRow.TotalKM
|
||||
currentSources[i] = currentRow
|
||||
}
|
||||
agg := aggregateFromDailySource(date, protocol, currentRow, previousRow, hasPrevious)
|
||||
if hasPrevious {
|
||||
if cfg.StationaryCarry {
|
||||
agg.QualityReason = stats.QualityReasonStationaryCarry
|
||||
} else if hasPrevious {
|
||||
agg.QualityReason = "realtime_location_fallback_historical_baseline"
|
||||
} else {
|
||||
agg.QualityReason = "realtime_location_fallback_current_day_first_baseline"
|
||||
@@ -716,15 +732,28 @@ func queryRealtimeLocationLastRows(ctx context.Context, db *sql.DB, cfg config,
|
||||
if loc == nil {
|
||||
loc = time.FixedZone("Asia/Shanghai", 8*3600)
|
||||
}
|
||||
sqlText := `SELECT l.vin, COALESCE(NULLIF(s.peer, ''), ''), l.total_mileage_event_time, l.total_mileage_km
|
||||
eventTimeColumn := "l.total_mileage_event_time"
|
||||
timePredicate := `l.total_mileage_event_time >= ?
|
||||
AND l.total_mileage_event_time < DATE_ADD(?, INTERVAL 1 DAY)`
|
||||
if cfg.StationaryCarry {
|
||||
eventTimeColumn = "l.event_time"
|
||||
timePredicate = `l.event_time >= ?
|
||||
AND l.event_time < DATE_ADD(?, INTERVAL 1 DAY)
|
||||
AND l.total_mileage_event_time < ?
|
||||
AND COALESCE(l.speed_kmh, 0) = 0`
|
||||
}
|
||||
sqlText := `SELECT l.vin, COALESCE(NULLIF(s.peer, ''), ''), ` + eventTimeColumn + `, l.total_mileage_km
|
||||
FROM vehicle_realtime_location l
|
||||
LEFT JOIN vehicle_realtime_snapshot s ON s.protocol = l.protocol AND s.vin = l.vin
|
||||
WHERE l.protocol = ?
|
||||
AND l.vin IS NOT NULL AND l.vin <> ''
|
||||
AND l.total_mileage_km IS NOT NULL AND l.total_mileage_km > 0
|
||||
AND l.total_mileage_event_time >= ?
|
||||
AND l.total_mileage_event_time < DATE_ADD(?, INTERVAL 1 DAY)`
|
||||
rows, err := db.QueryContext(ctx, sqlText, string(protocol), date, date)
|
||||
AND ` + timePredicate
|
||||
args := []any{string(protocol), date, date}
|
||||
if cfg.StationaryCarry {
|
||||
args = append(args, date)
|
||||
}
|
||||
rows, err := db.QueryContext(ctx, sqlText, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -979,6 +1008,7 @@ func loadConfig() (config, error) {
|
||||
Reset: envBool("BACKFILL_RESET", false),
|
||||
Debug: envBool("BACKFILL_DEBUG", false),
|
||||
EventTimeFullScan: envBool("BACKFILL_EVENT_TIME_FULL_SCAN", false),
|
||||
StationaryCarry: envBool("BACKFILL_STATIONARY_CARRY_FORWARD", false),
|
||||
ProgressEvery: int64(envInt("BACKFILL_PROGRESS_EVERY", 100000)),
|
||||
BaselineLookback: envInt("BACKFILL_BASELINE_LOOKBACK_DAYS", 7),
|
||||
Location: loc,
|
||||
|
||||
Reference in New Issue
Block a user