Skip to content

Day 4:分析缓存——已经跑过的不重跑

今天做什么

每天跑一次全量文档分析?浪费。加缓存——文档内容没变的,直接用缓存结果。

代码

go
package main

import (
    "context"
    "crypto/md5"
    "fmt"
    "sync"
)

// ===== 带缓存的文档分析器 =====
type CachedAnalyzer struct {
    analyzer *DocAnalyzer
    cache    sync.Map // map[hash]AnalysisResult
}

func NewCachedAnalyzer(maxWorkers int) *CachedAnalyzer {
    return &CachedAnalyzer{
        analyzer: NewAnalyzer(maxWorkers),
    }
}

func (a *CachedAnalyzer) AnalyzeWithCache(ctx context.Context, 
    doc string) (AnalysisResult, bool, error) {

    // 计算文档指纹
    hash := fmt.Sprintf("%x", md5.Sum([]byte(doc)))

    // 命中缓存,直接返回
    if cached, ok := a.cache.Load(hash); ok {
        return cached.(AnalysisResult), true, nil
    }

    // 未命中,实际分析
    result, err := a.analyzer.chain.Analyze(ctx, doc)
    if err != nil {
        return AnalysisResult{}, false, err
    }

    // 存入缓存
    a.cache.Store(hash, result)
    return result, false, nil
}

// ===== 批量分析 + 缓存 =====
func (a *CachedAnalyzer) AnalyzeBatchCached(ctx context.Context, 
    docs []string) ([]AnalysisResult, int, error) {

    var results []AnalysisResult
    cacheHits := 0

    for _, doc := range docs {
        result, hit, err := a.AnalyzeWithCache(ctx, doc)
        if err != nil {
            return nil, 0, err
        }
        if hit {
            cacheHits++
        }
        results = append(results, result)
    }

    return results, cacheHits, nil
}

func main() {
    ctx := context.Background()
    analyzer := NewCachedAnalyzer(5)

    docs := []string{
        "财报Q1...不变的内容",
        "财报Q1...不变的内容",  // 和上面一样,命中缓存
        "财报Q2...新的内容",    // 新内容,重新分析
    }

    results, hits, _ := analyzer.AnalyzeBatchCached(ctx, docs)
    fmt.Printf("完成 %d 份,缓存命中 %d\n", len(results), hits)
}

运行

bash
go run main.go
# 第一次:3份全分析
# 第二次:如果文档没变,3次全部命中缓存

缓存策略总结

策略做法适用场景
MD5 指纹文档内容不变=缓存有效定期分析同一批文档
TTL 过期缓存N分钟后自动失效文档可能频繁更新
增量分析只分析新增/修改的文档海量文档库

Day 4 完成。缓存让重复分析几乎零成本。