This commit is contained in:
toom1996
2026-09-17 00:38:01 +08:00
parent 7dd3fda73c
commit 6c31b18e0f
10 changed files with 389 additions and 77 deletions

View File

@ -56,6 +56,16 @@ type IngestRepository interface {
// ScheduleRetry 失败时调用:attempts+1,未达上限则退避后重置 pending,达上限则置 failed。
// 用于临时失败(网络抖动 / 单图下载失败)的自动重试,区别于永久失败(payload 解析错等)直接 MarkFailed。
ScheduleRetry(ctx context.Context, id uint32, errMsg string) error
// ListImagePHashes 返回全部已晋升图片(runway + street)的 (id, phash, kind),
// 跳过 is_deleted 与 phash=0/NULL(存量未计算)。供入库时与新增图做全局汉明比对(近似去重)。
ListImagePHashes(ctx context.Context) ([]ImagePHash, error)
}
// ImagePHash 已晋升图片的感知哈希摘要,供入库时全局近似去重比对。
type ImagePHash struct {
ID uint32 // 图片数字主键
Phash uint64 // 感知哈希(SQL 已过滤 0/NULL)
Kind string // "runway" | "street"(决定 dup_of 的 hashid 类型)
}
type ingestRepository struct {
@ -366,6 +376,40 @@ func (r *ingestRepository) RetryJob(ctx context.Context, id uint32) error {
}).Error
}
// ListImagePHashes 返回全部已晋升图片(runway + street)的感知哈希摘要,供入库时全局近似去重。
// 跳过 is_deleted 与 phash=0/NULL(存量未计算)。结果合并 runway + street 两类,
// 用 Kind 标注类型,调用方据此把 dup_of 编码成对应 hashid 类型。
//
// 注:每次入库任务都会全量拉取一次(图片量当前为千级,可接受);若后续图片量到十万级,
// 可改为按 runway_id/snap_id 分批或加内存缓存 + 定时刷新,避免每 job 一次全表扫描。
func (r *ingestRepository) ListImagePHashes(ctx context.Context) ([]ImagePHash, error) {
type phRow struct {
ID uint32 `gorm:"column:id"`
Phash uint64 `gorm:"column:phash"`
}
out := make([]ImagePHash, 0, 64)
const whereActive = "is_deleted = 0 AND phash IS NOT NULL AND phash <> 0"
var rw []phRow
if err := r.db.WithContext(ctx).Model(&model.BrandRunwayImage{}).
Select("id, phash").Where(whereActive).Scan(&rw).Error; err != nil {
return nil, err
}
for _, x := range rw {
out = append(out, ImagePHash{ID: x.ID, Phash: x.Phash, Kind: "runway"})
}
var sn []phRow
if err := r.db.WithContext(ctx).Model(&model.StreetSnapImage{}).
Select("id, phash").Where(whereActive).Scan(&sn).Error; err != nil {
return nil, err
}
for _, x := range sn {
out = append(out, ImagePHash{ID: x.ID, Phash: x.Phash, Kind: "street"})
}
return out, nil
}
// isDuplicateKey 兜底:gorm 的 ErrDuplicatedKey 在不同驱动下的封装不一定一致,
// 直接命中 MySQL 1062 错误号更稳。
func isDuplicateKey(err error) bool {