/** * 修复标签覆盖率统计 * 更新所有标签的coverage和coverage_rate字段 */ const { getDb } = require('../db/init'); function updateTagStats(dbSuffix = 'onion') { const db = getDb(dbSuffix); try { // 获取总用户数 const totalUsersRow = db.prepare('SELECT COUNT(*) as n FROM users').get(); const totalUsers = totalUsersRow.n; if (totalUsers === 0) { console.error('❌ 没有用户数据'); return; } console.log(`\n🔄 更新标签覆盖率统计(总用户数: ${totalUsers})`); // 获取所有标签 const tags = db.prepare('SELECT id FROM tags').all(); let updated = 0; const stmt = db.prepare(` UPDATE tags SET coverage = ?, coverage_rate = ? WHERE id = ? `); for (const tag of tags) { // 计算该标签的覆盖用户数 const coverageRow = db.prepare(` SELECT COUNT(DISTINCT user_id) as cnt FROM user_tags WHERE tag_id = ? `).get(tag.id); const coverage = coverageRow.cnt || 0; const coverage_rate = totalUsers > 0 ? +(coverage / totalUsers * 100).toFixed(2) : 0; stmt.run(coverage, coverage_rate, tag.id); updated++; if (updated % 50 === 0) { console.log(` ✓ 已更新 ${updated} 个标签...`); } } console.log(`\n✅ 更新完成: ${updated} 个标签\n`); // 显示样本 console.log('📊 样本数据(前5个标签):'); const samples = db.prepare(` SELECT id, name, coverage, coverage_rate FROM tags LIMIT 5 `).all(); for (const sample of samples) { console.log(` • ${sample.name}: ${sample.coverage} users (${sample.coverage_rate}%)`); } // 显示统计 console.log('\n📊 整体统计:'); const stats = db.prepare(` SELECT MIN(coverage) as min_coverage, MAX(coverage) as max_coverage, ROUND(AVG(coverage), 2) as avg_coverage, COUNT(*) as total_tags FROM tags `).get(); console.log(` • 总标签数: ${stats.total_tags}`); console.log(` • 覆盖范围: ${stats.min_coverage} - ${stats.max_coverage} 用户`); console.log(` • 平均覆盖: ${stats.avg_coverage} 用户`); db.close(); } catch (e) { console.error('❌ 错误:', e.message); db.close(); process.exit(1); } } // 执行更新 updateTagStats();