condrule.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "go-common/app/job/live/xroom-feed/internal/model"
  6. daoAnchorV1 "go-common/app/service/live/dao-anchor/api/grpc/v1"
  7. "go-common/library/log"
  8. )
  9. const (
  10. _isAll = -1
  11. _roomStatusTagId = 3
  12. _onlineCurrent = 3
  13. )
  14. type attrFilter struct {
  15. attrId int64
  16. attrSubId int64
  17. max int64
  18. min int64
  19. top int64
  20. }
  21. var attrType = map[string]int64{
  22. _onlineType: 1,
  23. _incomeType: 2,
  24. _dmsType: 3,
  25. _hourRankType: 4,
  26. _liveDaysType: 5,
  27. }
  28. var tagType = map[string]bool{
  29. _areaType: true,
  30. _roomStatusType: true,
  31. _anchorCateType: true,
  32. }
  33. type filterItem struct {
  34. isTagHit bool
  35. item *daoAnchorV1.AttrResp
  36. }
  37. // ParentAreaIds ...
  38. var ParentAreaIds []int64
  39. // AreaIds ...
  40. var AreaIds [][]int64
  41. // getConditionTypeIndex ...
  42. func (s *Service) getConditionTypeIndex(conds []*model.RuleProtocol, sType string) (i int64) {
  43. i = -1
  44. for index, cond := range conds {
  45. if cond == nil {
  46. continue
  47. }
  48. if cond.ConfType == sType {
  49. i = int64(index)
  50. break
  51. }
  52. }
  53. return
  54. }
  55. // genCondConfRoomList ... recId for log
  56. func (s *Service) genCondConfRoomList(ctx context.Context, Condition []*model.RuleProtocol, Cond string, recId int) (roomIds []int64) {
  57. ParentAreaIds := make([]int64, 0)
  58. AreaIds := make([][]int64, 0)
  59. areaFilter := make(map[int64]map[int64]bool)
  60. roomStatus := make(map[int64]bool)
  61. anchorCate := make(map[int64]bool)
  62. attrs := make([]*daoAnchorV1.AttrReq, 0)
  63. attrsFilter := make(map[int64]map[int64]*attrFilter)
  64. for _, cond := range Condition {
  65. // 统计型标签
  66. if attrTypeV, ok := attrType[cond.Key]; ok {
  67. isAppend := true
  68. param := &daoAnchorV1.AttrReq{
  69. AttrId: attrTypeV,
  70. }
  71. if len(cond.Condition) <= 0 || cond.Condition[0] == nil {
  72. continue
  73. }
  74. if cond.Key == _onlineType {
  75. switch cond.Condition[0].StringV {
  76. case "current":
  77. param.AttrSubId = 1
  78. case "last7day":
  79. param.AttrSubId = 2
  80. case "last30day":
  81. param.AttrSubId = 3
  82. }
  83. }
  84. if cond.Key == _incomeType || cond.Key == _dmsType {
  85. switch cond.Condition[0].StringV {
  86. case "range15min":
  87. param.AttrSubId = 1
  88. case "range30min":
  89. param.AttrSubId = 2
  90. case "range45min":
  91. param.AttrSubId = 3
  92. case "range60min":
  93. param.AttrSubId = 4
  94. }
  95. }
  96. if cond.Key == _liveDaysType {
  97. switch cond.Condition[0].StringV {
  98. case "last7day":
  99. param.AttrSubId = 3
  100. case "last30day":
  101. param.AttrSubId = 4
  102. }
  103. }
  104. if cond.Key == _hourRankType {
  105. if cond.Condition[0].TopV <= 0 {
  106. isAppend = false
  107. }
  108. param.AttrSubId = 1 // 目前小时榜固定是1 @orca
  109. }
  110. // 排除后台选择了小时榜,但是top写了0,导致dao anchor不返回这个attr,导致下面and or 过滤出错
  111. if isAppend {
  112. attrsFilter[attrTypeV] = make(map[int64]*attrFilter)
  113. attrsFilter[attrTypeV][param.AttrSubId] = &attrFilter{}
  114. if i := s.getConditionTypeIndex(cond.Condition, _confTypeRange); i >= 0 && cond.Condition[i] != nil {
  115. attrsFilter[attrTypeV][param.AttrSubId].max = cond.Condition[i].Max
  116. attrsFilter[attrTypeV][param.AttrSubId].min = cond.Condition[i].Min
  117. }
  118. if i := s.getConditionTypeIndex(cond.Condition, _confTypeTop); i >= 0 && cond.Condition[i] != nil {
  119. attrsFilter[attrTypeV][param.AttrSubId].top = cond.Condition[i].TopV
  120. }
  121. attrs = append(attrs, param)
  122. }
  123. }
  124. // 展示型标签
  125. if _, ok := tagType[cond.Key]; ok {
  126. if cond.Key == _areaType {
  127. for index, areaCond := range cond.Condition {
  128. // parent area id dimension
  129. if index == 0 {
  130. err := json.Unmarshal([]byte(areaCond.StringV), &ParentAreaIds)
  131. if err != nil {
  132. log.Error("[genCondConfRoomList]recId:%d, unmarshalParentAreaIdErr:%+v", recId, err)
  133. continue
  134. }
  135. if len(ParentAreaIds) == 1 && ParentAreaIds[0] == _isAll {
  136. areaFilter[_isAll] = make(map[int64]bool)
  137. break
  138. }
  139. for _, pId := range ParentAreaIds {
  140. if _, ok := areaFilter[pId]; !ok {
  141. areaFilter[pId] = make(map[int64]bool)
  142. }
  143. }
  144. }
  145. // area id dimension
  146. if index == 1 {
  147. err := json.Unmarshal([]byte(areaCond.StringV), &AreaIds)
  148. if err != nil {
  149. log.Error("[genCondConfRoomList]recId:%d, unmarshalAreaIdErr:%+v", recId, err)
  150. continue
  151. }
  152. for pIdIndex, ids := range AreaIds {
  153. // 后台保证长度对应 ParentAreaId[pIdIndex]
  154. if len(ParentAreaIds) <= pIdIndex {
  155. continue
  156. }
  157. if _, ok := areaFilter[ParentAreaIds[pIdIndex]]; !ok {
  158. continue
  159. }
  160. for _, id := range ids {
  161. if _, ok := areaFilter[ParentAreaIds[pIdIndex]][id]; !ok {
  162. areaFilter[ParentAreaIds[pIdIndex]][id] = true
  163. }
  164. }
  165. }
  166. }
  167. }
  168. }
  169. if cond.Key == _roomStatusType && len(cond.Condition) >= 0 && cond.Condition[0] != nil {
  170. switch cond.Condition[0].StringV {
  171. case "lottery":
  172. roomStatus[2] = true
  173. case "pk":
  174. roomStatus[1] = true
  175. }
  176. }
  177. if cond.Key == _anchorCateType && len(cond.Condition) >= 0 && cond.Condition[0] != nil {
  178. switch cond.Condition[0].StringV {
  179. case "normal":
  180. anchorCate[0] = true
  181. case "sign":
  182. anchorCate[1] = true
  183. case "union":
  184. anchorCate[2] = true
  185. }
  186. }
  187. }
  188. }
  189. log.Info("[genCondConfRoomList]recId:%d, attrs: %+v", recId, attrs)
  190. roomList, err := s.getOnlineListByAttrs(ctx, attrs)
  191. if err != nil {
  192. log.Error("[getOnlineListByAttrs]recId:%d, getOnlineListByAttrsErr:%+v, resp:%+v", recId, err, roomList)
  193. return
  194. }
  195. filterRoomData := make([]*filterItem, 0)
  196. for _, roomData := range roomList {
  197. isHit := false
  198. isTagHit := false
  199. if Cond == _condAnd {
  200. isHit = s.andFilter(attrsFilter, areaFilter, roomStatus, anchorCate, roomData, recId)
  201. }
  202. if Cond == _condOr {
  203. isHit, isTagHit = s.orFilter(attrsFilter, areaFilter, roomStatus, anchorCate, roomData, recId)
  204. }
  205. if !isHit {
  206. continue
  207. }
  208. // 命中逻辑
  209. filterRoomData = append(filterRoomData, &filterItem{
  210. isTagHit: isTagHit,
  211. item: roomData,
  212. })
  213. }
  214. return s.sort(attrsFilter, filterRoomData, Cond, recId)
  215. }
  216. func (s *Service) andFilter(attrsFilters map[int64]map[int64]*attrFilter, areaFilter map[int64]map[int64]bool, roomStatus, anchorCate map[int64]bool, roomData *daoAnchorV1.AttrResp, recId int) (isHit bool) {
  217. // area filter
  218. if len(areaFilter) > 0 {
  219. _, isParentAll := areaFilter[_isAll]
  220. // 不是全选继续判断
  221. if !isParentAll {
  222. if _, ok := areaFilter[roomData.ParentAreaId]; !ok {
  223. log.Info("[andFilter]recId:%d, ParentAreaIdNotMatch:areaFilter:%+v, parentId:%d, roomId:%d", recId, areaFilter, roomData.ParentAreaId, roomData.RoomId)
  224. return false
  225. }
  226. _, isAreaAll := areaFilter[roomData.ParentAreaId][_isAll]
  227. _, isAreaIdExist := areaFilter[roomData.ParentAreaId][roomData.AreaId]
  228. if !isAreaAll && !isAreaIdExist {
  229. log.Info("[andFilter]recId:%d, AreaIdNotMatch:areaFilter:%+v, Id:%d, roomId:%d", recId, areaFilter, roomData.AreaId, roomData.RoomId)
  230. return false
  231. }
  232. }
  233. }
  234. //如果配置了房间状态筛选
  235. if len(roomStatus) > 0 {
  236. roomStatusTag := &daoAnchorV1.TagData{}
  237. for _, tag := range roomData.TagList {
  238. if tag.TagId == _roomStatusTagId {
  239. roomStatusTag = tag
  240. break
  241. }
  242. }
  243. if _, ok := roomStatus[roomStatusTag.TagSubId]; !ok {
  244. log.Info("[andFilter]recId:%d, roomStatusNotMatch:roomStatus:%+v, tagSubId:%d, roomId:%d", recId, roomStatus, roomStatusTag.TagSubId, roomData.RoomId)
  245. return false
  246. }
  247. }
  248. //如果配置了主播类型筛选
  249. if len(anchorCate) > 0 {
  250. if _, ok := anchorCate[roomData.AnchorProfileType]; !ok {
  251. log.Info("[andFilter]recId:%d, anchorCateNotMatch:anchorCate:%+v, anchorProfileType:%d, roomId:%d", recId, anchorCate, roomData.AnchorProfileType, roomData.RoomId)
  252. return false
  253. }
  254. }
  255. // attr(统计类) filter
  256. attrsMap := make(map[int64]*daoAnchorV1.AttrData)
  257. for _, attr := range roomData.AttrList {
  258. attrsMap[attr.AttrId] = attr
  259. }
  260. for attrId, attrFilter := range attrsFilters {
  261. if _, ok := attrsMap[attrId]; !ok {
  262. log.Info("[andFilter]recId:%d, attrNotExist:attrId:%d, attrFilter:%d, roomID:%d", recId, attrId, attrsMap, roomData.RoomId)
  263. return false
  264. }
  265. for attrSubId, attrInfo := range attrFilter {
  266. if attrInfo == nil {
  267. continue
  268. }
  269. if attrsMap[attrId].AttrSubId == attrSubId {
  270. if attrInfo.min > 0 && attrsMap[attrId].AttrValue < attrInfo.min {
  271. log.Info("[andFilter]recId:%d, attrMinNotMatch:attrId:%d, value:%d, max:%d, min:%d, roomID:%d", recId, attrId, attrsMap[attrId].AttrValue, attrInfo.max, attrInfo.min, roomData.RoomId)
  272. return false
  273. }
  274. if attrInfo.max > 0 && attrsMap[attrId].AttrValue > attrInfo.max {
  275. log.Info("[andFilter]recId:%d, attrMaxNotMatch:attrId:%d, value:%d, max:%d, min:%d, roomID:%d", recId, attrId, attrsMap[attrId].AttrValue, attrInfo.max, attrInfo.min, roomData.RoomId)
  276. return false
  277. }
  278. }
  279. }
  280. }
  281. log.Info("[andFilter]recId:%d, successMatch:roomData:%+v,attrs:%+v, areaFilter:%+v, roomStatus:%+v, anchorState:%+v, roomID:%d", recId, roomData, attrsFilters, areaFilter, roomStatus, anchorCate, roomData.RoomId)
  282. return true
  283. }
  284. func (s *Service) orFilter(attrsFilters map[int64]map[int64]*attrFilter, areaFilter map[int64]map[int64]bool, roomStatus, anchorCate map[int64]bool, roomData *daoAnchorV1.AttrResp, recId int) (isHit bool, isTagHit bool) {
  285. // area filter
  286. isTagHit = false
  287. if len(areaFilter) > 0 {
  288. if _, ok := areaFilter[_isAll]; ok {
  289. log.Info("[orFilter]recId:%d, ParentAreaIdAllMatch:areaFilter:%+v, parentId:%d, roomID:%d", recId, areaFilter, roomData.ParentAreaId, roomData.RoomId)
  290. isTagHit = true
  291. return true, isTagHit
  292. }
  293. if _, ok := areaFilter[roomData.ParentAreaId]; ok {
  294. log.Info("[orFilter]recId:%d, ParentAreaIdMatch:areaFilter:%+v, parentId:%d, roomID:%d", recId, areaFilter, roomData.ParentAreaId, roomData.RoomId)
  295. isTagHit = true
  296. return true, isTagHit
  297. }
  298. _, isAll := areaFilter[roomData.ParentAreaId][_isAll]
  299. _, isAreaIdExist := areaFilter[roomData.ParentAreaId][roomData.AreaId]
  300. if isAll || isAreaIdExist {
  301. log.Info("[orFilter]recId:%d, AreaIdMatch:areaFilter:%+v, Id:%d, roomID:%d", recId, areaFilter, roomData.AreaId, roomData.RoomId)
  302. isTagHit = true
  303. return true, isTagHit
  304. }
  305. }
  306. //如果配置了房间状态筛选
  307. if len(roomStatus) > 0 {
  308. roomStatusTag := &daoAnchorV1.TagData{}
  309. for _, tag := range roomData.TagList {
  310. if tag.TagId == _roomStatusTagId {
  311. roomStatusTag = tag
  312. break
  313. }
  314. }
  315. if _, ok := roomStatus[roomStatusTag.TagSubId]; ok {
  316. log.Info("[orFilter]recId:%d, roomStatusMatch:roomStatus:%+v, tagSubId:%d, roomID:%d", recId, roomStatus, roomStatusTag.TagSubId, roomData.RoomId)
  317. isTagHit = true
  318. return true, isTagHit
  319. }
  320. }
  321. //如果配置了主播类型筛选
  322. if len(anchorCate) > 0 {
  323. if _, ok := anchorCate[roomData.AnchorProfileType]; ok {
  324. log.Info("[orFilter]recId:%d, anchorCateMatch:anchorCate:%+v, anchorProfileType:%d, roomID:%d", recId, anchorCate, roomData.AnchorProfileType, roomData.RoomId)
  325. isTagHit = true
  326. return true, isTagHit
  327. }
  328. }
  329. // attr filter
  330. attrDataMap := make(map[int64]*daoAnchorV1.AttrData)
  331. for _, attr := range roomData.AttrList {
  332. attrDataMap[attr.AttrId] = attr
  333. }
  334. for attrId, attrFilter := range attrsFilters {
  335. if _, ok := attrDataMap[attrId]; !ok {
  336. continue
  337. }
  338. //小时榜不需要判断max min
  339. if attrId == attrType[_hourRankType] {
  340. return true, isTagHit
  341. }
  342. for attrSubId, attrFilterInfo := range attrFilter {
  343. attrData, ok := attrDataMap[attrId]
  344. if !ok {
  345. continue
  346. }
  347. if attrData.AttrSubId == attrSubId {
  348. if attrFilterInfo.min > 0 && attrData.AttrValue < attrFilterInfo.min {
  349. continue
  350. }
  351. if attrFilterInfo.max > 0 && attrData.AttrValue > attrFilterInfo.max {
  352. continue
  353. }
  354. log.Info("[orFilter]recId:%d, attrMaxMinMatch:attrId:%d, value:%d, max:%d, min:%d, roomID:%d", recId, attrId, attrDataMap[attrId].AttrValue, attrFilterInfo.max, attrFilterInfo.min, roomData.RoomId)
  355. return true, isTagHit
  356. }
  357. }
  358. }
  359. log.Info("[orFilter]recId:%d, failMatch:roomData:%+v,attrs:%+v, areaFilter:%+v, roomStatus:%+v, anchorState:%+v, roomId:%d", recId, roomData, attrsFilters, areaFilter, roomStatus, anchorCate, roomData.RoomId)
  360. return false, isTagHit
  361. }