calc.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. package service
  2. import (
  3. "context"
  4. "math"
  5. "time"
  6. "go-common/app/job/main/figure-timer/conf"
  7. "go-common/app/job/main/figure-timer/model"
  8. "go-common/library/log"
  9. )
  10. const (
  11. bizTypePosLawful = iota
  12. bizTypeNegLawful
  13. // bizTypePosWide
  14. // bizTypeNegWide
  15. bizTypePosFriendly
  16. bizTypeNegFriendly
  17. bizTypePosCreativity
  18. // bizTypeNegCreativity
  19. bizTypePosBounty
  20. // bizTypeNegBounty
  21. )
  22. // HandleFigure handle all figure score for a mid
  23. func (s *Service) HandleFigure(c context.Context, mid int64, weekVer int64) (err error) {
  24. var (
  25. figure = &model.Figure{}
  26. userInfo *model.UserInfo
  27. actionCounter *model.ActionCounter
  28. records []*model.FigureRecord
  29. newRecord *model.FigureRecord
  30. weekVerRecordsFrom = time.Unix(weekVer, 0).AddDate(0, 0, -7*52).Unix()
  31. weekVerRecordsTo = time.Unix(weekVer, 0).AddDate(0, 0, -7).Unix() + 1
  32. )
  33. //1. get user_info from hbase
  34. if userInfo, err = s.dao.UserInfo(c, mid, weekVer); err != nil {
  35. return
  36. }
  37. //2. get action_counter from hbase
  38. if actionCounter, err = s.dao.ActionCounter(c, mid, weekVer); err != nil {
  39. return
  40. }
  41. //3. get figure_records from hbase
  42. if records, err = s.dao.CalcRecords(c, mid, weekVerRecordsFrom, weekVerRecordsTo); err != nil {
  43. return
  44. }
  45. //4. calc figure
  46. figure, newRecord = s.CalcFigure(c, userInfo, []*model.ActionCounter{actionCounter}, records, weekVer)
  47. log.Info("User figure [%+v]", figure)
  48. log.Info("User newRecord [%+v]", newRecord)
  49. //5. save to db
  50. time.Sleep(time.Millisecond)
  51. if figure.ID, err = s.dao.UpsertFigure(c, figure); err != nil {
  52. log.Error("%+v", err)
  53. }
  54. //6. save new record
  55. if err = s.dao.PutCalcRecord(c, newRecord, weekVer); err != nil {
  56. log.Error("%+v", err)
  57. }
  58. //7. remove existed redis
  59. if err = s.dao.RemoveCache(c, mid); err != nil {
  60. log.Error("%+v", err)
  61. }
  62. rank.AddScore(figure.Score)
  63. return
  64. }
  65. // CalcFigure calc figure.
  66. func (s *Service) CalcFigure(c context.Context, userInfo *model.UserInfo, actionCounters []*model.ActionCounter, records []*model.FigureRecord, weekVer int64) (figure *model.Figure, newRecord *model.FigureRecord) {
  67. figure = &model.Figure{Mid: userInfo.Mid, Ver: weekVer}
  68. newRecord = &model.FigureRecord{Mid: userInfo.Mid, Version: time.Unix(weekVer, 0)}
  69. var (
  70. posx float64
  71. negx float64
  72. newPosx, newNegx float64
  73. 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
  74. posOffset, negOffset int64
  75. lawfulBase = s.c.Property.Calc.InitLawfulScore
  76. lawfulPosMax = s.c.Property.Calc.LawfulPosMax
  77. lawfulNegMax = s.c.Property.Calc.LawfulNegMax
  78. lawfulPosK = s.c.Property.Calc.LawfulPosK
  79. lawfulNegK1 = s.c.Property.Calc.LawfulNegK1
  80. lawfulNegK2 = s.c.Property.Calc.LawfulNegK2
  81. lawfulPosL = s.c.Property.Calc.LawfulPosL
  82. lawfulNegL = s.c.Property.Calc.LawfulNegL
  83. lawfulPosC3 = s.c.Property.Calc.LawfulPosC3
  84. lawfulNegC1 = s.c.Property.Calc.LawfulNegC1
  85. lawfulPosQ3 = s.c.Property.Calc.LawfulPosQ3
  86. lawfulNegQ1 = s.c.Property.Calc.LawfulNegQ1
  87. wideBase = s.c.Property.Calc.InitWideScore
  88. widePosMax = s.c.Property.Calc.WidePosMax
  89. widePosK = s.c.Property.Calc.WidePosK
  90. wideC1 = s.c.Property.Calc.WideC1 //有播放的活跃天数
  91. wideQ1 = s.c.Property.Calc.WideQ1
  92. wideC2 = s.c.Property.Calc.WideC2 // 账号累计经验值
  93. wideQ2 = s.c.Property.Calc.WideQ2
  94. friendlyBase = s.c.Property.Calc.InitFriendlyScore
  95. friendlyPosMax = s.c.Property.Calc.FriendlyPosMax
  96. friendlyNegMax = s.c.Property.Calc.FriendlyNegMax
  97. friendlyPosK = s.c.Property.Calc.FriendlyPosK
  98. friendlyNegK = s.c.Property.Calc.FriendlyNegK
  99. friendlyPosL = s.c.Property.Calc.FriendlyPosL
  100. friendlyNegL = s.c.Property.Calc.FriendlyNegL
  101. bountyBase = s.c.Property.Calc.InitBountyScore
  102. bountyMax = s.c.Property.Calc.BountyMax
  103. bountyPosL = s.c.Property.Calc.BountyPosL
  104. bountyK = s.c.Property.Calc.BountyK
  105. bountyQ1 = s.c.Property.Calc.BountyQ1
  106. bountyC1 = s.c.Property.Calc.BountyC1
  107. creativityBase = s.c.Property.Calc.InitCreativityScore
  108. creativityPosMax = s.c.Property.Calc.CreativityPosMax
  109. creativityPosK = s.c.Property.Calc.CreativityPosK
  110. creativityPosL1 = s.c.Property.Calc.CreativityPosL1
  111. )
  112. //1. lawful
  113. newPosx, posx = s.calcActionX(lawfulPosL, bizTypePosLawful, actionCounters, records, weekVer)
  114. posx += lawfulPosQ3 * lawfulPosC3 * float64(userInfo.DisciplineCommittee)
  115. posOffset = calcOffset(lawfulPosMax, lawfulPosK, posx)
  116. spyScore := userInfo.SpyScore
  117. negx = lawfulNegQ1 * lawfulNegC1 * float64(80-float64(spyScore))
  118. if negx < 0 {
  119. negx = 0.0
  120. }
  121. negOffset = calcOffset(lawfulNegMax, lawfulNegK1, negx)
  122. newNegx, negx = s.calcActionX(lawfulNegL, bizTypeNegLawful, actionCounters, records, weekVer)
  123. negOffset += calcOffset(lawfulNegMax, lawfulNegK2, negx)
  124. figure.LawfulScore = int32(lawfulBase + posOffset - negOffset)
  125. if figure.LawfulScore < 0 {
  126. figure.LawfulScore = 0
  127. }
  128. newRecord.XPosLawful, newRecord.XNegLawful = int64(newPosx), int64(newNegx)
  129. //2. wide
  130. newPosx, newNegx = 0, 0
  131. posx = wideQ1*wideC1*float64(userInfo.ArchiveViews) + wideQ2*wideC2*float64(userInfo.Exp)
  132. posOffset = calcOffset(widePosMax, widePosK, posx)
  133. negx = 0
  134. negOffset = 0
  135. figure.WideScore = int32(wideBase + posOffset - negOffset)
  136. if figure.WideScore < 0 {
  137. figure.WideScore = 0
  138. }
  139. newRecord.XPosWide, newRecord.XNegWide = int64(newPosx), int64(newNegx)
  140. //3. friendly
  141. newPosx, newNegx = 0, 0
  142. newPosx, posx = s.calcActionX(friendlyPosL, bizTypePosFriendly, actionCounters, records, weekVer)
  143. posOffset = calcOffset(friendlyPosMax, friendlyPosK, posx)
  144. newNegx, negx = s.calcActionX(friendlyNegL, bizTypeNegFriendly, actionCounters, records, weekVer)
  145. negOffset = calcOffset(friendlyNegMax, friendlyNegK, negx)
  146. figure.FriendlyScore = int32(friendlyBase + posOffset - negOffset)
  147. if figure.FriendlyScore < 0 {
  148. figure.FriendlyScore = 0
  149. }
  150. newRecord.XPosFriendly, newRecord.XNegFriendly = int64(newPosx), int64(newNegx)
  151. //4. bounty
  152. newPosx, newNegx = 0, 0
  153. var bountyVIP float64
  154. if userInfo.VIPStatus > 0 {
  155. bountyVIP = 1
  156. }
  157. newPosx, posx = s.calcActionX(bountyPosL, bizTypePosBounty, actionCounters, records, weekVer)
  158. posx += bountyQ1 * bountyC1 * bountyVIP
  159. posOffset = calcOffset(bountyMax, bountyK, posx)
  160. negx = 0
  161. negOffset = 0
  162. figure.BountyScore = int32(bountyBase + posOffset - negOffset)
  163. if figure.BountyScore < 0 {
  164. figure.BountyScore = 0
  165. }
  166. newRecord.XPosBounty, newRecord.XNegBounty = int64(newPosx), int64(newNegx)
  167. //5. creativity
  168. newPosx, newNegx = 0, 0
  169. newPosx, posx = s.calcActionX(creativityPosL1, bizTypePosCreativity, actionCounters, records, weekVer)
  170. posOffset = calcOffset(creativityPosMax, creativityPosK, posx)
  171. negx = 0
  172. negOffset = 0
  173. figure.CreativityScore = int32(creativityBase + posOffset - negOffset)
  174. if figure.CreativityScore < 0 {
  175. figure.CreativityScore = 0
  176. }
  177. newRecord.XPosCreativity, newRecord.XNegCreativity = int64(newPosx), int64(newNegx)
  178. //6. calc score
  179. 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)))
  180. return
  181. }
  182. // x must >= 0
  183. func calcOffset(max, k, x float64) (score int64) {
  184. return int64(math.Floor(max * (1 - math.Pow(math.E, -(k*x)))))
  185. }
  186. func (s *Service) calcActionX(L float64, bizType int8, actionCounters []*model.ActionCounter, records []*model.FigureRecord, weekVer int64) (newx, totalx float64) {
  187. var (
  188. day int64 = 24 * 3600
  189. t float64
  190. lawfulPosC1 = s.c.Property.Calc.LawfulPosC1
  191. lawfulPosC2 = s.c.Property.Calc.LawfulPosC2
  192. lawfulPosQ1 = s.c.Property.Calc.LawfulPosQ1
  193. lawfulPosQ2 = s.c.Property.Calc.LawfulPosQ2
  194. lawfulNegC2 = s.c.Property.Calc.LawfulNegC2
  195. lawfulNegC3 = s.c.Property.Calc.LawfulNegC3
  196. lawfulNegQ2 = s.c.Property.Calc.LawfulNegQ2
  197. lawfulNegQ3 = s.c.Property.Calc.LawfulNegQ3
  198. friendlyPosQ1 = s.c.Property.Calc.FriendlyPosQ1
  199. friendlyPosC1 = s.c.Property.Calc.FriendlyPosC1
  200. friendlyPosQ2 = s.c.Property.Calc.FriendlyPosQ2
  201. friendlyPosC2 = s.c.Property.Calc.FriendlyPosC2
  202. friendlyPosQ3 = s.c.Property.Calc.FriendlyPosQ3
  203. friendlyPosC3 = s.c.Property.Calc.FriendlyPosC3
  204. friendlyNegQ1 = s.c.Property.Calc.FriendlyNegQ1
  205. friendlyNegC1 = s.c.Property.Calc.FriendlyNegC1
  206. friendlyNegQ2 = s.c.Property.Calc.FriendlyNegQ2
  207. friendlyNegC2 = s.c.Property.Calc.FriendlyNegC2
  208. friendlyNegQ3 = s.c.Property.Calc.FriendlyNegQ3
  209. friendlyNegC3 = s.c.Property.Calc.FriendlyNegC3
  210. friendlyNegQ4 = s.c.Property.Calc.FriendlyNegQ4
  211. friendlyNegC4 = s.c.Property.Calc.FriendlyNegC4
  212. creativityQ1 = s.c.Property.Calc.CreativityQ1
  213. creativityC1 = s.c.Property.Calc.CreativityC1
  214. bountyQ2 = s.c.Property.Calc.BountyQ2
  215. bountyC2 = s.c.Property.Calc.BountyC2
  216. bountyQ3 = s.c.Property.Calc.BountyQ3
  217. bountyC3 = s.c.Property.Calc.BountyC3
  218. )
  219. if L == 0.0 {
  220. return 0, 0
  221. }
  222. for _, ac := range actionCounters {
  223. t = float64(7 - (ac.Version.Unix()-weekVer)/day)
  224. if t <= 0 {
  225. continue
  226. }
  227. switch bizType {
  228. case bizTypePosLawful:
  229. if ac.ReportReplyPassed < 0 {
  230. ac.ReportReplyPassed = 0
  231. }
  232. newx += actionX(lawfulPosQ1, lawfulPosC1, float64(ac.ReportReplyPassed), t, L)
  233. if ac.ReportDanmakuPassed < 0 {
  234. ac.ReportDanmakuPassed = 0
  235. }
  236. newx += actionX(lawfulPosQ2, lawfulPosC2, float64(ac.ReportDanmakuPassed), t, L)
  237. case bizTypeNegLawful:
  238. if ac.PublishReplyDeleted < 0 {
  239. ac.PublishReplyDeleted = 0
  240. }
  241. newx += actionX(lawfulNegQ2, lawfulNegC2, float64(ac.PublishReplyDeleted), t, L)
  242. if ac.PublishDanmakuDeleted < 0 {
  243. ac.PublishDanmakuDeleted = 0
  244. }
  245. newx += actionX(lawfulNegQ3, lawfulNegC3, float64(ac.PublishDanmakuDeleted), t, L)
  246. case bizTypePosFriendly:
  247. newx += actionX(friendlyPosQ1, friendlyPosC1, float64(ac.CoinCount), t, L)
  248. newx += actionX(friendlyPosQ2, friendlyPosC2, float64(ac.ReplyCount), t, L)
  249. newx += actionX(friendlyPosQ3, friendlyPosC3, float64(ac.DanmakuCount), t, L)
  250. case bizTypeNegFriendly:
  251. newx += actionX(friendlyNegQ1, friendlyNegC1, float64(ac.CoinHighRisk), t, L)
  252. newx += actionX(friendlyNegQ2, friendlyNegC2, float64(ac.CoinLowRisk), t, L)
  253. if ac.PublishReplyDeleted < 0 {
  254. ac.PublishReplyDeleted = 0
  255. }
  256. newx += actionX(friendlyNegQ3, friendlyNegC3, float64(ac.PublishReplyDeleted), t, L)
  257. if ac.PublishDanmakuDeleted < 0 {
  258. ac.PublishDanmakuDeleted = 0
  259. }
  260. newx += actionX(friendlyNegQ4, friendlyNegC4, float64(ac.PublishDanmakuDeleted), t, L)
  261. case bizTypePosCreativity:
  262. replyLikeCount := float64(ac.ReplyLiked) - float64(ac.ReplyUnliked)
  263. if replyLikeCount < 0 {
  264. replyLikeCount = 0.0
  265. }
  266. newx += actionX(creativityQ1, creativityC1, replyLikeCount, t, L)
  267. case bizTypePosBounty:
  268. newx += actionX(bountyQ2, bountyC2, float64(ac.PayMoney), t, L)
  269. newx += actionX(bountyQ3, bountyC3, float64(ac.PayLiveMoney), t, L)
  270. }
  271. }
  272. totalx = newx
  273. for _, r := range records {
  274. t = float64((weekVer - r.Version.Unix()) / day)
  275. if t <= 0 {
  276. continue
  277. }
  278. switch bizType {
  279. case bizTypePosLawful:
  280. totalx += actionX(1, 1, float64(r.XPosLawful), t, L)
  281. case bizTypeNegLawful:
  282. totalx += actionX(1, 1, float64(r.XNegLawful), t, L)
  283. case bizTypePosFriendly:
  284. totalx += actionX(1, 1, float64(r.XPosFriendly), t, L)
  285. case bizTypeNegFriendly:
  286. totalx += actionX(1, 1, float64(r.XNegFriendly), t, L)
  287. case bizTypePosCreativity:
  288. totalx += actionX(1, 1, float64(r.XPosCreativity), t, L)
  289. case bizTypePosBounty:
  290. totalx += actionX(1, 1, float64(r.XPosBounty), t, L)
  291. }
  292. }
  293. return
  294. }
  295. func actionX(q, c, x, t, L float64) float64 {
  296. return q * c * x * math.Pow(math.E, -math.Pow((t/L), 2))
  297. }
  298. // InitFigure initialize user figure
  299. func (s *Service) InitFigure(c context.Context, mid int64, ver string) (figure *model.Figure, err error) {
  300. figure = &model.Figure{}
  301. figure.Mid = mid
  302. figure.LawfulScore = int32(conf.Conf.Property.Calc.InitLawfulScore)
  303. figure.WideScore = int32(conf.Conf.Property.Calc.InitWideScore)
  304. figure.FriendlyScore = int32(conf.Conf.Property.Calc.InitFriendlyScore)
  305. figure.BountyScore = int32(conf.Conf.Property.Calc.InitBountyScore)
  306. figure.CreativityScore = int32(conf.Conf.Property.Calc.InitCreativityScore)
  307. figure.Ver = s.curVer
  308. if figure.ID, err = s.dao.UpsertFigure(c, figure); err != nil {
  309. return
  310. }
  311. if err = s.dao.SetFigureCache(c, figure); err != nil {
  312. log.Error("%+v", err)
  313. }
  314. return
  315. }
  316. // get ever monday start time ts.
  317. func weekVersion(now time.Time) (ts int64) {
  318. var (
  319. wd int
  320. w time.Weekday
  321. )
  322. w = now.Weekday()
  323. switch w {
  324. case time.Sunday:
  325. wd = 6
  326. default:
  327. wd = int(w) - 1
  328. }
  329. return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -wd).Unix()
  330. }