数据汇总与统计:健康数据趋势分析实现
·
一、统计端点的统一架构
AI-HEALTH系统为五大健康模块设计了统一的统计端点,所有Summary服务遵循相同的设计规范,形成可扩展的统计体系。
RESTful API设计
所有统计控制器采用一致的API规范:
package com.aihealth.controller;
import com.aihealth.service.FoodRecordSummaryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.ComponentScan;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/food-record/summary")
@ComponentScan(basePackages = {"controller", "service"})
public class FoodRecordSummaryController {
private static final Logger logger = LoggerFactory.getLogger(FoodRecordSummaryController.class);
@Autowired
private FoodRecordSummaryService foodRecordSummaryService;
@GetMapping
public Map<String, Object> getFoodRecordSummary(
@RequestParam("username") String username,
@RequestParam("startDate") String startDate,
@RequestParam("endDate") String endDate) {
logger.info("Received request for food record summary: username={}, startDate={}, endDate={}", username, startDate, endDate);
try {
Map<String, Object> result = foodRecordSummaryService.getFoodRecordSummary(username, startDate, endDate);
logger.info("Successfully returned food record summary: {}", result);
return result;
} catch (Exception e) {
logger.error("Error processing food record summary request", e);
throw new RuntimeException("处理饮食记录总结时出错: " + e.getMessage(), e);
}
}
}
MoodRecordSummaryController采用完全相同的结构:
@RestController
@RequestMapping("/api/v1/mood/summary")
@ComponentScan(basePackages = {"controller", "service"})
public class MoodRecordSummaryController {
private static final Logger logger = LoggerFactory.getLogger(MoodRecordSummaryController.class);
@Autowired
private MoodRecordSummaryService moodRecordSummaryService;
@GetMapping
public Map<String, Object> getMoodRecordSummary(
@RequestParam("username") String username,
@RequestParam("startDate") String startDate,
@RequestParam("endDate") String endDate) {
logger.info("Received request for mood record summary: username={}, startDate={}, endDate={}", username, startDate, endDate);
try {
Map<String, Object> result = moodRecordSummaryService.getMoodRecordSummary(username, startDate, endDate);
logger.info("Successfully returned mood record summary: {}", result);
return result;
} catch (Exception e) {
logger.error("Error processing mood record summary request", e);
throw new RuntimeException("处理情绪记录总结时出错: " + e.getMessage(), e);
}
}
}
接口规范
| 属性 | 值 |
|---|---|
| 路由模式 | /api/v1/{module}/summary |
| 请求方法 | GET |
| 参数 | username, startDate, endDate |
| 返回格式 | Map<String, Object> |
二、时间序列数据的构建
趋势分析的核心在于将原始记录转化为按时间排序的数据序列。
日期分组与排序
所有SummaryServiceImpl遵循相同的分组模式:
package com.aihealth.service.impl;
import com.aihealth.entity.FoodRecord;
import com.aihealth.entity.FoodItem;
import com.aihealth.service.FoodRecordService;
import com.aihealth.service.FoodRecordSummaryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class FoodRecordSummaryServiceImpl implements FoodRecordSummaryService {
@Autowired
private FoodRecordService foodRecordService;
@Override
public Map<String, Object> getFoodRecordSummary(String username, String startDate, String endDate) {
// 获取日期范围内的所有饮食记录
List<FoodRecord> records = foodRecordService.getFoodRecordsByUsernameAndDateRange(username, startDate, endDate);
// 统计信息
int totalRecords = records != null ? records.size() : 0;
int totalCalories = 0;
List<Map<String, Object>> dailyRecords = new ArrayList<>();
if (records != null && !records.isEmpty()) {
// 按日期分组统计
Map<String, List<FoodRecord>> recordsByDate = new HashMap<>();
for (FoodRecord record : records) {
if (record == null) {
continue;
}
// 提取日期部分(YYYY-MM-DD)
if (record.getRecordTime() != null) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String date = record.getRecordTime().format(formatter);
if (!recordsByDate.containsKey(date)) {
recordsByDate.put(date, new ArrayList<>());
}
recordsByDate.get(date).add(record);
}
}
// 处理每天的记录 - 按日期排序
List<String> sortedDates = new ArrayList<>(recordsByDate.keySet());
sortedDates.sort(String::compareTo);
for (String date : sortedDates) {
List<FoodRecord> dayRecords = recordsByDate.get(date);
Map<String, Object> daySummary = new HashMap<>();
daySummary.put("date", date);
daySummary.put("recordCount", dayRecords.size());
List<Map<String, Object>> meals = new ArrayList<>();
int dayCalories = 0;
for (FoodRecord record : dayRecords) {
Map<String, Object> meal = new HashMap<>();
meal.put("mealType", record.getMealType() != null ? record.getMealType() : "未知");
meal.put("recordTime", record.getRecordTime() != null ? record.getRecordTime() : "");
// 提取食物项
List<Map<String, Object>> foodItems = new ArrayList<>();
if (record.getFoodItems() != null) {
for (FoodItem item : record.getFoodItems()) {
if (item == null) continue;
Map<String, Object> foodItem = new HashMap<>();
foodItem.put("name", item.getName() != null ? item.getName() : "未知");
foodItem.put("amount", item.getAmount() != null ? item.getAmount() : "");
foodItems.add(foodItem);
}
}
meal.put("foodItems", foodItems);
// 计算卡路里
int mealCalories = 0;
if (record.getCalories() != null && !record.getCalories().isEmpty()) {
try {
mealCalories = Integer.parseInt(record.getCalories());
} catch (NumberFormatException e) {
// 忽略无效的卡路里值
}
}
meal.put("calories", mealCalories);
meals.add(meal);
dayCalories += mealCalories;
totalCalories += mealCalories;
}
daySummary.put("meals", meals);
daySummary.put("totalCalories", dayCalories);
dailyRecords.add(daySummary);
}
}
// 构建返回结果
Map<String, Object> summary = new HashMap<>();
summary.put("totalRecords", totalRecords);
summary.put("totalCalories", totalCalories);
summary.put("dailyRecords", dailyRecords);
return summary;
}
}
sortedDates数组即为时间序列,按日期升序排列,每个元素对应一天的数据点。
三、趋势指标的计算
1. 饮食记录趋势 - 卡路里摄入变化
返回结果中dailyRecords数组按日期顺序排列,连成每日的卡路里摄入趋势线:
Map<String, Object> summary = new HashMap<>();
summary.put("totalRecords", totalRecords);
summary.put("totalCalories", totalCalories);
summary.put("dailyRecords", dailyRecords);
return summary;
2. 睡眠记录趋势 - 时长与质量变化
package com.aihealth.service.impl;
import com.aihealth.entity.SleepRecord;
import com.aihealth.service.SleepRecordService;
import com.aihealth.service.SleepRecordSummaryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SleepRecordSummaryServiceImpl implements SleepRecordSummaryService {
@Autowired
private SleepRecordService sleepRecordService;
@Override
public Map<String, Object> getSleepRecordSummary(String username, String startDate, String endDate) {
List<SleepRecord> records = sleepRecordService.getSleepRecordsByUsernameAndDateRange(username, startDate, endDate);
int totalRecords = records != null ? records.size() : 0;
double totalDuration = 0;
Map<String, Integer> qualityCountMap = new HashMap<>();
List<Map<String, Object>> dailyRecords = new ArrayList<>();
Map<String, List<SleepRecord>> recordsByDate = new HashMap<>();
if (records != null) {
for (SleepRecord record : records) {
if (record != null && record.getSleepTime() != null) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String date = record.getSleepTime().format(formatter);
if (!recordsByDate.containsKey(date)) {
recordsByDate.put(date, new ArrayList<>());
}
recordsByDate.get(date).add(record);
}
if (record != null && record.getSleepQuality() != null && !record.getSleepQuality().isEmpty()) {
String quality = record.getSleepQuality();
qualityCountMap.put(quality, qualityCountMap.getOrDefault(quality, 0) + 1);
}
}
}
List<String> sortedDates = new ArrayList<>(recordsByDate.keySet());
sortedDates.sort(String::compareTo);
for (String date : sortedDates) {
List<SleepRecord> dayRecords = recordsByDate.get(date);
Map<String, Object> daySummary = new HashMap<>();
daySummary.put("date", date);
daySummary.put("recordCount", dayRecords.size());
List<Map<String, Object>> sleeps = new ArrayList<>();
double dayDuration = 0;
Map<String, Integer> dayQualityCountMap = new HashMap<>();
for (SleepRecord record : dayRecords) {
Map<String, Object> sleep = new HashMap<>();
sleep.put("recordName", record.getRecordName());
sleep.put("sleepTime", record.getSleepTime());
sleep.put("wakeTime", record.getWakeTime());
sleep.put("duration", record.getDuration());
sleep.put("sleepQuality", record.getSleepQuality());
sleeps.add(sleep);
if (record.getDuration() != null && !record.getDuration().isEmpty()) {
try {
double duration = Double.parseDouble(record.getDuration());
dayDuration += duration;
totalDuration += duration;
} catch (NumberFormatException e) {
// 忽略无效的时长值
}
}
if (record.getSleepQuality() != null && !record.getSleepQuality().isEmpty()) {
String quality = record.getSleepQuality();
dayQualityCountMap.put(quality, dayQualityCountMap.getOrDefault(quality, 0) + 1);
}
}
daySummary.put("sleeps", sleeps);
daySummary.put("totalDuration", dayDuration);
daySummary.put("qualityCount", dayQualityCountMap);
dailyRecords.add(daySummary);
}
double avgDuration = totalRecords > 0 ? totalDuration / totalRecords : 0;
Map<String, Object> summary = new HashMap<>();
summary.put("totalRecords", totalRecords);
summary.put("totalDuration", totalDuration);
summary.put("avgDuration", avgDuration);
summary.put("qualityCount", qualityCountMap);
summary.put("dailyRecords", dailyRecords);
return summary;
}
}
四、趋势分析在各模块的应用
| 模块 | 时间序列字段 | 核心趋势指标 | 特有统计 |
|---|---|---|---|
| 饮食 | recordTime | dayCalories | 餐次分组、食物项提取 |
| 运动 | recordTime | dayCalories | 运动项目明细 |
| 睡眠 | sleepTime | avgDuration | qualityCount分布 |
| 体重 | recordDate | avgWeight | min/max体重 |
| 情绪 | recordTime | moodCount | 最常见情绪 |
五、设计总结
原始记录 → 日期分组 → sortedDates排序 → 每日聚合指标 → 时间序列趋势
↓
┌─────────────────┐
│ dailyRecords │
│ 按日期排列 │
│ 形成趋势线 │
└─────────────────┘
通过统一的Controller规范、一致的Service模式,AI-HEALTH实现了健康数据的高效统计与趋势分析。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)