123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- 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
- }
|