3. 数据源结构解析:Funcotator 的目录层级与必需文件
很多人第一次接触 Funcotator 时,容易被它的数据源目录结构搞晕。我最早用的时候,就干过把不同版本的数据库直接扔进一个目录里的事,结果跑出来的注释结果乱七八糟。后来花了好几天排查,才发现是目录结构没对上。
说白了,数据源就是 Funcotator 的字典库。它按特定规则组织好,工具才能高效地查字典。这一节,我们把这个结构拆开来看清楚。
3.1 数据源文件夹的核心逻辑
Funcotator 要求所有数据源放在一个根目录下,这个目录就是 dataSourcesFolder(也有地方叫 data-sources-path)。你执行命令时,通过 --data-sources-path 参数指定这个根目录。
核心原则: 根目录内,一级子目录的名字必须与数据源版本名完全一致。比如 gnomAD_v2.1、clinvar_20210310。
为什么会这样?因为 Funcotator 在运行时会直接去 dataSourcesFolder/版本名/ 下找必需文件。名字对不上,它就报错。
3.2 目录层级:一个典型示例
我用自己的一个项目目录来举例,你看着会更直观:
funcotator_data/ # 这是 dataSourcesFolder 根目录
├── gnomAD_v2.1_exome/ # 版本目录:外显子群体频率
│ ├── gnomAD_v2.1_exome.vcf
│ ├── gnomAD_v2.1_exome.vcf.idx
│ ├── info_fields.txt
│ └── info_field_types.txt
├── clinvar_20210310/ # 版本目录:临床意义数据库
│ ├── clinvar_20210310.vcf
│ ├── clinvar_20210310.vcf.idx
│ ├── info_fields.txt
│ └── info_field_types.txt
├── dbsnp_b151/ # 版本目录:常见变异数据库
│ ├── dbsnp_b151.vcf
│ ├── dbsnp_b151.vcf.idx
│ ├── info_fields.txt
│ └── info_field_types.txt
└── empty/ # 不包含必需文件,Funcotator 会直接跳过
嗯,这里要注意:每个版本目录下只能有一个 VCF 文件。如果有多个,Funcotator 会报错,因为它不知道用哪个。
3.3 必需文件清单与作用
每个版本目录里,必须包含以下四个文件(缺一不可):
| 文件名 | 类型 | 作用 |
|---|---|---|
数据源名.vcf |
VCF / 压缩 VCF | 包含所有注释记录的变异位点信息 |
数据源名.vcf.idx |
索引文件 | Tabix 索引,用于快速定位特定区域的记录 |
info_fields.txt |
文本 | 定义 VCF INFO 字段的 ID、类型、数量、描述 |
info_field_types.txt |
文本 | 指定每个 INFO 字段的 GATK 类型(如 String, Integer, Float) |
避坑指南: 我曾经只用 bgzip 压缩了 VCF,忘了生成 .tbi 或 .idx 索引。执行注释时,Funcotator 直接卡住,日志里只写了一句 No index file found。后来我学乖了,每次生成完索引后,都会用 ls -lh 确认索引文件大小不为 0。
3.4 info_fields.txt 与 info_field_types.txt 的格式
这两个文件的格式很关键,但它们经常被忽视。我给你们拆开看:
info_fields.txt 的格式,每行对应 VCF 中一个 INFO 字段:
##INFO=
##INFO=
##INFO=
info_field_types.txt 更简单,每行是 字段名\t类型:
AF Float
AN Integer
AC Integer
小技巧: 如果 VCF 里 INFO 字段很多,你不想手动写,可以用 bcftools head 或者 grep ^##INFO 从 VCF 头部提取出来,再稍作格式化。这比手敲快得多,也不容易写错。
3.5 数据源命名约定
虽然 Funcotator 没有强制命名规则,但社区和一些 best practice 建议遵循以下模式:
- 数据库名_版本号(如
clinvar_20210310) - 数据库名_版本号_数据集(如
gnomAD_v2.1_genome或gnomAD_v2.1_exome) - 数据库名_版本号_日期(如
dbsnp_b151_20210310)
我个人习惯使用 数据库名_版本号 加下划线的格式。这样在写脚本批量处理时,用 ls -d 配合正则就能直接取到所有版本目录。
3.6 实战验证:一个完整的目录检验流程
为了确保你的数据源目录结构没问题,我建议每次添加新数据源后,都执行一次下面这个验证步骤:
# 1. 检查所有版本目录是否包含必需文件
for dir in /path/to/funcotator_data/*/; do
version=$(basename "$dir")
# 尝试找到 VCF 文件(不区分 .vcf 还是 .vcf.gz)
vcf_file=$(ls "$dir"*.vcf* 2>/dev/null | head -n 1)
if [[ -z "$vcf_file" ]]; then
echo "ERROR: $version 缺少 VCF 文件"
continue
fi
idx_file=$(ls "$dir"*.idx 2>/dev/null | head -n 1)
if [[ -z "$idx_file" ]]; then
echo "ERROR: $version 缺少索引文件"
fi
if [[ ! -f "$dir"info_fields.txt ]]; then
echo "ERROR: $version 缺少 info_fields.txt"
fi
if [[ ! -f "$dir"info_field_types.txt ]]; then
echo "ERROR: $version 缺少 info_field_types.txt"
fi
done
这个脚本我放在自己的工具库里,每次更新数据库都会跑一次。它帮我省下了不少手动检查的时间。
3.7 知识体系结构图
下面这张图把数据源目录的核心结构、必需文件、以及它们之间的关系画清楚了。你把它当作一个速查图谱,回过头来看时思路会清晰很多:
3.8 常见问题与解决方法
整理几个我经常被问到的问题,你提前看一下,后面真遇到了就不慌了:
- VCF 文件用了
.gz压缩,索引文件是.vcf.gz.tbi,可以吗? —— 可以。.vcf.gz+.tbi是标准组合。Funcotator 内部调用 Tabix 时会自动识别。 - info_fields.txt 和 info_field_types.txt 必须跟 VCF 文件中实际使用的字段完全一致吗? —— 严格来说,只需要包含你打算在注释中使用的字段。但我建议保持一致,否则会出现“字段定义了但没用”或“字段引用了但没定义”的情况。
- 空目录或缺少必需文件的目录, Funcotator 会怎么处理? —— 它会跳过该目录,并在日志里输出
WARN级别的信息。不会中断整个注释流程,但你的结果里会缺少该数据源的注释。
一句话总结: 数据源目录 = 根目录 + 版本子目录 + 四个必需文件。版本子目录名字不能错,四大金刚一个不能少。