package file import ( "context" "encoding/binary" "fmt" "io" "sort" "time" "git.pyer.club/kingecg/gotidb/pkg/engine" ) // queryRaw 实现原始数据查询 func (e *FileEngine) queryRaw(ctx context.Context, query engine.Query) (engine.QueryResult, error) { result := &engine.TimeSeriesResult{ SeriesID: query.SeriesID, Points: make([]engine.DataPoint, 0), } // 如果指定了SeriesID,只查询特定序列 if query.SeriesID != "" { points, err := e.querySeriesPoints(query.SeriesID, query.StartTime, query.EndTime) if err != nil { return nil, err } result.Points = points return result, nil } // 否则查询所有匹配的序列 matchedSeries := e.findMatchingSeries(query) for _, seriesID := range matchedSeries { points, err := e.querySeriesPoints(seriesID, query.StartTime, query.EndTime) if err != nil { return nil, err } result.Points = append(result.Points, points...) } // 按时间戳排序 sort.Slice(result.Points, func(i, j int) bool { return result.Points[i].Timestamp < result.Points[j].Timestamp }) return result, nil } // queryLatest 实现最新数据查询 func (e *FileEngine) queryLatest(ctx context.Context, query engine.Query) (engine.QueryResult, error) { result := &engine.TimeSeriesResult{ SeriesID: query.SeriesID, Points: make([]engine.DataPoint, 0), } if query.SeriesID != "" { point, err := e.queryLatestPoint(query.SeriesID) if err != nil { return nil, err } if point != nil { result.Points = append(result.Points, *point) } return result, nil } matchedSeries := e.findMatchingSeries(query) for _, seriesID := range matchedSeries { point, err := e.queryLatestPoint(seriesID) if err != nil { return nil, err } if point != nil { result.Points = append(result.Points, *point) } } return result, nil } // queryAggregate 实现聚合查询 func (e *FileEngine) queryAggregate(ctx context.Context, query engine.Query) (engine.QueryResult, error) { result := &engine.AggregateResult{ SeriesID: query.SeriesID, Groups: make([]engine.AggregateGroup, 0), } // 创建时间窗口 windows := splitTimeRange(query.StartTime, query.EndTime, query.AggInterval) // 如果指定了SeriesID,只聚合特定序列 if query.SeriesID != "" { groups, err := e.aggregateSeriesInWindows(query.SeriesID, windows, query.Aggregation) if err != nil { return nil, err } result.Groups = groups return result, nil } // 否则聚合所有匹配的序列 matchedSeries := e.findMatchingSeries(query) for _, window := range windows { group := engine.AggregateGroup{ StartTime: window.start, EndTime: window.end, } var totalSum float64 var totalCount int for _, seriesID := range matchedSeries { points, err := e.querySeriesPoints(seriesID, window.start, window.end) if err != nil { return nil, err } windowSum, windowCount := aggregatePoints(points, query.Aggregation) totalSum += windowSum totalCount += windowCount } if totalCount > 0 { group.Value = calculateAggregateValue(totalSum, totalCount, query.Aggregation) group.Count = totalCount result.Groups = append(result.Groups, group) } } return result, nil } // 辅助方法 func (e *FileEngine) querySeriesPoints(seriesID string, startTime, endTime int64) ([]engine.DataPoint, error) { e.timeIndex.mu.RLock() windows := e.timeIndex.windows[seriesID] e.timeIndex.mu.RUnlock() var points []engine.DataPoint for _, window := range windows { if window.endTime < startTime || window.startTime > endTime { continue } segment, ok := e.segments[window.segmentID] if !ok { continue } segmentPoints, err := e.readSegmentPoints(segment, window.offset, startTime, endTime) if err != nil { return nil, err } points = append(points, segmentPoints...) } return points, nil } func (e *FileEngine) queryLatestPoint(seriesID string) (*engine.DataPoint, error) { e.timeIndex.mu.RLock() windows := e.timeIndex.windows[seriesID] e.timeIndex.mu.RUnlock() if len(windows) == 0 { return nil, nil } // 找到最新的时间窗口 var latestWindow timeWindow for _, window := range windows { if window.endTime > latestWindow.endTime { latestWindow = window } } segment, ok := e.segments[latestWindow.segmentID] if !ok { return nil, nil } points, err := e.readSegmentPoints(segment, latestWindow.offset, 0, time.Now().UnixNano()) if err != nil { return nil, err } if len(points) == 0 { return nil, nil } // 返回最新的点 latestPoint := points[len(points)-1] return &latestPoint, nil } func (e *FileEngine) readSegmentPoints(segment *Segment, offset int64, startTime, endTime int64) ([]engine.DataPoint, error) { segment.mu.RLock() defer segment.mu.RUnlock() var points []engine.DataPoint // 移动到指定偏移 if _, err := segment.file.Seek(offset, io.SeekStart); err != nil { return nil, err } // 读取数据点 for { var timestamp int64 var value float64 err := binary.Read(segment.file, binary.BigEndian, ×tamp) if err == io.EOF { break } if err != nil { return nil, err } err = binary.Read(segment.file, binary.BigEndian, &value) if err != nil { return nil, err } if timestamp >= startTime && timestamp <= endTime { points = append(points, engine.DataPoint{ Timestamp: timestamp, Value: value, }) } } return points, nil } func (e *FileEngine) findMatchingSeries(query engine.Query) []string { e.tagIndex.mu.RLock() defer e.tagIndex.mu.RUnlock() var matchedSeries []string seriesMap := make(map[string]bool) // 首先根据标签过滤器找到匹配的序列 for _, filter := range query.TagFilters { if values, ok := e.tagIndex.index[filter.Key]; ok { if series, ok := values[filter.Value]; ok { for _, seriesID := range series { seriesMap[seriesID] = true } } } } // 转换为切片 for seriesID := range seriesMap { matchedSeries = append(matchedSeries, seriesID) } return matchedSeries } func (e *FileEngine) aggregateSeriesInWindows(seriesID string, windows []timeWindow, aggType engine.AggregationType) ([]engine.AggregateGroup, error) { var groups []engine.AggregateGroup for _, window := range windows { points, err := e.querySeriesPoints(seriesID, window.start, window.end) if err != nil { return nil, err } if len(points) > 0 { sum, count := aggregatePoints(points, aggType) groups = append(groups, engine.AggregateGroup{ StartTime: window.start, EndTime: window.end, Value: calculateAggregateValue(sum, count, aggType), Count: count, }) } } return groups, nil } func aggregatePoints(points []engine.DataPoint, aggType engine.AggregationType) (float64, int) { if len(points) == 0 { return 0, 0 } var sum float64 for _, p := range points { sum += p.Value } return sum, len(points) } func calculateAggregateValue(sum float64, count int, aggType engine.AggregationType) float64 { if count == 0 { return 0 } switch aggType { case engine.AggSum: return sum case engine.AggAvg: return sum / float64(count) case engine.AggCount: return float64(count) default: return sum } } func splitTimeRange(start, end int64, interval time.Duration) []timeWindow { var windows []timeWindow intervalNanos := interval.Nanoseconds() for windowStart := start; windowStart < end; windowStart += intervalNanos { windowEnd := windowStart + intervalNanos if windowEnd > end { windowEnd = end } windows = append(windows, timeWindow{ start: windowStart, end: windowEnd, }) } return windows } // 错误处理辅助函数 func wrapError(op string, err error) error { if err == nil { return nil } return fmt.Errorf("%s: %v", op, err) }