rank.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. package mcndao
  2. import (
  3. "context"
  4. "fmt"
  5. "sort"
  6. "time"
  7. "go-common/app/admin/main/up/util"
  8. "go-common/app/admin/main/up/util/mathutil"
  9. "go-common/app/interface/main/mcn/conf"
  10. "go-common/app/interface/main/mcn/dao/cache"
  11. "go-common/app/interface/main/mcn/dao/global"
  12. "go-common/app/interface/main/mcn/model/mcnmodel"
  13. arcgrpc "go-common/app/service/main/archive/api"
  14. "go-common/library/log"
  15. "github.com/bluele/gcache"
  16. )
  17. // RankByTid .
  18. // 存储rank的缓存
  19. // 对每种排行榜的分类进行缓存
  20. // 对排序进行实时计算
  21. // 先去localcache中取,取不到的话,去db中取
  22. type RankByTid struct {
  23. // [tid][datatype] rank list
  24. TidMap map[int16]map[mcnmodel.DataType][]mcnmodel.RankDataInterface
  25. TidTypeListMap map[mcnmodel.DataType][]*mcnmodel.TidnameInfo
  26. }
  27. //RankFunc rank func
  28. type RankFunc func(signId int64) (result *RankByTid, err error)
  29. type tidnameUnique struct {
  30. tidInfoMap map[mcnmodel.DataType]map[int16]*mcnmodel.TidnameInfo
  31. }
  32. func newTidNameUnique() *tidnameUnique {
  33. return &tidnameUnique{tidInfoMap: make(map[mcnmodel.DataType]map[int16]*mcnmodel.TidnameInfo)}
  34. }
  35. func (t *tidnameUnique) addTid(tid int16, name string, datatype mcnmodel.DataType) {
  36. var dmap map[int16]*mcnmodel.TidnameInfo
  37. var ok bool
  38. if dmap, ok = t.tidInfoMap[datatype]; !ok {
  39. dmap = make(map[int16]*mcnmodel.TidnameInfo)
  40. t.tidInfoMap[datatype] = dmap
  41. }
  42. dmap[tid] = &mcnmodel.TidnameInfo{Tid: tid, Name: name}
  43. }
  44. func (t *tidnameUnique) getList(datatype mcnmodel.DataType) (typeList []*mcnmodel.TidnameInfo) {
  45. for _, v := range t.tidInfoMap[datatype] {
  46. typeList = append(typeList, v)
  47. }
  48. return
  49. }
  50. func (t *tidnameUnique) export(dmap map[mcnmodel.DataType][]*mcnmodel.TidnameInfo) {
  51. for dataType, tidMap := range t.tidInfoMap {
  52. var typeList []*mcnmodel.TidnameInfo
  53. for k, v := range tidMap {
  54. if k == 0 {
  55. continue
  56. }
  57. typeList = append(typeList, v)
  58. }
  59. dmap[dataType] = typeList
  60. }
  61. }
  62. // // 排序,根据increase数量做倒序
  63. // type rankByFansIncreaseDesc []*mcnmodel.RankUpFansInfo
  64. // func (s rankByFansIncreaseDesc) Len() int {
  65. // return len(s)
  66. // }
  67. // func (s rankByFansIncreaseDesc) Swap(i, j int) {
  68. // s[i], s[j] = s[j], s[i]
  69. // }
  70. // func (s rankByFansIncreaseDesc) Less(i, j int) bool {
  71. // return s[i].FansIncrease > s[j].FansIncrease
  72. // }
  73. type sortRankFunc func(p1, p2 mcnmodel.RankDataInterface) bool
  74. type rankDataSorter struct {
  75. datas []mcnmodel.RankDataInterface
  76. by sortRankFunc // Closure used in the Less method.
  77. }
  78. // Len is part of sort.Interface.
  79. func (s *rankDataSorter) Len() int {
  80. return len(s.datas)
  81. }
  82. // Swap is part of sort.Interface.
  83. func (s *rankDataSorter) Swap(i, j int) {
  84. s.datas[i], s.datas[j] = s.datas[j], s.datas[i]
  85. }
  86. // Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
  87. func (s *rankDataSorter) Less(i, j int) bool {
  88. return s.by(s.datas[i], s.datas[j])
  89. }
  90. func byValueDesc(p1, p2 mcnmodel.RankDataInterface) bool {
  91. return p1.GetValue() > p2.GetValue()
  92. }
  93. //GetList get list
  94. func (s *RankByTid) GetList(tid int16, dataType mcnmodel.DataType) (res []mcnmodel.RankDataInterface) {
  95. if s.TidMap == nil {
  96. return
  97. }
  98. tMap, ok := s.TidMap[tid]
  99. if !ok || tMap == nil {
  100. return
  101. }
  102. if res, ok = tMap[dataType]; !ok {
  103. res = nil
  104. }
  105. return
  106. }
  107. var nulltidlist = make([]*mcnmodel.TidnameInfo, 0)
  108. //GetTypeList get type's list
  109. func (s *RankByTid) GetTypeList(dataType mcnmodel.DataType) (res []*mcnmodel.TidnameInfo) {
  110. res = s.TidTypeListMap[dataType]
  111. if res == nil {
  112. res = nulltidlist
  113. }
  114. return
  115. }
  116. func (s *RankByTid) addRank(v mcnmodel.RankDataInterface) {
  117. var dmap, allMap map[mcnmodel.DataType][]mcnmodel.RankDataInterface
  118. if s.TidMap == nil {
  119. s.TidMap = make(map[int16]map[mcnmodel.DataType][]mcnmodel.RankDataInterface)
  120. }
  121. var ok bool
  122. if v.GetTid() != 0 {
  123. if dmap, ok = s.TidMap[v.GetTid()]; !ok {
  124. dmap = make(map[mcnmodel.DataType][]mcnmodel.RankDataInterface)
  125. s.TidMap[v.GetTid()] = dmap
  126. }
  127. dmap[v.GetDataType()] = append(dmap[v.GetDataType()], v)
  128. }
  129. if allMap, ok = s.TidMap[0]; !ok {
  130. allMap = make(map[mcnmodel.DataType][]mcnmodel.RankDataInterface)
  131. s.TidMap[0] = allMap
  132. }
  133. allMap[v.GetDataType()] = append(allMap[v.GetDataType()], v)
  134. }
  135. func (s *RankByTid) addTidMap(v *tidnameUnique) {
  136. if s.TidTypeListMap == nil {
  137. s.TidTypeListMap = make(map[mcnmodel.DataType][]*mcnmodel.TidnameInfo)
  138. }
  139. v.export(s.TidTypeListMap)
  140. }
  141. //Truncate truncate all the sorted list by max item number
  142. func (s *RankByTid) Truncate(max int) {
  143. for _, v := range s.TidMap {
  144. for k2, v2 := range v {
  145. var length = len(v2)
  146. if length == 0 {
  147. continue
  148. }
  149. var m = mathutil.Min(max, length)
  150. v[k2] = v2[0:m]
  151. }
  152. }
  153. }
  154. // Sort sort by sorting function
  155. func (s *RankByTid) Sort(sortFunc sortRankFunc) {
  156. for _, v := range s.TidMap {
  157. for k2, v2 := range v {
  158. var sorter = &rankDataSorter{
  159. datas: v2,
  160. by: sortFunc,
  161. }
  162. sort.Sort(sorter)
  163. v[k2] = v2
  164. }
  165. }
  166. }
  167. type keyFunc func(int64) string
  168. type loadRankFunc func(signID int64, date time.Time) (result *RankByTid, err error)
  169. // GetRankUpFans get fans
  170. func (d *Dao) GetRankUpFans(signID int64) (result *RankByTid, err error) {
  171. return d.getRankCache(signID, cacheKeyRankFans, d.loadRankUpFansCache)
  172. }
  173. // GetRankArchiveLikes get fans
  174. func (d *Dao) GetRankArchiveLikes(signID int64) (result *RankByTid, err error) {
  175. return d.getRankCache(signID, cacheKeyRankArchiveLikes, d.loadRankArchiveLikesCache)
  176. }
  177. func (d *Dao) getRankCache(signID int64, keyCalc keyFunc, load loadRankFunc) (result *RankByTid, err error) {
  178. var key = keyCalc(signID)
  179. v, err := d.localcache.Get(key)
  180. if err != nil {
  181. if err == gcache.KeyNotFoundError {
  182. // load cache
  183. v, err = load(signID, time.Now())
  184. if err != nil {
  185. log.Error("load cache error, signID=%d, err=%s", signID, err)
  186. return
  187. }
  188. d.localcache.SetWithExpire(key, v, time.Duration(conf.Conf.RankCache.ExpireTime))
  189. } else {
  190. log.Error("get from gcache err, signID=%d, err=%s", signID, err)
  191. return
  192. }
  193. }
  194. if v == nil {
  195. return
  196. }
  197. result, _ = v.(*RankByTid)
  198. return
  199. }
  200. func cacheKeyRankFans(signID int64) string {
  201. return fmt.Sprintf("rank_fans_%d", signID)
  202. }
  203. func cacheKeyRankArchiveLikes(signID int64) string {
  204. return fmt.Sprintf("rank_likes_%d", signID)
  205. }
  206. var dataTypes = []mcnmodel.DataType{
  207. mcnmodel.DataTypeAccumulate,
  208. mcnmodel.DataTypeDay,
  209. mcnmodel.DataTypeWeek,
  210. mcnmodel.DataTypeMonth,
  211. mcnmodel.DataTypeActiveFans,
  212. }
  213. // --------------------------------------- load rank up fans -------------------------------
  214. func (d *Dao) loadRankUpFansCache(signID int64, date time.Time) (result *RankByTid, err error) {
  215. rawRanks, err := d.RawRankUpFans(signID, date)
  216. if err != nil {
  217. log.Error("fail to get raw rank up fans, signid=%d, err=%s", signID, err)
  218. return
  219. }
  220. result = new(RankByTid)
  221. if len(rawRanks) == 0 {
  222. log.Info("up fans rank data is empty, sign id=%d", signID)
  223. return
  224. }
  225. var midMap = make(map[int64]struct{})
  226. //var accumulateMap = make(map[int64]*mcnmodel.McnRankUpFan)
  227. // 获取mid列表
  228. for _, v := range rawRanks {
  229. midMap[v.UpMid] = struct{}{}
  230. //if v.DataType == mcnmodel.DataTypeAccumulate {
  231. // accumulateMap[v.UpMid] = v
  232. //}
  233. }
  234. var mids []int64
  235. for k := range midMap {
  236. mids = append(mids, k)
  237. }
  238. // 获取账号信息,头像
  239. accInfos, err := global.GetInfos(context.Background(), mids)
  240. if err != nil || accInfos == nil {
  241. log.Warn("get infos fail, err=%s", err)
  242. }
  243. var tidUnique = newTidNameUnique()
  244. // 组装信息
  245. for _, v := range rawRanks {
  246. var info mcnmodel.RankUpFansInfo
  247. info.Copy(v)
  248. if account, ok := accInfos[v.UpMid]; ok {
  249. info.Name = account.Name
  250. info.UpFaceLink = account.Face
  251. info.TidName = cache.GetTidName(int64(info.Tid))
  252. if info.TidName == "" {
  253. info.TidName = "其他"
  254. }
  255. tidUnique.addTid(info.Tid, info.TidName, info.DataType)
  256. }
  257. //if accumulateData, ok := accumulateMap[v.UpMid]; ok {
  258. // info.FansAccumulate = accumulateData.Value1
  259. //}
  260. result.addRank(&info)
  261. }
  262. result.addTidMap(tidUnique)
  263. // 排序
  264. result.Sort(byValueDesc)
  265. // 截断到10个,截断需要在排序之后
  266. result.Truncate(10)
  267. return
  268. }
  269. //RawRankUpFans get from db
  270. func (d *Dao) RawRankUpFans(signID int64, date time.Time) (result []*mcnmodel.McnRankUpFan, err error) {
  271. // 有X种类型,
  272. // 昨日、上周、上月、累计
  273. // 每种类型取最近日期的数据
  274. for _, typ := range dataTypes {
  275. var tmpResult []*mcnmodel.McnRankUpFan
  276. e := d.mcndb.Raw(`select * from mcn_rank_up_fans where data_type=? and sign_id=?
  277. and generate_date=(select generate_date from mcn_rank_up_fans where data_type=? and sign_id=? and generate_date <= ? order by generate_date desc limit 1)`,
  278. typ, signID, typ, signID, date).
  279. Find(&tmpResult).Error
  280. if e != nil {
  281. log.Error("fail to get rank, type=%d, sign id=%d, err=%s", typ, signID, e)
  282. continue
  283. }
  284. result = append(result, tmpResult...)
  285. }
  286. log.Info("get rank from db, sign id=%d, len=%d, date=%s", signID, len(result), date.Format(dateFmt))
  287. return
  288. }
  289. //ReloadRank reload rank from db
  290. func (d *Dao) ReloadRank(signID int64) (err error) {
  291. // load cache
  292. v, err := d.loadRankUpFansCache(signID, time.Now())
  293. if err != nil {
  294. log.Error("load cache error, signID=%d, err=%s", signID, err)
  295. return
  296. }
  297. var key = cacheKeyRankFans(signID)
  298. d.localcache.SetWithExpire(key, v, time.Hour)
  299. log.Info("reload rank cache, sign id=%d", signID)
  300. return
  301. }
  302. // ----------------------------------------- load rank archive likes ------------------------------------
  303. func (d *Dao) loadRankArchiveLikesCache(signID int64, date time.Time) (result *RankByTid, err error) {
  304. rawArchiveLike, err := d.RawRankArchiveLikes(signID, date)
  305. if err != nil {
  306. log.Error("fail to get raw rank up fans, signid=%d, err=%s", signID, err)
  307. return
  308. }
  309. result = new(RankByTid)
  310. if len(rawArchiveLike) == 0 {
  311. log.Info("archive likes rank data is empty, sign id=%d", signID)
  312. return
  313. }
  314. // 获取 aid列表
  315. var aids []int64
  316. //var accumulateMap = make(map[int64]*mcnmodel.McnRankArchiveLike)
  317. for _, v := range rawArchiveLike {
  318. aids = append(aids, v.ArchiveID)
  319. //if v.DataType == mcnmodel.DataTypeAccumulate {
  320. // accumulateMap[v.ArchiveID] = v
  321. //}
  322. }
  323. aids = util.Unique(aids)
  324. // 获取archive信息
  325. arcsReply, err := global.GetArcGRPC().Arcs(context.Background(), &arcgrpc.ArcsRequest{Aids: aids})
  326. if err != nil {
  327. log.Error("fail to get archive info, sign_id=%d err=%s", signID, err)
  328. return
  329. }
  330. archiveDataMap := arcsReply.Arcs
  331. var tidUnique = newTidNameUnique()
  332. // 组装archive信息
  333. for _, v := range rawArchiveLike {
  334. var info = mcnmodel.RankArchiveLikeInfo{}
  335. info.CopyFromDB(v)
  336. var archive, ok = archiveDataMap[v.ArchiveID]
  337. if !ok {
  338. continue
  339. }
  340. info.CopyFromArchive(archive)
  341. tidUnique.addTid(info.Tid, info.TidName, info.DataType)
  342. //if accumulateData, ok := accumulateMap[v.ArchiveID]; ok {
  343. // info.LikesAccumulate = accumulateData.LikeCount
  344. //}
  345. result.addRank(&info)
  346. }
  347. result.addTidMap(tidUnique)
  348. // 排序
  349. result.Sort(byValueDesc)
  350. result.Truncate(10)
  351. return
  352. }
  353. //RawRankArchiveLikes get from db
  354. func (d *Dao) RawRankArchiveLikes(signID int64, date time.Time) (result []*mcnmodel.McnRankArchiveLike, err error) {
  355. // 有X种类型,
  356. // 昨日、上周、上月、累计
  357. // 每种类型取最近日期的数据
  358. for _, typ := range dataTypes {
  359. var tmpResult []*mcnmodel.McnRankArchiveLike
  360. e := d.mcndb.Raw(`select * from mcn_rank_archive_likes where data_type=? and sign_id=?
  361. and generate_date=(select generate_date from mcn_rank_archive_likes where data_type=? and sign_id=? and generate_date <= ? order by generate_date desc limit 1)`,
  362. typ, signID, typ, signID, date).
  363. Find(&tmpResult).Error
  364. if e != nil {
  365. log.Error("fail to get rank, type=%d, sign id=%d, err=%s", typ, signID, e)
  366. continue
  367. }
  368. result = append(result, tmpResult...)
  369. }
  370. log.Info("get rank from db, sign id=%d, len=%d, date=%s", signID, len(result), date.Format(dateFmt))
  371. return
  372. }