# 本项目缓存一览

本文档梳理仓库内**与业务相关的各类缓存**：说明用途、键与过期策略，并汇总运维脚本。按「分布式（Redis）→ 进程内 → 磁盘/模型 → 第三方」组织。

---

## 一、Redis 集中式缓存（生产主路径）

所有下列缓存默认连接 **`infrastructure.redis`**（`config/config.yaml` 与 `REDIS_*` 环境变量），**数据库编号一般为 `db=0`**（脚本可通过参数覆盖）。`snapshot_db` 仅在配置中存在，供快照/运维场景选用，应用代码未按该字段切换业务缓存的 DB。

### 1. 文本 / 图像向量缓存（Embedding）

- **作用**：缓存 BGE/TEI 文本向量与 CN-CLIP 图像向量、CLIP 文本塔向量，避免重复推理。
- **实现**：`embeddings/redis_embedding_cache.py` 的 `RedisEmbeddingCache`；键构造见 `embeddings/cache_keys.py`。
- **Key 形态**（最终 Redis 键 = `前缀` + `可选 namespace` + `逻辑键`）：
  - **前缀**：`infrastructure.redis.embedding_cache_prefix`（默认 `embedding`，可用 `REDIS_EMBEDDING_CACHE_PREFIX` 覆盖）。
  - **命名空间**：`embeddings/server.py` 与客户端中分为：
    - 文本：`namespace=""` → `{prefix}:{embed:norm0|1:...}`
    - 图像：`namespace="image"` → `{prefix}:image:{embed:模型名:txt:norm0|1:...}`
    - CLIP 文本：`namespace="clip_text"` → `{prefix}:clip_text:{embed:模型名:img:norm0|1:...}`
  - 逻辑键段含 `embed:`、`norm0/1`、模型名（多模态）、过长文本/URL 时用 `h:sha256:...` 摘要（见 `cache_keys.py` 注释）。
- **值格式**：BF16 压缩后的字节（`embeddings/bf16.py`），非 JSON。
- **TTL**：`infrastructure.redis.cache_expire_days`（默认 **720 天**，`REDIS_CACHE_EXPIRE_DAYS`）。写入用 `SETEX`；**命中时滑动续期**（`EXPIRE` 刷新为同一时长）。
- **Redis 客户端**：`decode_responses=False`（二进制）。

**主要代码**：`embeddings/server.py`、`embeddings/text_encoder.py`、`embeddings/image_encoder.py`。

---

### 2. 翻译结果缓存（Translation）

- **作用**：按「翻译模型 + 目标语言 + 原文」缓存译文；支持**模型质量分层探测**（高 tier 模型写入的缓存可被同 tier 或更高 tier 的请求命中，见 `translation/settings.py` 中 `translation_cache_probe_models`）。
- **Key 形态**：`trans:{model}:{target_lang}:{text前4字符}{sha256全文}`（`translation/cache.py` 的 `build_key`）。
- **值格式**：UTF-8 译文字符串。
- **TTL**：`services.translation.cache.ttl_seconds`（默认 **62208000 秒 = 720 天**）。若 `sliding_expiration: true`，命中时刷新 TTL。
- **能力级开关**：各 `capabilities.*.use_cache` 为 `false` 时该后端不落 Redis。
- **Redis 客户端**：`decode_responses=True`。

**主要代码**：`translation/cache.py`、`translation/service.py`；翻译 HTTP 服务：`api/translator_app.py`（`get_translation_service()` 使用 `lru_cache` 单例，见下文进程内缓存）。

---

### 3. 商品内容理解 / Anchors 与语义分析缓存（Indexer）

- **作用**：缓存 LLM 对商品标题等拼出的 **prompt 输入** 所做的分析结果（anchors、语义属性等），避免重复调用大模型。键与 `analysis_kind`、`prompt` 契约版本、`target_lang` 及输入摘要相关。
- **Key 形态**：`{anchor_cache_prefix}:{analysis_kind}:{prompt_contract_hash[:12]}:{target_lang}:{prompt_input[:4]}{md5}`（`indexer/product_enrich.py` 中 `_make_analysis_cache_key`）。
- **前缀**：`infrastructure.redis.anchor_cache_prefix`（默认 `product_anchors`，`REDIS_ANCHOR_CACHE_PREFIX`）。
- **值格式**：JSON 字符串（规范化后的分析结果）。
- **TTL**：`anchor_cache_expire_days`（默认 **30 天**），以秒写入 `SETEX`（**非滑动**，与向量/翻译不同）。
- **读逻辑**：无 TTL 刷新；仅校验内容是否「有意义」再返回。

**主要代码**：`indexer/product_enrich.py`；与 HTTP 侧对齐说明见 `api/routes/indexer.py` 注释。

---

## 二、进程内缓存（非共享、随进程重启失效）

| 名称 | 用途 | 范围/生命周期 |
|------|------|----------------|
| **`get_app_config()`** | 解析并缓存全局 `AppConfig` | `config/loader.py`：`@lru_cache(maxsize=1)`；`reload_app_config()` 可 `cache_clear()` |
| **`TranslationService` 单例** | 翻译服务进程内复用后端与 Redis 客户端 | `api/translator_app.py`：`get_translation_service()` |
| **`_nllb_tokenizer_code_by_normalized_key`** | NLLB tokenizer 语言码映射 | `translation/languages.py`：`@lru_cache(maxsize=1)` |
| **`QueryTextAnalysisCache`** | 单次查询解析内复用分词、tokenizer 结果 | `query/tokenization.py`，随 `QueryParser` 一次 parse |
| **`_SelectionContext`（SKU 意图）** | 归一化文本、分词、匹配布尔等小字典 | `search/sku_intent_selector.py`，单次选择流程 |
| **`incremental_service` transformer 缓存** | 按 `tenant_id` 缓存文档转换器 | `indexer/incremental_service.py`，**无界**、多租户进程长期存活时需注意内存 |
| **NLLB batch 内 `token_count_cache`** | 同一 batch 内避免重复计 token | `translation/backends/local_ctranslate2.py` |
| **CLIP 分词器 `@lru_cache`**（第三方） | 简单 tokenizer 缓存 | `third-party/clip-as-service/.../simple_tokenizer.py` |

**说明**：`utils/cache.py` 中的 **`DictCache`**（文件 JSON：默认 `.cache/dict_cache.json`）已导出，但仓库内**无直接 `DictCache(` 调用**，视为可复用工具/预留，非当前主路径。

---

## 三、磁盘与模型相关「缓存」（非 Redis）

| 名称 | 用途 | 配置/位置 |
|------|------|-----------|
| **Hugging Face / 本地模型目录** | 重排器、翻译本地模型等权重下载与缓存 | `services.rerank.backends.*.cache_dir` 等，常见默认 **`./model_cache`**（`config/config.yaml`） |
| **vLLM `enable_prefix_caching`** | 重排服务内 **Prefix KV 缓存**（加速同前缀批推理） | `services.rerank.backends.qwen3_vllm*`、`reranker/backends/qwen3_vllm*.py` |
| **运行时目录** | 重排服务状态/引擎文件 | `services.rerank.instances.*.runtime_dir`（如 `./.runtime/reranker/...`） |

翻译能力里的 **`use_cache: true`**（如 NLLB、Marian）在多数后端指 **推理时的 KV cache（Transformer）**，与 Redis 译文缓存是不同层次；Redis 译文缓存仍由 `TranslationCache` 控制。

---

## 四、Elasticsearch 内部缓存

索引设置中的 `refresh_interval` 等影响近实时可见性，但**不属于应用层键值缓存**。若需调优 ES 查询缓存、节点堆等，见运维文档与集群配置，此处不展开。

---

## 五、运维与巡检脚本（Redis）

| 脚本 | 作用 |
|------|------|
| `scripts/redis/redis_cache_health_check.py` | 按 **embedding / translation / anchors** 三类前缀巡检：key 数量估算、TTL 采样、`IDLETIME` 等 |
| `scripts/redis/redis_cache_prefix_stats.py` | 按前缀统计 key 数量与 **MEMORY USAGE**（可多 DB） |
| `scripts/redis/redis_memory_heavy_keys.py` | 扫描占用内存最大的 key，辅助排查「统计与总内存不一致」 |
| `scripts/redis/monitor_eviction.py` | 实时监控 **eviction** 相关事件，用于容量与驱逐策略排查 |
| `scripts/redis/purge_caches.py` | 一键清空业务缓存：embedding（含 `:image:` / `:clip_text:`）、anchors、translation；**默认跳过 `trans:deepl*`**（可 dry-run 预览） |

使用前需加载项目配置（如 `source activate.sh`）以保证 `REDIS_CONFIG` 与生产一致。脚本注释中给出了 **`redis-cli` 手工统计**示例（按前缀 `wc -l`、`MEMORY STATS` 等）。

### 快速清空（排除 `trans:deepl*`）

```bash
source activate.sh

# 先预览会删多少 key（推荐）
python scripts/redis/purge_caches.py --dry-run

# 真正删除（默认 db=0）
python scripts/redis/purge_caches.py
```

---

## 六、总表（Redis 与各层缓存）

| 缓存名称 | 业务模块 | 存储 | Key 前缀 / 命名模式 | 过期时间 | 过期策略 | 值摘要 | 配置键 / 环境变量 |
|----------|----------|------|---------------------|----------|----------|--------|-------------------|
| 文本向量 | 检索 / 索引 / Embedding 服务 | Redis db≈0 | `{embedding_cache_prefix}:*`（逻辑键以 `embed:norm…` 开头） | `cache_expire_days`（默认 720 天） | 写入 TTL + 命中滑动续期 | BF16 字节向量 | `infrastructure.redis.*`；`REDIS_EMBEDDING_CACHE_PREFIX`、`REDIS_CACHE_EXPIRE_DAYS` |
| 图像向量（CLIP 图） | 图搜 / 多模态 | 同上 | `{embedding_cache_prefix}:image:*`（其中 `{embedding_cache_prefix}` 默认 `embedding`） | 同上 | 同上 | BF16 字节 | 同上 |
| CLIP 文本塔向量 | 图搜文本侧 | 同上 | `{embedding_cache_prefix}:clip_text:*`（其中 `{embedding_cache_prefix}` 默认 `embedding`） | 同上 | 同上 | BF16 字节 | 同上 |
| 翻译译文 | 查询翻译、翻译服务 | 同上 | `trans:{model}:{lang}:*` | `services.translation.cache.ttl_seconds`（默认 720 天） | 可配置滑动（`sliding_expiration`） | UTF-8 字符串 | `services.translation.cache.*`；各能力 `use_cache` |
| 商品分析 / Anchors | 索引富化、LLM 内容理解 | 同上 | `{anchor_cache_prefix}:{kind}:{hash}:{lang}:*` | `anchor_cache_expire_days`（默认 30 天） | 固定 TTL，不滑动 | JSON 字符串 | `anchor_cache_prefix`、`anchor_cache_expire_days`；`REDIS_ANCHOR_*` |
| 应用配置 | 全栈 | 进程内存 | N/A（单例） | 进程生命周期 | `reload_app_config` 清除 | `AppConfig` 对象 | `config/loader.py` |
| 翻译服务实例 | 翻译 API | 进程内存 | N/A | 进程生命周期 | 单例 | `TranslationService` | `api/translator_app.py` |
| 查询分词缓存 | 查询解析 | 单次请求内 | N/A | 单次 parse | — | 分词与中间结果 | `query/tokenization.py` |
| SKU 意图辅助字典 | 搜索排序辅助 | 单次请求内 | N/A | 单次选择 | — | 小 dict | `search/sku_intent_selector.py` |
| 增量索引 Transformer | 索引管道 | 进程内存 | `tenant_id` 字符串键 | 长期（无界） | 无自动淘汰 | Transformer 元组 | `indexer/incremental_service.py` |
| 重排 / 翻译模型权重 | 推理服务 | 本地磁盘 | 目录路径 | 无自动删除（人工清理） | — | 模型文件 | `cache_dir: ./model_cache` 等 |
| vLLM Prefix 缓存 | 重排（Qwen3 等） | GPU/引擎内 | 引擎内部 | 引擎管理 | — | KV Cache | `enable_prefix_caching` |
| 文件 Dict 缓存（可选） | 通用 | `.cache/dict_cache.json` | 分类 + 自定义 key | 持久直至删除 | — | JSON 可序列化值 | `utils/cache.py`（当前无调用方） |

---

## 七、维护建议（简要）

1. **容量**：三类 Redis 缓存（embedding / trans / anchors）可共用同一实例；大租户或图搜多时 **embedding** 与 **trans** 往往占主要内存，可用 `redis_cache_prefix_stats.py` 分前缀观察。
2. **键迁移**：变更 `embedding_cache_prefix`、CLIP `model_name` 或 prompt 契约会自然**隔离新键空间**；旧键依赖 TTL 或人工批量删除。
3. **一致性**：向量缓存对异常向量会 **delete key**（`RedisEmbeddingCache.get`）；anchors 依赖 `cache_version` 与契约 hash 防止错误复用。
4. **监控**：除脚本外，Embedding HTTP 服务健康检查会报告各 lane 的 **`cache_enabled`**（`embeddings/server.py`）。

---

*文档随代码扫描生成；若新增 Redis 用途，请同步更新本文件与 `scripts/redis/redis_cache_health_check.py` 中的 `_load_known_cache_types()`。*
