test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. package v1
  2. import (
  3. "context"
  4. "designs/config"
  5. "designs/crons"
  6. "designs/global"
  7. "designs/model"
  8. "designs/response"
  9. "designs/service"
  10. "fmt"
  11. "github.com/gin-gonic/gin"
  12. "go.mongodb.org/mongo-driver/v2/bson"
  13. "gorm.io/gorm/clause"
  14. "os"
  15. "strconv"
  16. "time"
  17. )
  18. type logData struct {
  19. LogTime time.Time `json:"logTime" gorm:"column:logTime;"`
  20. Type int `json:"Type"`
  21. }
  22. func calculateUserOnlineTime(logData []logData) int64 {
  23. var lastLog int64
  24. var isStart bool
  25. var onlineTimeTotal int64
  26. for k, v := range logData {
  27. logTime := v.LogTime.Unix()
  28. //如果跟上一次的记录隔的时间超过6分钟,就认为是之前断线了,属于无效数据
  29. if k > 0 && logData[k-1].LogTime.Unix()+60*6 < logTime {
  30. isStart = false
  31. continue
  32. }
  33. if v.Type == 1 && isStart == false {
  34. isStart = true
  35. lastLog = v.LogTime.Unix()
  36. continue
  37. }
  38. if v.Type == 1 && isStart == true {
  39. //logTime := v.LogTime.Unix()
  40. onlineTimeTotal = onlineTimeTotal + (logTime - lastLog)
  41. lastLog = logTime
  42. //如果下一次的心跳,间隔时间大于6分钟了,就可以认为,这次就算是结束了
  43. if k+1 == len(logData) || logData[k+1].LogTime.Unix() > logTime+60*6 {
  44. isStart = false
  45. }
  46. continue
  47. }
  48. if v.Type == 2 && isStart == true {
  49. //logTime := v.LogTime.Unix()
  50. onlineTimeTotal = onlineTimeTotal + (logTime - lastLog)
  51. isStart = false
  52. continue
  53. }
  54. }
  55. return onlineTimeTotal
  56. }
  57. func SetUserBehaviorBak(c *gin.Context) {
  58. //读取出来user数据
  59. var users []model.User
  60. global.App.DB.Table("user").
  61. Where("pf", "=", "tt").
  62. Where("gid", "=", "linkup").
  63. Where("createdAt", ">=", "2024-11-12").
  64. Where("createdAt", "<=", "2024-11-13").Scan(&users)
  65. collection := global.App.MongoDB.Database("chunhao").Collection("adRelated")
  66. for _, user := range users {
  67. //查询出reids中的openId
  68. userIdKeys := fmt.Sprintf("%s:%s:%s:%v", user.Gid, user.Pf, config.Get("app.user_table_id"), strconv.Itoa(user.UserId))
  69. userIdData, _ := global.App.Redis.HGetAll(context.Background(), userIdKeys).Result()
  70. openId := userIdData["openId"]
  71. //openId = strconv.Itoa(user.UserId)
  72. //查询出在线时长数据
  73. var LogData []logData
  74. global.App.DB.Table("user_online").
  75. Where("pf", user.Pf).
  76. Where("gid", user.Gid).
  77. Where("userId", user.UserId).Scan(&LogData)
  78. duration := calculateUserOnlineTime(LogData)
  79. //查询出看广告数据
  80. var req_count int64
  81. var exp_count int64
  82. global.App.DB.Table("user_see_ads").
  83. Where("pf", user.Pf).
  84. Where("gid", user.Gid).
  85. Where("userId", user.UserId).Count(&req_count)
  86. global.App.DB.Table("user_see_ads").
  87. Where("pf", user.Pf).
  88. Where("gid", user.Gid).
  89. Where("adState", 2).
  90. Where("userId", user.UserId).Count(&exp_count)
  91. //查询出启动次数
  92. var start_num int64
  93. global.App.DB.Table("user_login").
  94. Where("pf", user.Pf).
  95. Where("gid", user.Gid).
  96. Where("userId", user.UserId).Count(&start_num)
  97. //存入mongo
  98. adData := struct {
  99. Id string `bson:"_id" json:"_id"`
  100. UserId string `bson:"userId" json:"userId"`
  101. Aid int64 `json:"aid" bson:"aid"` //广告的推广计划id,即广告ID,广告平台配置落地页参数
  102. Cid string `json:"cid" bson:"cid"` //openid的用户点击aid广告进入游戏时的唯一标识,广告平台提供
  103. Pid int64 `json:"pid" bson:"pid"` //广告的项目id(仅巨量引擎存在,腾讯广告时不存在该值),广告平台配置落地页参数
  104. CreateTime int64 `bson:"create_time"` //当前计划的创建时间
  105. StartNum int `bson:"startNum" json:"startNum"` //启动次数
  106. Revenue float32 `bson:"revenue" json:"revenue"` //当日预估收益
  107. Duration int64 `bson:"duration" json:"duration"` //当日在线时长
  108. ReqCount int `bson:"req_count" json:"req_count"` //当日的激励视频广告请求次数
  109. ExpCount int `bson:"exp_count" json:"exp_count"` //当日的激励视频广告曝光次数
  110. }{
  111. UserId: user.Gid + "|" + user.Pf + "|" + openId,
  112. Id: user.Gid + "|" + user.Pf + "|" + openId + "|" + "7436301890621997000",
  113. Aid: 7436301890621997000,
  114. Pid: 0,
  115. Cid: "",
  116. Duration: duration,
  117. StartNum: int(start_num),
  118. Revenue: 0,
  119. ReqCount: int(req_count),
  120. ExpCount: int(exp_count),
  121. CreateTime: user.CreatedAt.Unix(),
  122. }
  123. collection.InsertOne(context.Background(), adData)
  124. fmt.Println(user.Gid+"|"+user.Pf+"|"+openId, "数据写入完成\n")
  125. }
  126. }
  127. func DeleteUserBehaviorBak(c *gin.Context) {
  128. collection := global.App.MongoDB.Database("chunhao").Collection("userBehavior")
  129. filter := bson.M{"create_time": bson.M{"$gt": 1}}
  130. collection.DeleteMany(context.Background(), filter)
  131. response.Success(c, gin.H{})
  132. }
  133. func GetUserNickName(c *gin.Context) {
  134. //读取user表
  135. var count int64
  136. err := global.App.DB.Table("user").Count(&count).Error
  137. if err != nil {
  138. response.Fail(c, 1001, err.Error())
  139. return
  140. }
  141. var i int64
  142. for i = 1; i <= count; i++ {
  143. var user model.User
  144. err = global.App.DB.Table("user").Where("id", i).Find(&user).Error
  145. if err != nil {
  146. response.Fail(c, 1001, err.Error())
  147. return
  148. }
  149. if user.Pf == "web" {
  150. //web跳过
  151. continue
  152. }
  153. userKey := user.Gid + ":" + user.Pf + ":" + config.Get("app.user_table_key") + user.OpenId
  154. userData, err := global.App.Redis.HGetAll(context.Background(), userKey).Result()
  155. if err != nil {
  156. global.App.Log.Error("GetUserData err")
  157. response.Fail(c, 1003, "GetUserData err"+err.Error())
  158. return
  159. }
  160. if userData["head"] != "" {
  161. //有意义的数据
  162. //data := struct {
  163. // ID int `json:"id" gorm:"not null;"`
  164. // Head string `json:"head" gorm:"not null;"`
  165. // NickName string `json:"nickName" gorm:"not null;column:nickName;"`
  166. //}{
  167. // Head: userData["head"],
  168. // NickName: userData["nickName"],
  169. //}
  170. //err = global.App.DB.Table("nickname").Create(&data).Error
  171. //if err != nil {
  172. // response.Fail(c, 1003, "nickname err"+err.Error())
  173. // return
  174. //}
  175. }
  176. }
  177. response.Success(c, gin.H{})
  178. }
  179. // 定义一个函数来执行任务
  180. func WriteDBDataToFile(c *gin.Context) {
  181. // 打开文件准备写入
  182. file, err := os.Create("./nickname.txt")
  183. if err != nil {
  184. response.Fail(c, 1001, fmt.Errorf("无法创建文件: %v", err))
  185. }
  186. defer file.Close()
  187. // 查询数据库
  188. var data []struct {
  189. ID int `json:"id" gorm:"not null;"`
  190. Head string `json:"head" gorm:"not null;"`
  191. NickName string `json:"nickName" gorm:"not null;column:nickName;"`
  192. }
  193. global.App.DB.Table("nickname").Scan(&data)
  194. // 写入列名到文件(可选)
  195. for _, v := range data {
  196. fmt.Println(v)
  197. fmt.Fprintf(file, "%s\t%s\n", v.NickName, v.Head)
  198. }
  199. response.Success(c, gin.H{})
  200. }
  201. // 对打点数据进行汇算
  202. func ActionDataSummary(c *gin.Context) {
  203. now := time.Now()
  204. for i := 1; i <= 30; i++ {
  205. lastDay := now.AddDate(0, 0, -i).Format("20060102")
  206. service.SeeAdsSummary(lastDay)
  207. fmt.Println("用时", time.Since(now))
  208. }
  209. response.Success(c, gin.H{})
  210. }
  211. func BehaviorTimeSummary(c *gin.Context) {
  212. //先查出所有gid
  213. ActiveGid := service.GetActiveGid()
  214. //现在直接汇总所有的数据(直到前一天的)
  215. now := time.Now()
  216. end := now.AddDate(0, 0, -1)
  217. start, _ := time.Parse("2006-01-02 15:04:05", "2025-05-17 15:04:05")
  218. crons.BehaviorSummary("wx", ActiveGid, start, end)
  219. global.App.Log.Info("重新汇总用户在线时长数据完成")
  220. response.Success(c, gin.H{})
  221. }
  222. func BehaviorSummary(c *gin.Context) {
  223. //先查出所有gid
  224. ActiveGid := service.GetActiveGid()
  225. now := time.Now().AddDate(0, 0, -1)
  226. start := now.AddDate(0, 0, -45)
  227. pf := "wx"
  228. //循环一下,查出userId 跟相关的在线数据
  229. for _, gid := range ActiveGid {
  230. start1 := time.Now()
  231. fmt.Println("处理数据开始,gid :", gid)
  232. //查询 30天内的在线数据
  233. SummaryData, err := service.UserOnlineSummary(gid, pf, "", start.Format("2006-01-02 15:04:05"), now.Format("2006-01-02 15:04:05"))
  234. if err != nil {
  235. response.Fail(c, 1001, err.Error())
  236. return
  237. }
  238. //aaa, _ := json.Marshal(SummaryData)
  239. //global.App.Log.Error(string(aaa))
  240. //
  241. //return
  242. fmt.Println("查询在线数据完成:", time.Since(start1))
  243. //查询用户的登录次数
  244. var loginData []struct {
  245. UserId int `json:"userId" gorm:"not null;column:userId;"`
  246. LoginCount int `json:"loginCount" gorm:"not null;column:loginCount;"`
  247. }
  248. loginDataMap := make(map[int]int)
  249. err = global.App.DB.Table("user_login").
  250. Where("gid", gid).
  251. Where("pf", pf).
  252. Group("userId").
  253. Select("count(*) as loginCount", "userId").
  254. Scan(&loginData).Error
  255. if err != nil {
  256. response.Fail(c, 1002, err.Error())
  257. return
  258. }
  259. for _, login := range loginData {
  260. loginDataMap[login.UserId] = login.LoginCount
  261. }
  262. fmt.Println("查询登录数据完成:", time.Since(start1))
  263. //查询用户的看广告次数,广告看完次数
  264. var seeAdsData []struct {
  265. UserId int `json:"userId" gorm:"not null;column:userId;"`
  266. SeeAdsCount int `json:"seeAdsCount" gorm:"not null;column:seeAdsCount;"`
  267. State2Count int `json:"state2Count" gorm:"not null;column:state2Count;"`
  268. }
  269. seeAdsDataMap := make(map[int]int)
  270. seeAdsDataMap2 := make(map[int]int)
  271. err = global.App.DB.Table("user_see_ads").
  272. Where("gid", gid).
  273. Where("pf", pf).
  274. Group("userId").
  275. Select("count(*) as seeAdsCount", "SUM(CASE WHEN adsState = 2 THEN 1 ELSE 0 END) AS state2Count", "userId").
  276. Scan(&seeAdsData).Error
  277. if err != nil {
  278. response.Fail(c, 1003, err.Error())
  279. return
  280. }
  281. for _, ads := range seeAdsData {
  282. seeAdsDataMap[ads.UserId] = ads.SeeAdsCount
  283. seeAdsDataMap2[ads.UserId] = ads.State2Count
  284. }
  285. fmt.Println("查询广告数据完成:", time.Since(start1))
  286. //格式化,存入数据库
  287. var userIdList []model.User
  288. err = global.App.DB.Table("user").Where("gid", gid).
  289. Select("id", "userId").
  290. Where("pf", pf).Scan(&userIdList).Error
  291. if err != nil {
  292. response.Fail(c, 1004, err.Error())
  293. return
  294. }
  295. //fmt.Println(len(userIdList))
  296. userBehavior := make(map[int]model.UserBehavior)
  297. for _, users := range userIdList {
  298. userBehavior[users.UserId] = model.UserBehavior{
  299. ID: users.ID,
  300. Duration: int(SummaryData[users.UserId]),
  301. StartNum: loginDataMap[users.UserId],
  302. AdCount: seeAdsDataMap[users.UserId],
  303. AdExpCount: seeAdsDataMap2[users.UserId],
  304. }
  305. }
  306. var userBehaviorList []model.UserBehavior
  307. for _, Behavior := range userBehavior {
  308. userBehaviorList = append(userBehaviorList, Behavior)
  309. }
  310. err = global.App.DB.Table("user_behavior").Clauses(clause.OnConflict{
  311. Columns: []clause.Column{{Name: "id"}}, // 冲突列(主键)
  312. DoUpdates: clause.AssignmentColumns([]string{"duration", "startNum", "adCount", "adExpCount"}), // 需要更新的列
  313. }).CreateInBatches(&userBehaviorList, 1000).Error
  314. if err != nil {
  315. //global.App.Log.Error(userBehavior)
  316. response.Fail(c, 1005, err.Error())
  317. return
  318. }
  319. fmt.Println("存入汇总完成:", time.Since(start1))
  320. }
  321. }
  322. func TestClickHouse(c *gin.Context) {
  323. sql := "CREATE TABLE user_see_ads\n(\n `pf` LowCardinality(String) COMMENT '登录路径',\n `gid` LowCardinality(String) COMMENT '游戏ID',\n `userId` UInt32 COMMENT '用户ID',\n `date` Date COMMENT '日期',\n `createdAt` DateTime DEFAULT now() COMMENT '时间',\n `adsId` Nullable(String) COMMENT '广告ID',\n \n -- 修复字段声明顺序:Nullable 应包裹 LowCardinality\n `adsType` LowCardinality(Nullable(String)) COMMENT '类型',\n `adsScene` LowCardinality(Nullable(String)) COMMENT '广告场景',\n \n `adsState` Nullable(Int8) COMMENT '广告状态: 0失败 1成功 2完整观看',\n `startTime` Nullable(DateTime) COMMENT '广告开始时间',\n `cost` UInt32 DEFAULT 0 COMMENT '广告收益'\n)\nENGINE = MergeTree()\nPARTITION BY (toYear(date), toMonth(date))\nORDER BY (date, pf, gid, userId)\nPRIMARY KEY (date, pf, gid)\nSETTINGS \n index_granularity = 8192,\n index_granularity_bytes = 10485760;\n"
  324. err := global.App.Clickhouse.Exec(sql).Error
  325. response.Success(c, gin.H{
  326. "res": err,
  327. })
  328. }