README.md 4.91 KB

歌词查重系统

这是一个使用 PostgreSQL 作为数据存储和候选召回层的歌词查重项目。Python 侧只负责歌词规范化、候选打分和最终判定,不再构建或加载 .pkl 本地索引。

架构

PostgreSQL:
  lyrics               保存原始歌词、规范化文本、原文/翻译文本、exact_hash
  lyric_lines          保存规范化歌词行和 line_hash
  exact_hash 索引      精确重复召回
  pg_trgm 索引         可选的近似文本召回
  line_hash 索引       行级重合召回

Python:
  normalize_lyrics     歌词清洗、时间戳/平台噪声处理、繁简转换、翻译行拆分
  DuplicateChecker     只对 PostgreSQL 召回的候选打分和排序
  决策规则              输出 duplicate / review / new

核心原则:

数据库负责召回候选。
Python 负责最终判断。
不再使用 pickle、本地 MinHash 索引或 outputs/indexes/*.pkl 作为生产链路。

安装依赖

python -m pip install -r requirements.txt

初始化 PostgreSQL

创建数据库:

createdb lyric_dedup

初始化表结构和索引:

python scripts/init_postgres.py \
  --dsn postgresql:///lyric_dedup

会创建:

lyrics
lyric_lines
pg_trgm extension
exact_hash / primary_text_trgm / line_hash 索引

导入曲库

python scripts/import_library_postgres.py \
  --dsn postgresql:///lyric_dedup \
  --lyrics-dir data/library

导入脚本会:

1. 扫描 data/library 下的 .lrc / .txt。
2. 读取并规范化歌词。
3. 写入 lyrics 和 lyric_lines。
4. 默认对 exact_hash 完全一致的记录做 soft delete,只保留质量更高的一条。
5. 输出重复报告到 outputs/results/postgres_exact_duplicates.csv。

如果只导入、不做 exact 去重:

python scripts/import_library_postgres.py \
  --dsn postgresql:///lyric_dedup \
  --lyrics-dir data/library \
  --skip-dedup-exact

检查单个歌词文件

python -m lyric_dedup.cli check-file \
  --dsn postgresql:///lyric_dedup \
  --file data/incoming/new_song.lrc

常用参数:

--recall-limit             每个 PostgreSQL 召回层最多返回多少候选
--max-candidates           最终返回和排序多少候选
--enable-trgm              启用 pg_trgm 近似文本召回
--trgm-threshold           pg_trgm similarity 阈值
--statement-timeout-ms     PostgreSQL statement_timeout

返回字段:

decision         duplicate / review / new
duplicate        duplicate 或 review 时为 true,new 时为 false
confidence       当前判定置信度
reason           中文判定原因
candidate_count  参与最终排序的候选数

启动 API

export LYRIC_DEDUP_DSN=postgresql:///lyric_dedup
uvicorn lyric_dedup_server.app:app --host 0.0.0.0 --port 8000

接口:

POST /api/v1/check

请求示例:

{
  "url": "https://example.com/song.lrc",
  "title": "Song Title",
  "artist": "Artist"
}

服务会下载 URL 对应的 .lrc / .txt 文件,使用 PostgreSQL 召回候选并判定。若结果为 new,且请求带有 URL,服务会把这首新歌词写入 PostgreSQL。

生成评估集

常规生产口径:

python -m lyric_dedup.cli generate-eval-set \
  --library-dir data/library \
  --lyrics-dir data/generated_eval/incoming \
  --csv data/generated_eval/eval_5000.csv \
  --size 5000 \
  --positive-ratio 0.3

hard 业务边界口径:

python -m lyric_dedup.cli generate-eval-set \
  --profile hard \
  --library-dir data/library \
  --lyrics-dir data/generated_eval/hard_incoming \
  --csv data/generated_eval/eval_hard_5000.csv \
  --size 5000 \
  --positive-ratio 0.3

生成器只写:

评估 CSV
样本歌词文件
manifest.json

不会再生成 .index.pkl。评估时由 PostgreSQL 召回候选,并根据 CSV 里的 source_record_id 排除 holdout 样本自身。

使用 PostgreSQL 评估

严格自动拦截口径:只有 duplicate 算预测应去重。

python scripts/evaluate_postgres.py \
  --dsn postgresql:///lyric_dedup \
  --csv data/generated_eval/eval_hard_5000.csv \
  --base-dir data/generated_eval \
  --out outputs/results/postgres_eval_hard_5000.csv

可疑样本召回口径:duplicatereview 都算抓到。

python scripts/evaluate_postgres.py \
  --dsn postgresql:///lyric_dedup \
  --csv data/generated_eval/eval_hard_5000.csv \
  --base-dir data/generated_eval \
  --positive-decisions duplicate,review \
  --out outputs/results/postgres_eval_hard_5000_review_positive.csv

评估会生成:

outputs/results/*.csv
outputs/results/*.csv.summary.json

summary 重点看:

precision       自动拦截准确率,重点关注 false_positive
recall          应去重样本召回率,重点关注 false_negative
f1              precision 和 recall 的综合指标
duplicate/review/new  三类判定分布