This commit is contained in:
toom1996
2026-08-26 19:40:16 +08:00
parent 30c9f21da4
commit a6724265ad
14 changed files with 400 additions and 101 deletions

View File

@ -0,0 +1,75 @@
// Command backfill_title_cn 把 brand_runway.title_cn 由已解析的结构化分类字段
// (year / collection_type / season)规则生成中文走秀标题。
//
// 设计:
// - title 字段本质就是「季节/品类描述」(Vogue 格式:Spring 2026 Ready-to-Wear、
// Resort 2026、Pre-Fall 2023、Fall 2023 Couture、Spring 2024 Menswear),
// 品牌名在 JOIN 出的 brand_name 里单独给,不混进 title。
// - collection_type / season 早已由历史迁移解析回填,因此 title_cn 可纯规则生成,
// 完全不依赖外部翻译服务,且结果稳定可重跑。
//
// 幂等:每次都按分类字段重新计算并整表覆盖,重跑无害。
// 不写任何业务逻辑,仅做一次性数据回填。
package main
import (
"fmt"
"log"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
const dsn = "root:root@tcp(127.0.0.1:3306)/db?charset=utf8mb4&parseTime=True&loc=Local"
// titleCnSQL 单条 UPDATE 用 CASE 把分类字段映射为中文标题。
// year 参与拼接(CONCAT),season 为 NULL 时 COALESCE 成 ''。
const titleCnSQL = `
UPDATE brand_runway
SET title_cn = CASE
WHEN collection_type = 'resort' THEN CONCAT(year, ' 度假系列')
WHEN collection_type = 'pre_fall' THEN CONCAT(year, ' 早秋系列')
WHEN collection_type = 'rtw' AND season = 'spring' THEN CONCAT(year, ' 春夏成衣')
WHEN collection_type = 'rtw' AND season = 'fall' THEN CONCAT(year, ' 秋冬成衣')
WHEN collection_type = 'rtw' THEN CONCAT(year, ' 成衣')
WHEN collection_type = 'menswear' AND season = 'spring' THEN CONCAT(year, ' 春夏男装')
WHEN collection_type = 'menswear' AND season = 'fall' THEN CONCAT(year, ' 秋冬男装')
WHEN collection_type = 'couture' AND season = 'spring' THEN CONCAT(year, ' 春夏高定')
WHEN collection_type = 'couture' AND season = 'fall' THEN CONCAT(year, ' 秋冬高定')
ELSE CONCAT(year, ' 系列')
END
WHERE is_deleted = 0`
func main() {
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("open:", err)
}
var before int64
db.Raw(`SELECT COUNT(*) FROM brand_runway WHERE is_deleted=0 AND title_cn <> ''`).Scan(&before)
fmt.Printf("before: title_cn 非空 = %d\n", before)
if r := db.Exec(titleCnSQL); r.Error != nil {
log.Fatalf("backfill title_cn failed: %v", r.Error)
} else {
fmt.Printf("updated rows = %d\n", r.RowsAffected)
}
var after int64
db.Raw(`SELECT COUNT(*) FROM brand_runway WHERE is_deleted=0 AND title_cn <> ''`).Scan(&after)
fmt.Printf("after: title_cn 非空 = %d\n", after)
// 抽样核对:原始 title -> 生成 title_cn
type row struct {
Title string
TitleCn string
}
var rows []row
db.Raw(`SELECT title, title_cn FROM brand_runway WHERE is_deleted=0 ORDER BY id LIMIT 12`).Scan(&rows)
fmt.Println("samples:")
for _, r := range rows {
fmt.Printf(" %-32q -> %q\n", r.Title, r.TitleCn)
}
fmt.Println("title_cn backfill done.")
}

View File

@ -0,0 +1,54 @@
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
const dsn = "root:root@tcp(127.0.0.1:3306)/db?charset=utf8mb4&parseTime=True&loc=Local"
func main() {
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
// 1) brand 3100 的走秀档案数(only_with_articles 子查询依赖这个)
var artCount int64
db.Raw(`SELECT COUNT(*) FROM brand_runway WHERE is_deleted=0 AND brand_id=3100`).Scan(&artCount)
fmt.Printf("brand 3100 走秀档案数 = %d\n", artCount)
// 2) 复现后端完整搜索:only_with_articles=1 + keyword=猿人头
kw := "%猿人头%"
type Row struct {
ID uint32
Name string
NameEn string
NameCn string
}
var rows []Row
db.Raw(`
SELECT id, name, name_en, name_cn FROM brand
WHERE is_deleted=0
AND id IN (SELECT DISTINCT brand_id FROM brand_runway WHERE is_deleted=0)
AND (name_en LIKE ? OR name_cn LIKE ?)`,
kw, kw).Scan(&rows)
fmt.Printf("\n[搜索 keyword=猿人头, only_with_articles=1] 命中 %d 条:\n", len(rows))
for _, r := range rows {
fmt.Printf(" id=%d | name=%q | name_en=%q | name_cn=%q\n", r.ID, r.Name, r.NameEn, r.NameCn)
}
// 3) 对比:only_with_articles=0(不过滤档案)时的命中
var rows2 []Row
db.Raw(`
SELECT id, name, name_en, name_cn FROM brand
WHERE is_deleted=0
AND (name_en LIKE ? OR name_cn LIKE ?)`,
kw, kw).Scan(&rows2)
fmt.Printf("\n[搜索 keyword=猿人头, only_with_articles=0] 命中 %d 条:\n", len(rows2))
for _, r := range rows2 {
fmt.Printf(" id=%d | name=%q | name_en=%q | name_cn=%q\n", r.ID, r.Name, r.NameEn, r.NameCn)
}
}

68
scripts/diag_hot/main.go Normal file
View File

@ -0,0 +1,68 @@
package main
// 诊断:复现 FeaturedIDs("images", 30) 的 SQL,验证热门品牌排名数据是否合理。
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
const dsn = "root:root@tcp(127.0.0.1:3306)/db?charset=utf8mb4&parseTime=True&loc=Local"
func main() {
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
// 1) 复现 FeaturedIDs:按图片总数 DESC 取前 30
type Row struct {
BrandID uint32 `gorm:"column:brand_id"`
Images int64 `gorm:"column:images"`
Shows int64 `gorm:"column:shows"`
}
var rows []Row
db.Raw(`
SELECT brand_id, COALESCE(SUM(image_count),0) AS images, COUNT(*) AS shows
FROM brand_runway
WHERE is_deleted = 0
GROUP BY brand_id
ORDER BY images DESC
LIMIT 30
`).Scan(&rows)
fmt.Println("== FeaturedIDs(images, 30) 原始排名 ==")
for i, r := range rows {
var name string
db.Raw(`SELECT name_en FROM brand WHERE id = ?`, r.BrandID).Scan(&name)
fmt.Printf("%2d. brand_id=%-6d images=%-6d shows=%-4d %s\n", i+1, r.BrandID, r.Images, r.Shows, name)
}
// 2) image_count 分布:有多少品牌有图、多少归零
var zeroBrands, hasImgBrands int64
var totalRows, zeroRows int64
db.Raw(`SELECT COUNT(*) FROM (SELECT brand_id, SUM(image_count) s FROM brand_runway WHERE is_deleted=0 GROUP BY brand_id) t WHERE s = 0`).Scan(&zeroBrands)
db.Raw(`SELECT COUNT(*) FROM (SELECT brand_id, SUM(image_count) s FROM brand_runway WHERE is_deleted=0 GROUP BY brand_id) t WHERE s > 0`).Scan(&hasImgBrands)
db.Raw(`SELECT COUNT(*) FROM brand_runway WHERE is_deleted=0`).Scan(&totalRows)
db.Raw(`SELECT COUNT(*) FROM brand_runway WHERE is_deleted=0 AND image_count=0`).Scan(&zeroRows)
fmt.Printf("\n== image_count 分布 ==\n有图品牌=%d 零图品牌=%d | 走秀总行=%d 其中 image_count=0 的行=%d\n", hasImgBrands, zeroBrands, totalRows, zeroRows)
// 3) 对比口径:按走秀数(shows) DESC 前 10
var byShows []Row
db.Raw(`
SELECT brand_id, COALESCE(SUM(image_count),0) AS images, COUNT(*) AS shows
FROM brand_runway
WHERE is_deleted = 0
GROUP BY brand_id
ORDER BY shows DESC
LIMIT 10
`).Scan(&byShows)
fmt.Println("\n== 若按 shows DESC 前 10 ==")
for i, r := range byShows {
var name string
db.Raw(`SELECT name_en FROM brand WHERE id = ?`, r.BrandID).Scan(&name)
fmt.Printf("%2d. brand_id=%-6d images=%-6d shows=%-4d %s\n", i+1, r.BrandID, r.Images, r.Shows, name)
}
}

View File

@ -47,3 +47,33 @@ UPDATE brand_runway SET
description_en = description,
title_cn = '',
description_cn = '';
-- ============================================================================
-- 第 5 步(依赖「分类字段回填迁移」之后执行):title_cn 规则生成
--
-- 前提:collection_type / season / year 已由历史迁移解析回填(rtw/menswear/
-- couture/resort/pre_fall × spring/fall/空)。title 本质是「季节/品类描述」,
-- 品牌名在 JOIN 的 brand_name 里单独给,因此 title_cn 可纯规则生成,
-- 完全不依赖外部翻译服务,结果稳定可重跑。
--
-- 映射:resort→「{year} 度假系列」、pre_fall→「{year} 早秋系列」、
-- rtw→「{year} {春夏|秋冬}成衣」、menswear→「{year} {春夏|秋冬}男装」、
-- couture→「{year} {春夏|秋冬}高定」。
--
-- 执行器:scripts/backfill_title_cn/main.go(幂等,整表覆盖重跑无害)。
-- 该步骤与上方 i18n 加列/回填相互独立,可单独重跑。
-- ============================================================================
UPDATE brand_runway
SET title_cn = CASE
WHEN collection_type = 'resort' THEN CONCAT(year, ' 度假系列')
WHEN collection_type = 'pre_fall' THEN CONCAT(year, ' 早秋系列')
WHEN collection_type = 'rtw' AND season = 'spring' THEN CONCAT(year, ' 春夏成衣')
WHEN collection_type = 'rtw' AND season = 'fall' THEN CONCAT(year, ' 秋冬成衣')
WHEN collection_type = 'rtw' THEN CONCAT(year, ' 成衣')
WHEN collection_type = 'menswear' AND season = 'spring' THEN CONCAT(year, ' 春夏男装')
WHEN collection_type = 'menswear' AND season = 'fall' THEN CONCAT(year, ' 秋冬男装')
WHEN collection_type = 'couture' AND season = 'spring' THEN CONCAT(year, ' 春夏高定')
WHEN collection_type = 'couture' AND season = 'fall' THEN CONCAT(year, ' 秋冬高定')
ELSE CONCAT(year, ' 系列')
END
WHERE is_deleted = 0;