352 lines
13 KiB
Go
352 lines
13 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"math"
|
|
"time"
|
|
|
|
"go-common/app/job/main/figure-timer/conf"
|
|
"go-common/app/job/main/figure-timer/model"
|
|
"go-common/library/log"
|
|
)
|
|
|
|
const (
|
|
bizTypePosLawful = iota
|
|
bizTypeNegLawful
|
|
// bizTypePosWide
|
|
// bizTypeNegWide
|
|
bizTypePosFriendly
|
|
bizTypeNegFriendly
|
|
bizTypePosCreativity
|
|
// bizTypeNegCreativity
|
|
bizTypePosBounty
|
|
// bizTypeNegBounty
|
|
)
|
|
|
|
// HandleFigure handle all figure score for a mid
|
|
func (s *Service) HandleFigure(c context.Context, mid int64, weekVer int64) (err error) {
|
|
var (
|
|
figure = &model.Figure{}
|
|
userInfo *model.UserInfo
|
|
actionCounter *model.ActionCounter
|
|
records []*model.FigureRecord
|
|
newRecord *model.FigureRecord
|
|
weekVerRecordsFrom = time.Unix(weekVer, 0).AddDate(0, 0, -7*52).Unix()
|
|
weekVerRecordsTo = time.Unix(weekVer, 0).AddDate(0, 0, -7).Unix() + 1
|
|
)
|
|
//1. get user_info from hbase
|
|
if userInfo, err = s.dao.UserInfo(c, mid, weekVer); err != nil {
|
|
return
|
|
}
|
|
//2. get action_counter from hbase
|
|
if actionCounter, err = s.dao.ActionCounter(c, mid, weekVer); err != nil {
|
|
return
|
|
}
|
|
//3. get figure_records from hbase
|
|
if records, err = s.dao.CalcRecords(c, mid, weekVerRecordsFrom, weekVerRecordsTo); err != nil {
|
|
return
|
|
}
|
|
//4. calc figure
|
|
figure, newRecord = s.CalcFigure(c, userInfo, []*model.ActionCounter{actionCounter}, records, weekVer)
|
|
log.Info("User figure [%+v]", figure)
|
|
log.Info("User newRecord [%+v]", newRecord)
|
|
//5. save to db
|
|
time.Sleep(time.Millisecond)
|
|
if figure.ID, err = s.dao.UpsertFigure(c, figure); err != nil {
|
|
log.Error("%+v", err)
|
|
}
|
|
//6. save new record
|
|
if err = s.dao.PutCalcRecord(c, newRecord, weekVer); err != nil {
|
|
log.Error("%+v", err)
|
|
}
|
|
//7. remove existed redis
|
|
if err = s.dao.RemoveCache(c, mid); err != nil {
|
|
log.Error("%+v", err)
|
|
}
|
|
rank.AddScore(figure.Score)
|
|
return
|
|
}
|
|
|
|
// CalcFigure calc figure.
|
|
func (s *Service) CalcFigure(c context.Context, userInfo *model.UserInfo, actionCounters []*model.ActionCounter, records []*model.FigureRecord, weekVer int64) (figure *model.Figure, newRecord *model.FigureRecord) {
|
|
figure = &model.Figure{Mid: userInfo.Mid, Ver: weekVer}
|
|
newRecord = &model.FigureRecord{Mid: userInfo.Mid, Version: time.Unix(weekVer, 0)}
|
|
var (
|
|
posx float64
|
|
negx float64
|
|
newPosx, newNegx float64
|
|
k1, k2, k3, k4, k5 float64 = s.c.Property.Calc.K1, s.c.Property.Calc.K2, s.c.Property.Calc.K3, s.c.Property.Calc.K4, s.c.Property.Calc.K5
|
|
posOffset, negOffset int64
|
|
lawfulBase = s.c.Property.Calc.InitLawfulScore
|
|
lawfulPosMax = s.c.Property.Calc.LawfulPosMax
|
|
lawfulNegMax = s.c.Property.Calc.LawfulNegMax
|
|
lawfulPosK = s.c.Property.Calc.LawfulPosK
|
|
lawfulNegK1 = s.c.Property.Calc.LawfulNegK1
|
|
lawfulNegK2 = s.c.Property.Calc.LawfulNegK2
|
|
lawfulPosL = s.c.Property.Calc.LawfulPosL
|
|
lawfulNegL = s.c.Property.Calc.LawfulNegL
|
|
lawfulPosC3 = s.c.Property.Calc.LawfulPosC3
|
|
lawfulNegC1 = s.c.Property.Calc.LawfulNegC1
|
|
lawfulPosQ3 = s.c.Property.Calc.LawfulPosQ3
|
|
lawfulNegQ1 = s.c.Property.Calc.LawfulNegQ1
|
|
wideBase = s.c.Property.Calc.InitWideScore
|
|
widePosMax = s.c.Property.Calc.WidePosMax
|
|
widePosK = s.c.Property.Calc.WidePosK
|
|
wideC1 = s.c.Property.Calc.WideC1 //有播放的活跃天数
|
|
wideQ1 = s.c.Property.Calc.WideQ1
|
|
wideC2 = s.c.Property.Calc.WideC2 // 账号累计经验值
|
|
wideQ2 = s.c.Property.Calc.WideQ2
|
|
friendlyBase = s.c.Property.Calc.InitFriendlyScore
|
|
friendlyPosMax = s.c.Property.Calc.FriendlyPosMax
|
|
friendlyNegMax = s.c.Property.Calc.FriendlyNegMax
|
|
friendlyPosK = s.c.Property.Calc.FriendlyPosK
|
|
friendlyNegK = s.c.Property.Calc.FriendlyNegK
|
|
friendlyPosL = s.c.Property.Calc.FriendlyPosL
|
|
friendlyNegL = s.c.Property.Calc.FriendlyNegL
|
|
bountyBase = s.c.Property.Calc.InitBountyScore
|
|
bountyMax = s.c.Property.Calc.BountyMax
|
|
bountyPosL = s.c.Property.Calc.BountyPosL
|
|
bountyK = s.c.Property.Calc.BountyK
|
|
bountyQ1 = s.c.Property.Calc.BountyQ1
|
|
bountyC1 = s.c.Property.Calc.BountyC1
|
|
creativityBase = s.c.Property.Calc.InitCreativityScore
|
|
creativityPosMax = s.c.Property.Calc.CreativityPosMax
|
|
creativityPosK = s.c.Property.Calc.CreativityPosK
|
|
creativityPosL1 = s.c.Property.Calc.CreativityPosL1
|
|
)
|
|
//1. lawful
|
|
newPosx, posx = s.calcActionX(lawfulPosL, bizTypePosLawful, actionCounters, records, weekVer)
|
|
posx += lawfulPosQ3 * lawfulPosC3 * float64(userInfo.DisciplineCommittee)
|
|
posOffset = calcOffset(lawfulPosMax, lawfulPosK, posx)
|
|
|
|
spyScore := userInfo.SpyScore
|
|
negx = lawfulNegQ1 * lawfulNegC1 * float64(80-float64(spyScore))
|
|
if negx < 0 {
|
|
negx = 0.0
|
|
}
|
|
negOffset = calcOffset(lawfulNegMax, lawfulNegK1, negx)
|
|
newNegx, negx = s.calcActionX(lawfulNegL, bizTypeNegLawful, actionCounters, records, weekVer)
|
|
negOffset += calcOffset(lawfulNegMax, lawfulNegK2, negx)
|
|
figure.LawfulScore = int32(lawfulBase + posOffset - negOffset)
|
|
if figure.LawfulScore < 0 {
|
|
figure.LawfulScore = 0
|
|
}
|
|
newRecord.XPosLawful, newRecord.XNegLawful = int64(newPosx), int64(newNegx)
|
|
|
|
//2. wide
|
|
newPosx, newNegx = 0, 0
|
|
posx = wideQ1*wideC1*float64(userInfo.ArchiveViews) + wideQ2*wideC2*float64(userInfo.Exp)
|
|
posOffset = calcOffset(widePosMax, widePosK, posx)
|
|
negx = 0
|
|
negOffset = 0
|
|
figure.WideScore = int32(wideBase + posOffset - negOffset)
|
|
if figure.WideScore < 0 {
|
|
figure.WideScore = 0
|
|
}
|
|
newRecord.XPosWide, newRecord.XNegWide = int64(newPosx), int64(newNegx)
|
|
|
|
//3. friendly
|
|
newPosx, newNegx = 0, 0
|
|
newPosx, posx = s.calcActionX(friendlyPosL, bizTypePosFriendly, actionCounters, records, weekVer)
|
|
posOffset = calcOffset(friendlyPosMax, friendlyPosK, posx)
|
|
newNegx, negx = s.calcActionX(friendlyNegL, bizTypeNegFriendly, actionCounters, records, weekVer)
|
|
negOffset = calcOffset(friendlyNegMax, friendlyNegK, negx)
|
|
figure.FriendlyScore = int32(friendlyBase + posOffset - negOffset)
|
|
if figure.FriendlyScore < 0 {
|
|
figure.FriendlyScore = 0
|
|
}
|
|
newRecord.XPosFriendly, newRecord.XNegFriendly = int64(newPosx), int64(newNegx)
|
|
|
|
//4. bounty
|
|
newPosx, newNegx = 0, 0
|
|
var bountyVIP float64
|
|
if userInfo.VIPStatus > 0 {
|
|
bountyVIP = 1
|
|
}
|
|
newPosx, posx = s.calcActionX(bountyPosL, bizTypePosBounty, actionCounters, records, weekVer)
|
|
posx += bountyQ1 * bountyC1 * bountyVIP
|
|
posOffset = calcOffset(bountyMax, bountyK, posx)
|
|
negx = 0
|
|
negOffset = 0
|
|
figure.BountyScore = int32(bountyBase + posOffset - negOffset)
|
|
if figure.BountyScore < 0 {
|
|
figure.BountyScore = 0
|
|
}
|
|
newRecord.XPosBounty, newRecord.XNegBounty = int64(newPosx), int64(newNegx)
|
|
|
|
//5. creativity
|
|
newPosx, newNegx = 0, 0
|
|
newPosx, posx = s.calcActionX(creativityPosL1, bizTypePosCreativity, actionCounters, records, weekVer)
|
|
posOffset = calcOffset(creativityPosMax, creativityPosK, posx)
|
|
negx = 0
|
|
negOffset = 0
|
|
figure.CreativityScore = int32(creativityBase + posOffset - negOffset)
|
|
if figure.CreativityScore < 0 {
|
|
figure.CreativityScore = 0
|
|
}
|
|
newRecord.XPosCreativity, newRecord.XNegCreativity = int64(newPosx), int64(newNegx)
|
|
|
|
//6. calc score
|
|
figure.Score = int32(math.Floor(k1*float64(figure.LawfulScore) + k2*float64(figure.WideScore) + k3*float64(figure.FriendlyScore) + k4*float64(figure.CreativityScore) + k5*float64(figure.BountyScore)))
|
|
return
|
|
}
|
|
|
|
// x must >= 0
|
|
func calcOffset(max, k, x float64) (score int64) {
|
|
return int64(math.Floor(max * (1 - math.Pow(math.E, -(k*x)))))
|
|
}
|
|
|
|
func (s *Service) calcActionX(L float64, bizType int8, actionCounters []*model.ActionCounter, records []*model.FigureRecord, weekVer int64) (newx, totalx float64) {
|
|
var (
|
|
day int64 = 24 * 3600
|
|
t float64
|
|
|
|
lawfulPosC1 = s.c.Property.Calc.LawfulPosC1
|
|
lawfulPosC2 = s.c.Property.Calc.LawfulPosC2
|
|
lawfulPosQ1 = s.c.Property.Calc.LawfulPosQ1
|
|
lawfulPosQ2 = s.c.Property.Calc.LawfulPosQ2
|
|
lawfulNegC2 = s.c.Property.Calc.LawfulNegC2
|
|
lawfulNegC3 = s.c.Property.Calc.LawfulNegC3
|
|
lawfulNegQ2 = s.c.Property.Calc.LawfulNegQ2
|
|
lawfulNegQ3 = s.c.Property.Calc.LawfulNegQ3
|
|
|
|
friendlyPosQ1 = s.c.Property.Calc.FriendlyPosQ1
|
|
friendlyPosC1 = s.c.Property.Calc.FriendlyPosC1
|
|
friendlyPosQ2 = s.c.Property.Calc.FriendlyPosQ2
|
|
friendlyPosC2 = s.c.Property.Calc.FriendlyPosC2
|
|
friendlyPosQ3 = s.c.Property.Calc.FriendlyPosQ3
|
|
friendlyPosC3 = s.c.Property.Calc.FriendlyPosC3
|
|
friendlyNegQ1 = s.c.Property.Calc.FriendlyNegQ1
|
|
friendlyNegC1 = s.c.Property.Calc.FriendlyNegC1
|
|
friendlyNegQ2 = s.c.Property.Calc.FriendlyNegQ2
|
|
friendlyNegC2 = s.c.Property.Calc.FriendlyNegC2
|
|
friendlyNegQ3 = s.c.Property.Calc.FriendlyNegQ3
|
|
friendlyNegC3 = s.c.Property.Calc.FriendlyNegC3
|
|
friendlyNegQ4 = s.c.Property.Calc.FriendlyNegQ4
|
|
friendlyNegC4 = s.c.Property.Calc.FriendlyNegC4
|
|
|
|
creativityQ1 = s.c.Property.Calc.CreativityQ1
|
|
creativityC1 = s.c.Property.Calc.CreativityC1
|
|
|
|
bountyQ2 = s.c.Property.Calc.BountyQ2
|
|
bountyC2 = s.c.Property.Calc.BountyC2
|
|
bountyQ3 = s.c.Property.Calc.BountyQ3
|
|
bountyC3 = s.c.Property.Calc.BountyC3
|
|
)
|
|
if L == 0.0 {
|
|
return 0, 0
|
|
}
|
|
for _, ac := range actionCounters {
|
|
t = float64(7 - (ac.Version.Unix()-weekVer)/day)
|
|
if t <= 0 {
|
|
continue
|
|
}
|
|
switch bizType {
|
|
case bizTypePosLawful:
|
|
if ac.ReportReplyPassed < 0 {
|
|
ac.ReportReplyPassed = 0
|
|
}
|
|
newx += actionX(lawfulPosQ1, lawfulPosC1, float64(ac.ReportReplyPassed), t, L)
|
|
if ac.ReportDanmakuPassed < 0 {
|
|
ac.ReportDanmakuPassed = 0
|
|
}
|
|
newx += actionX(lawfulPosQ2, lawfulPosC2, float64(ac.ReportDanmakuPassed), t, L)
|
|
case bizTypeNegLawful:
|
|
if ac.PublishReplyDeleted < 0 {
|
|
ac.PublishReplyDeleted = 0
|
|
}
|
|
newx += actionX(lawfulNegQ2, lawfulNegC2, float64(ac.PublishReplyDeleted), t, L)
|
|
if ac.PublishDanmakuDeleted < 0 {
|
|
ac.PublishDanmakuDeleted = 0
|
|
}
|
|
newx += actionX(lawfulNegQ3, lawfulNegC3, float64(ac.PublishDanmakuDeleted), t, L)
|
|
case bizTypePosFriendly:
|
|
newx += actionX(friendlyPosQ1, friendlyPosC1, float64(ac.CoinCount), t, L)
|
|
newx += actionX(friendlyPosQ2, friendlyPosC2, float64(ac.ReplyCount), t, L)
|
|
newx += actionX(friendlyPosQ3, friendlyPosC3, float64(ac.DanmakuCount), t, L)
|
|
case bizTypeNegFriendly:
|
|
newx += actionX(friendlyNegQ1, friendlyNegC1, float64(ac.CoinHighRisk), t, L)
|
|
newx += actionX(friendlyNegQ2, friendlyNegC2, float64(ac.CoinLowRisk), t, L)
|
|
if ac.PublishReplyDeleted < 0 {
|
|
ac.PublishReplyDeleted = 0
|
|
}
|
|
newx += actionX(friendlyNegQ3, friendlyNegC3, float64(ac.PublishReplyDeleted), t, L)
|
|
if ac.PublishDanmakuDeleted < 0 {
|
|
ac.PublishDanmakuDeleted = 0
|
|
}
|
|
newx += actionX(friendlyNegQ4, friendlyNegC4, float64(ac.PublishDanmakuDeleted), t, L)
|
|
case bizTypePosCreativity:
|
|
replyLikeCount := float64(ac.ReplyLiked) - float64(ac.ReplyUnliked)
|
|
if replyLikeCount < 0 {
|
|
replyLikeCount = 0.0
|
|
}
|
|
newx += actionX(creativityQ1, creativityC1, replyLikeCount, t, L)
|
|
case bizTypePosBounty:
|
|
newx += actionX(bountyQ2, bountyC2, float64(ac.PayMoney), t, L)
|
|
newx += actionX(bountyQ3, bountyC3, float64(ac.PayLiveMoney), t, L)
|
|
}
|
|
}
|
|
totalx = newx
|
|
for _, r := range records {
|
|
t = float64((weekVer - r.Version.Unix()) / day)
|
|
if t <= 0 {
|
|
continue
|
|
}
|
|
switch bizType {
|
|
case bizTypePosLawful:
|
|
totalx += actionX(1, 1, float64(r.XPosLawful), t, L)
|
|
case bizTypeNegLawful:
|
|
totalx += actionX(1, 1, float64(r.XNegLawful), t, L)
|
|
case bizTypePosFriendly:
|
|
totalx += actionX(1, 1, float64(r.XPosFriendly), t, L)
|
|
case bizTypeNegFriendly:
|
|
totalx += actionX(1, 1, float64(r.XNegFriendly), t, L)
|
|
case bizTypePosCreativity:
|
|
totalx += actionX(1, 1, float64(r.XPosCreativity), t, L)
|
|
case bizTypePosBounty:
|
|
totalx += actionX(1, 1, float64(r.XPosBounty), t, L)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func actionX(q, c, x, t, L float64) float64 {
|
|
return q * c * x * math.Pow(math.E, -math.Pow((t/L), 2))
|
|
}
|
|
|
|
// InitFigure initialize user figure
|
|
func (s *Service) InitFigure(c context.Context, mid int64, ver string) (figure *model.Figure, err error) {
|
|
figure = &model.Figure{}
|
|
figure.Mid = mid
|
|
figure.LawfulScore = int32(conf.Conf.Property.Calc.InitLawfulScore)
|
|
figure.WideScore = int32(conf.Conf.Property.Calc.InitWideScore)
|
|
figure.FriendlyScore = int32(conf.Conf.Property.Calc.InitFriendlyScore)
|
|
figure.BountyScore = int32(conf.Conf.Property.Calc.InitBountyScore)
|
|
figure.CreativityScore = int32(conf.Conf.Property.Calc.InitCreativityScore)
|
|
figure.Ver = s.curVer
|
|
|
|
if figure.ID, err = s.dao.UpsertFigure(c, figure); err != nil {
|
|
return
|
|
}
|
|
if err = s.dao.SetFigureCache(c, figure); err != nil {
|
|
log.Error("%+v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
// get ever monday start time ts.
|
|
func weekVersion(now time.Time) (ts int64) {
|
|
var (
|
|
wd int
|
|
w time.Weekday
|
|
)
|
|
w = now.Weekday()
|
|
switch w {
|
|
case time.Sunday:
|
|
wd = 6
|
|
default:
|
|
wd = int(w) - 1
|
|
}
|
|
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -wd).Unix()
|
|
}
|