159 lines
4.5 KiB
Markdown
159 lines
4.5 KiB
Markdown
# Stats Service API - Статистические рекомендации и агрегаты
|
||
|
||
## Endpoints
|
||
|
||
### GET /api/v1/stats/summary
|
||
Получить агрегированную статистику для дашборда.
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"total_cases": 8,
|
||
"active_cases": 7,
|
||
"closed_cases": 1,
|
||
"by_gender": {"М": 8},
|
||
"by_age_group": {
|
||
"8-11": 6,
|
||
"12-14": 2
|
||
},
|
||
"by_psychotype": {},
|
||
"by_diagnosis": {"здоров": 3},
|
||
"by_season": {
|
||
"зима": 3,
|
||
"весна": 1,
|
||
"лето": 1
|
||
},
|
||
"avg_distance_km": 2.3,
|
||
"avg_search_duration_hours": 4.5,
|
||
"survival_rate": 100.0
|
||
}
|
||
```
|
||
|
||
### POST /api/v1/stats/recommendation
|
||
Получить статистические рекомендации на основе похожих случаев.
|
||
|
||
**Фильтры (в порядке приоритета):**
|
||
1. Возраст ±2 года + сезон + terrain
|
||
2. Возраст ±2 года + сезон (если < 5 случаев)
|
||
3. Возраст ±2 года (если < 5 случаев)
|
||
4. Все случаи (если < 5 случаев)
|
||
|
||
**Request:**
|
||
```json
|
||
{
|
||
"age": 10,
|
||
"season": "лето",
|
||
"terrain_primary": "лес"
|
||
}
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"median_distance_km": 2.3,
|
||
"top_directions": [
|
||
{
|
||
"direction": "СВ",
|
||
"count": 1,
|
||
"percentage": 100.0
|
||
}
|
||
],
|
||
"top_location_types": ["forest"],
|
||
"survival_rate": 100.0,
|
||
"sample_size": 1,
|
||
"filters_used": {
|
||
"age_range": "8 to 12",
|
||
"season": "лето",
|
||
"terrain": "лес"
|
||
}
|
||
}
|
||
```
|
||
|
||
### GET /api/v1/stats/heatmap
|
||
Получить данные для тепловой карты находок.
|
||
|
||
**Query Parameters:**
|
||
- `age_min` (optional): Минимальный возраст
|
||
- `age_max` (optional): Максимальный возраст
|
||
- `season` (optional): Сезон
|
||
- `outcome` (optional): Исход (alive/deceased)
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"points": [
|
||
{
|
||
"lat": 53.9,
|
||
"lon": 27.56,
|
||
"intensity": 1.0,
|
||
"case_id": "uuid",
|
||
"distance_km": 2.3,
|
||
"outcome": "alive"
|
||
}
|
||
],
|
||
"total": 1
|
||
}
|
||
```
|
||
|
||
## Функции stats_service.py
|
||
|
||
### get_statistical_recommendation()
|
||
SQL выборка похожих случаев с фильтрами:
|
||
- Возраст ±2 года
|
||
- Сезон
|
||
- Terrain (тип местности)
|
||
- Минимум 5 случаев для выборки
|
||
|
||
Возвращает:
|
||
- `median_distance_km` - медианное расстояние находки
|
||
- `top_directions` - топ-3 направления с процентами
|
||
- `top_location_types` - топ-5 типов локаций
|
||
- `survival_rate` - процент выживаемости
|
||
- `sample_size` - размер выборки
|
||
- `filters_used` - использованные фильтры
|
||
|
||
### get_dashboard_stats()
|
||
Агрегаты для дашборда:
|
||
- Общее количество случаев (всего, активных, закрытых)
|
||
- Распределение по полу, возрасту, психотипу, диагнозам, сезонам
|
||
- Средняя дистанция находки
|
||
- Средняя длительность поиска
|
||
- Процент выживаемости
|
||
|
||
### get_heatmap_data()
|
||
Данные для тепловой карты с фильтрами:
|
||
- Возраст (min/max)
|
||
- Сезон
|
||
- Исход (alive/deceased)
|
||
|
||
## Тестирование
|
||
|
||
```bash
|
||
# 1. Получить агрегаты дашборда
|
||
curl http://localhost:8000/api/v1/stats/summary
|
||
|
||
# 2. Получить статистические рекомендации
|
||
curl -X POST http://localhost:8000/api/v1/stats/recommendation \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"age": 10, "season": "лето", "terrain_primary": "лес"}'
|
||
|
||
# 3. Получить данные для тепловой карты
|
||
curl "http://localhost:8000/api/v1/stats/heatmap?age_min=8&age_max=12"
|
||
```
|
||
|
||
## Протестировано (2026-05-05)
|
||
|
||
✅ GET /api/v1/stats/summary - работает
|
||
✅ POST /api/v1/stats/recommendation - работает
|
||
✅ GET /api/v1/stats/heatmap - работает
|
||
|
||
## Технические детали
|
||
|
||
- **Синхронная SQLAlchemy** (не async)
|
||
- **PostgreSQL ARRAY** - используется `any()` вместо `contains()`
|
||
- **Fallback механизм** - если выборка < 5 случаев, расширяются фильтры
|
||
- **Pydantic модели** - валидация входных/выходных данных
|
||
|
||
## Дата создания
|
||
2026-05-05
|