Skip to content

Commit

Permalink
feat: 完成recommendservice (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lansongxx authored Feb 9, 2024
1 parent 8f2fc3f commit d6a34bd
Show file tree
Hide file tree
Showing 11 changed files with 688 additions and 23 deletions.
48 changes: 41 additions & 7 deletions biz/adaptor/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,47 @@ import (

type ContentServerImpl struct {
*config.Config
FileService service.IFileService
PostService service.IPostService
ZoneService service.IZoneService
UserService service.IUserService
ProductService service.IProductService
CouponService service.ICouponService
OrderService service.IOrderService
FileService service.IFileService
PostService service.IPostService
ZoneService service.IZoneService
UserService service.IUserService
ProductService service.IProductService
CouponService service.ICouponService
OrderService service.IOrderService
RecommendService service.IRecommendService
}

func (s *ContentServerImpl) CreateFeedBacks(ctx context.Context, req *content.CreateFeedBacksReq) (res *content.CreateFeedBacksResp, err error) {
return s.RecommendService.CreateFeedBacks(ctx, req)
}

func (s *ContentServerImpl) GetLatestRecommend(ctx context.Context, req *content.GetLatestRecommendReq) (res *content.GetLatestRecommendResp, err error) {
return s.RecommendService.GetLatestRecommend(ctx, req)
}

func (s *ContentServerImpl) CreateItems(ctx context.Context, req *content.CreateItemsReq) (res *content.CreateItemsResp, err error) {
return s.RecommendService.CreateItems(ctx, req)
}

func (s *ContentServerImpl) UpdateItem(ctx context.Context, req *content.UpdateItemReq) (res *content.UpdateItemResp, err error) {
return s.RecommendService.UpdateItem(ctx, req)
}

func (s *ContentServerImpl) DeleteItem(ctx context.Context, req *content.DeleteItemReq) (res *content.DeleteItemResp, err error) {
return s.RecommendService.DeleteItem(ctx, req)
}

func (s *ContentServerImpl) GetRecommendByUser(ctx context.Context, req *content.GetRecommendByUserReq) (res *content.GetRecommendByUserResp, err error) {
return s.RecommendService.GetRecommendByUser(ctx, req)
}

func (s *ContentServerImpl) GetRecommendByItem(ctx context.Context, req *content.GetRecommendByItemReq) (res *content.GetRecommendByItemResp, err error) {
return s.RecommendService.GetRecommendByItem(ctx, req)
}

func (s *ContentServerImpl) GetPopularRecommend(ctx context.Context, req *content.GetPopularRecommendReq) (res *content.GetPopularRecommendResp, err error) {
return s.RecommendService.GetPopularRecommend(ctx, req)

}

func (s *ContentServerImpl) CompletelyRemoveFile(ctx context.Context, req *content.CompletelyRemoveFileReq) (res *content.CompletelyRemoveFileResp, err error) {
Expand Down
235 changes: 235 additions & 0 deletions biz/application/service/recommend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
package service

import (
"context"
"fmt"
"github.com/CloudStriver/cloudmind-content/biz/infrastructure/consts"
"github.com/CloudStriver/cloudmind-content/biz/infrastructure/convertor"
"github.com/CloudStriver/cloudmind-content/biz/infrastructure/gorse"
gencontent "github.com/CloudStriver/service-idl-gen-go/kitex_gen/cloudmind/content"
"github.com/google/wire"
"github.com/samber/lo"
"github.com/zeromicro/go-zero/core/stores/redis"
"strconv"
)

type IRecommendService interface {
CreateItems(ctx context.Context, req *gencontent.CreateItemsReq) (resp *gencontent.CreateItemsResp, err error)
UpdateItem(ctx context.Context, req *gencontent.UpdateItemReq) (resp *gencontent.UpdateItemResp, err error)
DeleteItem(ctx context.Context, req *gencontent.DeleteItemReq) (resp *gencontent.DeleteItemResp, err error)
GetPopularRecommend(ctx context.Context, req *gencontent.GetPopularRecommendReq) (resp *gencontent.GetPopularRecommendResp, err error)
GetRecommendByItem(ctx context.Context, req *gencontent.GetRecommendByItemReq) (resp *gencontent.GetRecommendByItemResp, err error)
GetRecommendByUser(ctx context.Context, req *gencontent.GetRecommendByUserReq) (resp *gencontent.GetRecommendByUserResp, err error)
GetLatestRecommend(ctx context.Context, req *gencontent.GetLatestRecommendReq) (resp *gencontent.GetLatestRecommendResp, err error)
CreateFeedBacks(ctx context.Context, req *gencontent.CreateFeedBacksReq) (resp *gencontent.CreateFeedBacksResp, err error)
}

type RecommendService struct {
Redis *redis.Redis
Gorse *gorse.GorseClient
}

func (s *RecommendService) CreateFeedBacks(ctx context.Context, req *gencontent.CreateFeedBacksReq) (resp *gencontent.CreateFeedBacksResp, err error) {
feedbacks := lo.Map[*gencontent.FeedBack, gorse.Feedback](req.FeedBacks, func(feedback *gencontent.FeedBack, index int) gorse.Feedback {
return convertor.FeedBackToGorseFeedBack(feedback)
})
if _, err = s.Gorse.InsertFeedback(ctx, feedbacks); err != nil {
return resp, err
}
return resp, nil
}

func (s *RecommendService) GetLatestRecommend(ctx context.Context, req *gencontent.GetLatestRecommendReq) (resp *gencontent.GetLatestRecommendResp, err error) {
resp = new(gencontent.GetLatestRecommendResp)
if req.Limit == nil {
req.Limit = lo.ToPtr(int64(consts.DefaultLimit))
}

var (
offset int
val string
items []gorse.Score
)
if val, _ = s.Redis.GetCtx(ctx, fmt.Sprintf("cache:latest:recommend:%s", req.UserId)); val == "" {
offset = 0
} else {
if offset, err = strconv.Atoi(val); err != nil {
offset = 0
}
}

if req.Category != nil {
if items, err = s.Gorse.GetItemLatestWithCategory(ctx, req.UserId, req.GetCategory(), int(req.GetLimit()), offset); err != nil {
return resp, err
}
} else {
if items, err = s.Gorse.GetItemLatest(ctx, req.UserId, int(req.GetLimit()), offset); err != nil {
return resp, err
}
}
if len(resp.ItemIds) < int(req.GetLimit()) {
offset = 0
} else {
offset += int(req.GetLimit())
}

_ = s.Redis.SetexCtx(ctx, fmt.Sprintf("cache:latest:recommend:%s", req.UserId), strconv.Itoa(offset), 3600)
resp.ItemIds = lo.Map[gorse.Score, string](items, func(score gorse.Score, _ int) string {
return score.Id
})
return resp, nil
}

func (s *RecommendService) CreateItems(ctx context.Context, req *gencontent.CreateItemsReq) (resp *gencontent.CreateItemsResp, err error) {
items := lo.Map[*gencontent.Item, gorse.Item](req.Items, func(item *gencontent.Item, index int) gorse.Item {
return convertor.ItemToGorseItem(item)
})
if _, err = s.Gorse.InsertItems(ctx, items); err != nil {
return resp, err
}
return resp, nil
}

func (s *RecommendService) UpdateItem(ctx context.Context, req *gencontent.UpdateItemReq) (resp *gencontent.UpdateItemResp, err error) {
if _, err = s.Gorse.UpdateItem(ctx, req.ItemId, &gorse.ItemPatch{
IsHidden: req.IsHidden,
Categories: req.Categories,
Labels: req.Labels,
Comment: req.Comment,
}); err != nil {
return resp, err
}
return resp, nil
}

func (s *RecommendService) DeleteItem(ctx context.Context, req *gencontent.DeleteItemReq) (resp *gencontent.DeleteItemResp, err error) {
if _, err = s.Gorse.DeleteItem(ctx, req.ItemId); err != nil {
return resp, err
}
return resp, nil
}

func (s *RecommendService) GetPopularRecommend(ctx context.Context, req *gencontent.GetPopularRecommendReq) (resp *gencontent.GetPopularRecommendResp, err error) {
resp = new(gencontent.GetPopularRecommendResp)
if req.Limit == nil {
req.Limit = lo.ToPtr(int64(consts.DefaultLimit))
}

var (
offset int
items []gorse.Score
val string
)
if val, _ = s.Redis.GetCtx(ctx, fmt.Sprintf("cache:popular:recommend:%s", req.UserId)); val == "" {
offset = 0
} else {
if offset, err = strconv.Atoi(val); err != nil {
offset = 0
}
}

if req.Category != nil {
if items, err = s.Gorse.GetItemPopularWithCategory(ctx, req.UserId, req.GetCategory(), int(req.GetLimit()), offset); err != nil {
return resp, err
}
} else {
if items, err = s.Gorse.GetItemPopular(ctx, req.UserId, int(req.GetLimit()), offset); err != nil {
return resp, err
}
}
if len(items) < int(req.GetLimit()) {
offset = 0
} else {
offset += int(req.GetLimit())
}

_ = s.Redis.SetexCtx(ctx, fmt.Sprintf("cache:popular:recommend:%s", req.UserId), strconv.Itoa(offset), 3600)

resp.ItemIds = lo.Map[gorse.Score, string](items, func(score gorse.Score, _ int) string {
return score.Id
})
return resp, nil
}

func (s *RecommendService) GetRecommendByItem(ctx context.Context, req *gencontent.GetRecommendByItemReq) (resp *gencontent.GetRecommendByItemResp, err error) {
resp = new(gencontent.GetRecommendByItemResp)
if req.Limit == nil {
req.Limit = lo.ToPtr(int64(consts.DefaultLimit))
}

var (
offset int
val string
items []gorse.Score
)
if val, _ = s.Redis.GetCtx(ctx, fmt.Sprintf("cache:item:recommend:%s", req.ItemId)); val == "" {
offset = 0
} else {
if offset, err = strconv.Atoi(val); err != nil {
offset = 0
}
}

if req.Category != nil {
if items, err = s.Gorse.GetItemNeighborsWithCategory(ctx, req.ItemId, req.GetCategory(), int(req.GetLimit()), offset); err != nil {
return resp, err
}
} else {
if items, err = s.Gorse.GetItemNeighbors(ctx, req.ItemId, int(req.GetLimit()), offset); err != nil {
return resp, err
}
}
if len(resp.ItemIds) < int(req.GetLimit()) {
offset = 0
} else {
offset += int(req.GetLimit())
}

_ = s.Redis.SetexCtx(ctx, fmt.Sprintf("cache:item:recommend:%s", req.ItemId), strconv.Itoa(offset), 3600)
resp.ItemIds = lo.Map[gorse.Score, string](items, func(score gorse.Score, _ int) string {
return score.Id
})
return resp, nil
}

func (s *RecommendService) GetRecommendByUser(ctx context.Context, req *gencontent.GetRecommendByUserReq) (resp *gencontent.GetRecommendByUserResp, err error) {
resp = new(gencontent.GetRecommendByUserResp)
if req.Limit == nil {
req.Limit = lo.ToPtr(int64(consts.DefaultLimit))
}

var (
offset int
val string
)
if val, _ = s.Redis.GetCtx(ctx, fmt.Sprintf("cache:user:recommend:%s", req.UserId)); val == "" {
offset = 0
} else {
if offset, err = strconv.Atoi(val); err != nil {
offset = 0
}
}

if req.Category != nil {
if resp.ItemIds, err = s.Gorse.GetItemRecommendWithCategory(ctx, req.UserId, req.GetCategory(), "read", "60m", int(req.GetLimit()), offset); err != nil {
return resp, err
}
} else {
if resp.ItemIds, err = s.Gorse.GetItemRecommend(ctx, req.UserId, []string{}, "read", "60m", int(req.GetLimit()), offset); err != nil {
return resp, err
}
}
if len(resp.ItemIds) < int(req.GetLimit()) {
offset = 0
} else {
offset += int(req.GetLimit())
}

_ = s.Redis.SetexCtx(ctx, fmt.Sprintf("cache:user:recommend:%s", req.UserId), strconv.Itoa(offset), 3600)
return resp, nil
}

var RecommendSet = wire.NewSet(
wire.Struct(new(RecommendService), "*"),
wire.Bind(new(IRecommendService), new(*RecommendService)),
)
4 changes: 4 additions & 0 deletions biz/infrastructure/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ type Config struct {
CacheConf cache.CacheConf
Elasticsearch ElasticsearchConf
Redis *redis.RedisConf
GorseConf struct {
Url string
ApiKey string
}
}

func NewConfig() (*Config, error) {
Expand Down
7 changes: 4 additions & 3 deletions biz/infrastructure/consts/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ const (
)

var (
NotDel int64 = 1
SoftDel int64 = 2
HardDel int64 = 3
NotDel int64 = 1
SoftDel int64 = 2
HardDel int64 = 3
DefaultLimit = 10
)
21 changes: 21 additions & 0 deletions biz/infrastructure/convertor/convertor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package convertor

import (
"github.com/CloudStriver/cloudmind-content/biz/infrastructure/consts"
"github.com/CloudStriver/cloudmind-content/biz/infrastructure/gorse"
couponmapper "github.com/CloudStriver/cloudmind-content/biz/infrastructure/mapper/coupon"
"github.com/CloudStriver/cloudmind-content/biz/infrastructure/mapper/file"
ordermapper "github.com/CloudStriver/cloudmind-content/biz/infrastructure/mapper/order"
Expand Down Expand Up @@ -620,3 +621,23 @@ func ConvertUserMultiFieldsSearchQuery(in *gencontent.SearchOptions_MultiFieldsK
}
return q
}

func ItemToGorseItem(in *gencontent.Item) gorse.Item {
return gorse.Item{
ItemId: in.ItemId,
IsHidden: in.IsHidden,
Labels: in.Labels,
Categories: in.Categories,
Timestamp: in.Timestamp,
Comment: in.Comment,
}
}

func FeedBackToGorseFeedBack(in *gencontent.FeedBack) gorse.Feedback {
return gorse.Feedback{
FeedbackType: in.FeedbackType,
UserId: in.UserId,
ItemId: in.ItemId,
Timestamp: in.Timestamp,
}
}
Loading

0 comments on commit d6a34bd

Please sign in to comment.