79 lines
4.3 KiB
Markdown
Executable File
79 lines
4.3 KiB
Markdown
Executable File
# Derin Teknik Düzeltmeler ve Analiz Günlüğü
|
||
|
||
**Dosya:** `02_deep_fixes_log.md`
|
||
**Amaç:** Son geliştirme döngüsünde çözülen karmaşık sorunların teknik detaylarını belgelemek.
|
||
|
||
---
|
||
|
||
## 1. Live Match Synchronization & DB Safety
|
||
|
||
### Sorun Tanımı
|
||
|
||
Canlı maçlar (Live Matches), ana `matches` tablosuna henüz işlenmemiş olabiliyor. Ancak sistem bunları analiz etmeye çalıştığında:
|
||
|
||
1. `match_player_participation` tablosuna oyuncu eklemeye çalışıyor -> `matches` tablosunda ID olmadığı için **Foreign Key Constraint Error** alıyordu.
|
||
2. Veri tabana yazılamadığı için Python scripti "Lineup not found" hatasıyla patlıyordu.
|
||
|
||
### Uygulanan Çözüm
|
||
|
||
**Dual-Persistence Strategy (Çift Yazma Stratejisi):**
|
||
|
||
- **Logic:** `FeederPersistenceService.saveLineups` ve `saveOdds` metodları artık önce `matches` tablosunda `matchId` var mı diye kontrol ediyor.
|
||
- **Varsa:** Hem ilişkisel tablolara (`match_player_participation`) hem de `live_matches` JSON kolonuna yazıyor.
|
||
- **Yoksa (Sadece Canlı):** İlişkisel tabloları tamamen pas geçiyor (SKIP), veriyi sadece `live_matches.lineups` ve `live_matches.odds` JSON kolonlarına strüktüre edilmiş olarak yazıyor.
|
||
|
||
**Fallback Mechanism (Python & NestJS):**
|
||
|
||
- **NestJS:** `getPlayerCount` metodu önce ilişkisel tabloyu sayıyor. Sayı 0 ise `live_matches` JSON'ını parse edip oradaki oyuncu sayısını dönüyor.
|
||
- **Python:** `_run_model` içinde önce SQL sorgusu ile kadro çekmeye çalışıyor. Liste boşsa, `live_matches` tablosundaki JSON kolonunu çekip manuel parse ediyor.
|
||
|
||
---
|
||
|
||
## 2. Model Score & Context Mapping (Kritik)
|
||
|
||
### Sorun Tanımı
|
||
|
||
Kullanıcı, modelin skor tahminlerinin ve maç sonucu (1/X/2) tercihlerinin tutarsız olduğundan şikayetçiydi ("Home win diyor ama skor 0-1" gibi).
|
||
|
||
### Tespit Edilen Kök Nedenler
|
||
|
||
1. **HT/FT Sıralaması:** Model eğitimi `ht*3 + ft` (0=X, 1=1, 2=2) mantığıyla yapılmıştı. Ancak tahmin scripti etiketleri `1/1, 1/X...` gibi rastgele bir sırayla diziyordu. Bu yüzden `1/1` tahmini `X/X` gibi görünüyordu.
|
||
2. **Beraberlik (Draw) Körlüğü:** Data Feeder, beraberlik oranını `X` etiketiyle kaydediyordu (Mackolik verisi). Python scripti ise sadece `0` etiketini "Beraberlik" olarak kabul ediyordu. Sonuç olarak model "Beraberlik Oranı: 0.0" görüyordu (yani oran yok). Bu, modelin maçın dengesini yanlış anlamasına neden oluyordu.
|
||
3. **Away Bias (Deplasman Yanlılığı):** Backtest verileri, modelin sistematik olarak deplasman takımına fazla gol yazdığını (%15-20 fazla) gösterdi.
|
||
|
||
### Uygulanan Çözüm
|
||
|
||
1. **Etiket Düzeltmesi:** `htft_labels` listesi `[X/X, X/1, X/2, 1/X, 1/1, 1/2, 2/X, 2/1, 2/2]` olarak, eğitim verisiyle %100 uyumlu hale getirildi.
|
||
2. **Oran Normalizasyonu:** Python scripti artık hem `0` hem `X` etiketlerini beraberlik oranı olarak kabul ediyor.
|
||
3. **Skor Kalibrasyonu:** Backtest sonrası optimizasyon katsayıları eklendi.
|
||
- `HOME_GOAL_SCALE = 1.00`
|
||
- `AWAY_GOAL_SCALE = 0.85`
|
||
|
||
---
|
||
|
||
## 3. Akıllı Kupon Servisi (Smart Coupon)
|
||
|
||
### Yapı
|
||
|
||
NestJS tarafında `SmartCouponService` ve Python tarafında `smart_coupon_service.py` (CLI) işbirliği ile çalışır.
|
||
|
||
### Akış
|
||
|
||
1. **Request:** POST `/api/coupon/analyze-match` { matchId }
|
||
2. **Pre-Check 1 (Kadro):** DB'de kadro var mı?
|
||
- Yoksa -> `FeederService.refreshMatch(lineups)` -> Tekrar kontrol -> Hâlâ yoksa Hata Fırlat ("Yetersiz Veri").
|
||
3. **Pre-Check 2 (Oran):** DB'de oran var mı?
|
||
- Yoksa -> `FeederService.refreshMatch(odds)` -> Log bas (Engelleyici değil).
|
||
4. **Prediction:** Python scripti çalıştırılır (`--analyze --json`).
|
||
- Script: DB veya JSON Fallback'ten veriyi okur.
|
||
- Script: Modeli çalıştırır, kalibrasyon katsayılarını uygular.
|
||
- Script: JSON döner.
|
||
5. **Response:** NestJS JSON'ı parse edip kullanıcıya döner.
|
||
|
||
---
|
||
|
||
## Gelecek İçin Notlar
|
||
|
||
- **Database:** `live_matches` tablosundaki JSON kolonları artık kritik öneme sahip. Bunların şeması `Prisma` tarafında `Json` olarak tanımlı ama iç yapısı kod içinde (`FeederPersistence`) belirleniyor. Yapıyı değiştirirken dikkatli olunmalı.
|
||
- **Model:** V17 modeli şu an stabil. V18'e geçilirse `player_model_v17.py` değiştirilmeli ve `smart_coupon_service.py` içindeki scale faktörleri sıfırlanıp tekrar backtest yapılmalı.
|