go-common/app/job/main/up-rating/service/statistics.go
2019-04-22 18:49:16 +08:00

293 lines
8.0 KiB
Go

package service
import (
"bytes"
"context"
"fmt"
"strconv"
"time"
"go-common/app/job/main/up-rating/model"
"go-common/library/log"
xtime "go-common/library/time"
"golang.org/x/sync/errgroup"
)
const (
// TotalType total type
TotalType int = iota
// CreativeType creative type
CreativeType
// InfluenceType influence type
InfluenceType
// CreditType Credit type
CreditType
)
var (
_offset int64 = 10
_sumTotal int64
_creativeTotal int64
_influenceTotal int64
_creditTotal int64
)
func initSection(min, max, section int64, ctype int, tagID int64, date xtime.Time) *model.RatingStatis {
return &model.RatingStatis{
Section: section,
Tips: fmt.Sprintf("\"%d-%d\"", min, max),
TagID: tagID,
CDate: date,
CType: ctype,
}
}
func initSections(totalScore, tagID int64, ctype int, date xtime.Time) (statis []*model.RatingStatis) {
var (
idx int64
)
statis = make([]*model.RatingStatis, totalScore/_offset)
for idx*_offset < totalScore {
statis[idx] = initSection(idx*_offset, (idx+1)*_offset, idx, ctype, tagID, date)
idx++
}
return
}
// RunStatistics run up rating statistics
func (s *Service) RunStatistics(c context.Context, date time.Time) (err error) {
err = s.initTotalScore(c)
if err != nil {
log.Error("s.initTotalScore error(%v)", err)
return
}
err = s.delStatistics(c, date)
if err != nil {
log.Error("s.delStatistics error(%v)", err)
return
}
err = s.statistics(c, date)
if err != nil {
log.Error("s.scoreStatistics error(%v)", err)
}
return
}
func (s *Service) initTotalScore(c context.Context) (err error) {
params, err := s.getAllParamter(c)
if err != nil {
log.Error("s.getAllParamter error(%v)", err)
return
}
_sumTotal = params.WCSR + params.HR + params.WISR
_creativeTotal = params.WCSR
_influenceTotal = params.WISR
_creditTotal = params.HR
return
}
func (s *Service) delStatistics(c context.Context, date time.Time) (err error) {
err = s.delRatingCom(c, "up_rating_statistics", date)
if err != nil {
return
}
err = s.delRatingCom(c, "up_rating_top", date)
return
}
// delRatingCom del com
func (s *Service) delRatingCom(c context.Context, table string, date time.Time) (err error) {
for {
var rows int64
rows, err = s.dao.DelRatingCom(c, table, date, _limit)
if err != nil {
return
}
if rows == 0 {
break
}
}
return
}
func (s *Service) statistics(c context.Context, date time.Time) (err error) {
var (
readGroup errgroup.Group
sourceCh = make(chan []*model.Rating, _limit)
statisCh = make(chan []*model.Rating, _limit)
topCh = make(chan []*model.Rating, _limit)
sections map[int]map[int64][]*model.RatingStatis
topRating map[int]map[int64]*RatingHeap
)
baseInfo, err := s.BaseTotal(c, date)
if err != nil {
log.Error("s.BaseTotal error(%v)", err)
return
}
// get rating info
readGroup.Go(func() (err error) {
err = s.RatingInfos(c, date, sourceCh)
if err != nil {
log.Error("s.RatingInfos error(%v)", err)
}
return
})
// dispatch
readGroup.Go(func() (err error) {
defer func() {
close(topCh)
close(statisCh)
}()
for rating := range sourceCh {
statisCh <- rating
topCh <- rating
}
return
})
// top
readGroup.Go(func() (err error) {
topRating, err = s.ratingTop(c, date, topCh)
if err != nil {
log.Error("s.RatingTop error(%v)", err)
}
return
})
// statis
readGroup.Go(func() (err error) {
sections, err = s.scoreStatistics(c, date, statisCh, baseInfo)
if err != nil {
log.Error("s.scoreStatistics error(%v)", err)
}
return
})
if err = readGroup.Wait(); err != nil {
log.Error("run readGroup.Wait error(%v)", err)
return
}
// persistent
var writeGroup errgroup.Group
//up_rating_statistics
writeGroup.Go(func() (err error) {
err = s.insertSections(c, sections)
if err != nil {
log.Error("s.insertSections error(%v)", err)
}
return
})
// up_rating_top
writeGroup.Go(func() (err error) {
_, err = s.insertTopRating(c, date, topRating, baseInfo)
if err != nil {
log.Error("s.insertSections error(%v)", err)
}
return
})
if err = writeGroup.Wait(); err != nil {
log.Error("run writeGroup.Wait error(%v)", err)
}
return
}
func (s *Service) scoreStatistics(c context.Context, date time.Time, source chan []*model.Rating, baseInfo map[int64]*model.BaseInfo) (sections map[int]map[int64][]*model.RatingStatis, err error) {
sections = make(map[int]map[int64][]*model.RatingStatis) // map[ctype][tagID][]*model.RatingStatis
sections[TotalType] = make(map[int64][]*model.RatingStatis)
sections[CreativeType] = make(map[int64][]*model.RatingStatis)
sections[InfluenceType] = make(map[int64][]*model.RatingStatis)
sections[CreditType] = make(map[int64][]*model.RatingStatis)
for rating := range source {
for _, r := range rating {
statisScoreCtype(TotalType, r.CreativityScore+r.InfluenceScore+r.CreditScore, _sumTotal, sections, date, r, baseInfo[r.MID])
statisScoreCtype(CreativeType, r.CreativityScore, _creativeTotal, sections, date, r, baseInfo[r.MID])
statisScoreCtype(InfluenceType, r.InfluenceScore, _influenceTotal, sections, date, r, baseInfo[r.MID])
statisScoreCtype(CreditType, r.CreditScore, _creditTotal, sections, date, r, baseInfo[r.MID])
}
}
return
}
func statisScoreCtype(ctype int, score, totalScore int64, sections map[int]map[int64][]*model.RatingStatis, date time.Time, rate *model.Rating, base *model.BaseInfo) {
if _, ok := sections[ctype][rate.TagID]; !ok {
sections[ctype][rate.TagID] = initSections(totalScore, rate.TagID, ctype, xtime.Time(date.Unix()))
}
idx := score / _offset
if idx >= int64(len(sections[ctype][rate.TagID])) {
idx = int64(len(sections[ctype][rate.TagID]) - 1)
}
sections[ctype][rate.TagID][idx].Ups++
sections[ctype][rate.TagID][idx].TotalScore += rate.CreativityScore + rate.InfluenceScore + rate.CreditScore
sections[ctype][rate.TagID][idx].CreativityScore += rate.CreativityScore
sections[ctype][rate.TagID][idx].InfluenceScore += rate.InfluenceScore
sections[ctype][rate.TagID][idx].CreditScore += rate.CreditScore
if base != nil {
sections[ctype][rate.TagID][idx].Fans += base.TotalFans
sections[ctype][rate.TagID][idx].Avs += base.TotalAvs
sections[ctype][rate.TagID][idx].Coin += base.TotalCoin
sections[ctype][rate.TagID][idx].Play += base.TotalPlay
}
}
func (s *Service) insertSections(c context.Context, sections map[int]map[int64][]*model.RatingStatis) (err error) {
for ctype, tags := range sections {
for tagID, statis := range tags {
_, err = s.insertRatingStatis(c, ctype, tagID, statis)
if err != nil {
return
}
}
}
return
}
func (s *Service) insertRatingStatis(c context.Context, ctype int, tagID int64, statis []*model.RatingStatis) (rows int64, err error) {
return s.dao.InsertRatingStatis(c, assembleRatingStatis(c, ctype, tagID, statis))
}
func assembleRatingStatis(c context.Context, ctype int, tagID int64, statis []*model.RatingStatis) (vals string) {
var buf bytes.Buffer
for _, s := range statis {
buf.WriteString("(")
buf.WriteString(strconv.FormatInt(s.Ups, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.Section, 10))
buf.WriteByte(',')
buf.WriteString(s.Tips)
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.TotalScore, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.CreativityScore, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.InfluenceScore, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.CreditScore, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.Fans, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.Avs, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.Coin, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.Play, 10))
buf.WriteByte(',')
buf.WriteString(strconv.FormatInt(s.TagID, 10))
buf.WriteByte(',')
buf.WriteString(strconv.Itoa(s.CType))
buf.WriteByte(',')
buf.WriteString("'" + s.CDate.Time().Format(_layout) + "'")
buf.WriteString(")")
buf.WriteByte(',')
}
if buf.Len() > 0 {
buf.Truncate(buf.Len() - 1)
}
vals = buf.String()
buf.Reset()
return
}