package model import ( "math" "trading-go/common" ) type vector struct { v []Pair } type recommendList struct { list map[uint]float64 } type Pair struct { CategoryId uint `db:"category_id"` Score int `db:"score"` } func Recommend(uid, goodsId uint) error { db := common.DB var cIds []int64 sqlStr := "SELECT category_id FROM category_of_goods WHERE goods_id = ?" err := db.Select(&cIds, sqlStr, goodsId) if err != nil { return err } sqlStr = "INSERT INTO feedback(uid, category_id, score) VALUE (?, ?, 1) ON DUPLICATE KEY update score=score + 1" for _, id := range cIds { _, err := db.Exec(sqlStr, uid, id) if err != nil { return err } } return nil } func NewRecommend(uid uint, categoryId []uint) error { db := common.DB sqlStr := "INSERT INTO feedback(uid, category_id, score) VALUE (?, ?, 1) ON DUPLICATE KEY update score=score + 1" for _, id := range categoryId { _, err := db.Exec(sqlStr, uid, id) if err != nil { return err } } return nil } func GetRecommend(uid uint, cnt int) (goods []uint, err error) { var rList recommendList rList.list = make(map[uint]float64) userV, err := getUserVector(uid) if err != nil { return nil, err } mx := userV.max() goodsIds, err := getGoodsIds() if err != nil { return nil, err } for _, id := range goodsIds { itemV, err := getItemVector(id, uint(mx)) if err != nil { return nil, err } rList.list[id] = userV.similarity(itemV) } goods = rList.Sort(cnt) return } func getUserVector(uid uint) (vector, error) { var p []Pair db := common.DB sqlStr := "SELECT category_id, score FROM feedback WHERE uid = ? ORDER BY category_id DESC" err := db.Select(&p, sqlStr, uid) if err != nil { return vector{}, err } return vector{v: p}, err } func getItemVector(id uint, maxId uint) (vector, error) { var p []Pair var cIds []uint db := common.DB sqlStr := "SELECT category_id FROM category_of_goods WHERE goods_id = ? AND category_id <= ?" err := db.Select(&cIds, sqlStr, id, maxId) if err != nil { return vector{}, err } for i := 0; i < len(cIds); i++ { p = append(p, Pair{ CategoryId: cIds[i], Score: 1, }) } return vector{p}, err } func (v vector) similarity(other vector) float64 { user, item := make(map[uint]int), make(map[uint]int) for _, pair := range v.v { user[pair.CategoryId] = pair.Score } for _, pair := range other.v { item[pair.CategoryId] = 1 } a, b, cnt := 0, 0, 0 for ke, va := range user { if _, ok := item[ke]; ok { cnt++ a += va } b += va * va } if cnt == 0 { return 0 } return float64(a) / (math.Sqrt(float64(b)) * math.Sqrt(float64(cnt))) } func (v vector) max() uint { return v.v[0].CategoryId } func (r recommendList) Sort(n int) []uint { ids := make([]uint, 0, len(r.list)) scores := make([]float64, 0, len(r.list)) result := make([]uint, 0, n) for id, score := range r.list { ids = append(ids, id) scores = append(scores, score) } for i := 0; i < n; i++ { mxid := uint(i) for j := 0; j < len(ids); j++ { if scores[j] > scores[mxid] { mxid = uint(j) } } scores[mxid] = -1 result = append(result, ids[mxid]) } return result }