123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- package upcrmservice
- import (
- "context"
- "errors"
- "sync"
- "time"
- "go-common/app/admin/main/up/dao/global"
- "go-common/app/admin/main/up/model/datamodel"
- "go-common/app/admin/main/up/model/upcrmmodel"
- "go-common/app/admin/main/up/util"
- accgrpc "go-common/app/service/main/account/api"
- "go-common/library/database/elastic"
- "go-common/library/log"
- "go-common/library/net/metadata"
- "go-common/library/sync/errgroup"
- )
- const (
- maxSearchItemCount = 10000
- maxBatchCount = 100
- )
- var (
- //ErrTooManySearchItem too many search items, 搜索只支持返回前10000条数据
- ErrTooManySearchItem = errors.New("筛选仅支持展示前1万条")
- //ErrNoMid no mid
- ErrNoMid = errors.New("Mid为空")
- )
- //UpBaseInfoQuery query
- func (s *Service) UpBaseInfoQuery(context context.Context, arg *upcrmmodel.InfoQueryArgs) (result *upcrmmodel.InfoQueryResult, err error) {
- var data, e = s.upBaseInfoQueryBatch(s.crmdb.QueryUpBaseInfoBatchByMid, arg.Mid)
- err = e
- // 没找到按照错误处理
- if err != nil || len(data) == 0 {
- log.Error("get from db fail, req=%+v, err=%+v", arg, err)
- return
- }
- result = data[0]
- log.Info("query base info ok, req=%+v, err=%+v", arg, result)
- return
- }
- //QueryDbFunc query func type
- type QueryDbFunc func(fields string, mid ...int64) (result []upcrmmodel.UpBaseInfo, err error)
- func (s *Service) upBaseInfoQueryBatch(queryfunc QueryDbFunc, ids ...int64) (result []*upcrmmodel.InfoQueryResult, err error) {
- var data, e = queryfunc("*", ids...)
- err = e
- if err != nil {
- log.Error("get from db fail, err=%+v", err)
- return
- }
- for _, v := range data {
- var info = upcrmmodel.InfoQueryResult{}
- info.CopyFromBaseInfo(v)
- info.CalculateAttr()
- result = append(result, &info)
- }
- return
- }
- // UpAccountInfo get account info
- func (s *Service) UpAccountInfo(c context.Context, arg *upcrmmodel.InfoAccountInfoArgs) (res []*accgrpc.Info, err error) {
- var (
- infosReply *accgrpc.InfosReply
- mids = util.ExplodeInt64(arg.Mids, ",")
- )
- if infosReply, err = global.GetAccClient().Infos3(c, &accgrpc.MidsReq{Mids: mids, RealIp: metadata.String(c, metadata.RemoteIP)}); err != nil {
- return
- }
- if infosReply == nil || infosReply.Infos == nil {
- return
- }
- for _, v := range infosReply.Infos {
- res = append(res, v)
- }
- log.Info("query acount info ok, req=%+v, result=%+v", arg, res)
- return
- }
- //SearchResult struct
- type SearchResult struct {
- AccountState int `json:"account_state"`
- Activity int `json:"activity"`
- Attr int `json:"attr"`
- ArticleCountAccumulate int `json:"article_count_accumulate"`
- ID uint32
- Mid int64
- }
- func getAttrFormat(attrs upcrmmodel.UpAttr) (result []int) {
- // 什么要shift,因为es的位是从1开始的,而存储的位是从0开始的
- const shift = 1
- if attrs.AttrVideo != 0 {
- result = append(result, upcrmmodel.AttrBitVideo+shift)
- }
- if attrs.AttrAudio != 0 {
- result = append(result, upcrmmodel.AttrBitAudio+shift)
- }
- if attrs.AttrArticle != 0 {
- result = append(result, upcrmmodel.AttrBitArticle+shift)
- }
- if attrs.AttrPhoto != 0 {
- result = append(result, upcrmmodel.AttrBitPhoto+shift)
- }
- if attrs.AttrSign != 0 {
- result = append(result, upcrmmodel.AttrBitSign+shift)
- }
- if attrs.AttrGrowup != 0 {
- result = append(result, upcrmmodel.AttrBitGrowup+shift)
- }
- if attrs.AttrVerify != 0 {
- result = append(result, upcrmmodel.AttrBitVerify+shift)
- }
- return
- }
- func getEsCombo(attrs upcrmmodel.UpAttr) (combos []*elastic.Combo) {
- const shift = 1
- var attrs1, attrs2 []interface{}
- var attrFlagList = getAttrFormat(attrs)
- for _, v := range attrFlagList {
- if _, ok := upcrmmodel.AttrGroup1[v-shift]; ok {
- attrs1 = append(attrs1, v)
- } else if _, ok := upcrmmodel.AttrGroup2[v-shift]; ok {
- attrs2 = append(attrs2, v)
- }
- }
- if attrs1 != nil {
- var attrGroup = make(map[string][]interface{})
- attrGroup["attr_format"] = attrs1
- cmb := &elastic.Combo{}
- cmb.ComboIn([]map[string][]interface{}{
- attrGroup},
- ).MinIn(1).MinAll(1)
- combos = append(combos, cmb)
- }
- if attrs2 != nil {
- var attrGroup = make(map[string][]interface{})
- attrGroup["attr_format"] = attrs2
- cmb := &elastic.Combo{}
- cmb.ComboIn([]map[string][]interface{}{
- attrGroup},
- ).MinIn(1).MinAll(1)
- combos = append(combos, cmb)
- }
- return
- }
- //UpInfoSearch info search
- func (s *Service) UpInfoSearch(c context.Context, arg *upcrmmodel.InfoSearchArgs) (result upcrmmodel.InfoSearchResult, err error) {
- //调用搜索的接口
- var searchData esResult
- searchData, err = s.searchFromEs(c, arg)
- if err != nil {
- log.Error("search arg=%+v, err=%+v", arg, err)
- return
- }
- if len(searchData.Result) == 0 {
- log.Info("no data return from search, just return")
- return
- }
- var ids []int64
- for _, v := range searchData.Result {
- ids = append(ids, int64(v.ID))
- }
- result.Result, err = s.queryUpBaseInfo(c, ids...)
- if err != nil {
- log.Error("query up base info fail, err=%+v", err)
- return
- }
- result.PageInfo = searchData.Page.ToPageInfo()
- log.Info("res=%+v, page=%+v", searchData, result.PageInfo)
- return
- }
- type esPage struct {
- Num int `json:"num"`
- Size int `json:"size"`
- Total int `json:"total"`
- }
- //ToPageInfo cast to page info
- func (e *esPage) ToPageInfo() (pageInfo upcrmmodel.PageInfo) {
- if e == nil {
- return
- }
- pageInfo.TotalCount = e.Total
- pageInfo.Size = e.Size
- pageInfo.Page = e.Num
- return
- }
- type esResult struct {
- Page *esPage `json:"page"`
- Result []*SearchResult `json:"result"`
- }
- func (s *Service) searchFromEs(c context.Context, arg *upcrmmodel.InfoSearchArgs) (searchData esResult, err error) {
- if arg.Page*arg.Size > maxSearchItemCount {
- err = ErrTooManySearchItem
- return
- }
- var searchSdk = elastic.NewElastic(nil)
- var r = searchSdk.NewRequest("up_crm_info")
- r.Pn(arg.Page).Ps(arg.Size).Index("up_base_info").
- Fields("id")
- if arg.Mid != 0 {
- r.WhereEq("mid", arg.Mid)
- } else {
- if arg.AccountState != 0 {
- // 字段有0值,所以接口改为1,2表示字段的0,1,接口的0表示没有此条件
- var realArg = arg.AccountState - 1
- r.WhereEq("account_state", realArg)
- }
- if arg.Activity != 0 {
- r.WhereEq("activity", arg.Activity)
- }
- var startdate, _ = time.Parse(upcrmmodel.TimeFmtDate, arg.FirstDateBegin)
- var enddate, _ = time.Parse(upcrmmodel.TimeFmtDate, arg.FirstDateEnd)
- enddate = enddate.AddDate(0, 0, 1)
- var startStr = startdate.Format(upcrmmodel.TimeFmtMysql)
- var endStr = enddate.Format(upcrmmodel.TimeFmtMysql)
- if arg.FirstDateBegin != "" && arg.FirstDateEnd != "" {
- r.WhereRange("first_up_time", startStr, endStr, elastic.RangeScopeLcRc)
- }
- if arg.Order.Order == "" {
- arg.Order.Order = "desc"
- }
- if arg.Order.Field == "" {
- arg.Order.Field = "first_up_time"
- arg.Order.Order = "desc"
- }
- var combos = getEsCombo(arg.Attrs)
- r.WhereCombo(combos...)
- r.Order(arg.Order.Field, arg.Order.Order)
- }
- err = r.Scan(c, &searchData)
- return
- }
- func (s *Service) queryUpBaseInfo(c context.Context, ids ...int64) (result []*upcrmmodel.InfoQueryResult, err error) {
- var group, ctx = errgroup.WithContext(c)
- var infoData []*upcrmmodel.InfoQueryResult
- group.Go(func() error {
- var e error
- infoData, e = s.upBaseInfoQueryBatch(s.crmdb.QueryUpBaseInfoBatchByID, ids...)
- if e != nil {
- err = e
- log.Error("get base info fail, err=%+v", err)
- }
- return nil
- })
- var tidMap = make(map[int64]*datamodel.UpArchiveTypeData)
- var mapLock sync.Mutex
- for _, mid := range ids {
- group.Go(func() error {
- var arg = datamodel.GetUpArchiveTypeInfoArg{Mid: mid}
- var tidData, e = s.dataService.GetUpArchiveTypeInfo(ctx, &arg)
- if e != nil || tidData == nil {
- log.Error("get up type info err, err=%v", e)
- return nil
- }
- mapLock.Lock()
- tidMap[arg.Mid] = tidData
- mapLock.Unlock()
- return nil
- })
- }
- if err = group.Wait(); err != nil {
- log.Error("get data error, err=%v", err)
- return
- }
- var infoIDMap = make(map[uint32]*upcrmmodel.InfoQueryResult)
- for _, v := range infoData {
- infoIDMap[v.ID] = v
- }
- for _, v := range ids {
- var info, ok = infoIDMap[uint32(v)]
- if !ok {
- continue
- }
- if typeInfo, ok := tidMap[v]; ok {
- info.ActiveTid = typeInfo.Tid
- info.ActiveSubtid = typeInfo.SubTid
- }
- result = append(result, info)
- }
- return
- }
- //QueryUpInfoWithViewerData query with view data
- func (s *Service) QueryUpInfoWithViewerData(c context.Context, arg *upcrmmodel.UpInfoWithViewerArg) (result upcrmmodel.UpInfoWithViewerResult, err error) {
- if arg.Page*arg.Size > maxSearchItemCount {
- err = ErrTooManySearchItem
- return
- }
- // 如果是0,则默认设置所有的tag
- if arg.Flag == 0 {
- arg.Flag = -1
- }
- var mids []int64
- if arg.Mids != "" {
- mids = util.ExplodeInt64(arg.Mids, ",")
- var midlen = len(mids)
- if midlen == 0 {
- err = ErrNoMid
- log.Error("no mid get from mids, arg=%+v", arg)
- return
- }
- if midlen > maxBatchCount {
- mids = mids[:maxBatchCount]
- }
- } else {
- var searchSdk = elastic.NewElastic(nil)
- var r = searchSdk.NewRequest("up_crm_info")
- if arg.Size > maxBatchCount {
- arg.Size = maxBatchCount
- }
- r.Pn(arg.Page).Ps(arg.Size).Index("up_base_info").
- Fields("mid").
- Order(arg.Sort, arg.Order)
- var searchData esResult
- err = r.Scan(c, &searchData)
- if err != nil {
- log.Error("fail to get from search, arg=%+v", arg)
- return
- }
- for _, v := range searchData.Result {
- mids = append(mids, int64(v.Mid))
- }
- result.PageInfo = searchData.Page.ToPageInfo()
- }
- var group, ctx = errgroup.WithContext(c)
- var infoData []*upcrmmodel.InfoQueryResult
- var playData []*upcrmmodel.UpPlayInfo
- group.Go(func() error {
- if arg.Flag&upcrmmodel.FlagUpBaseData != 0 {
- infoData, err = s.upBaseInfoQueryBatch(s.crmdb.QueryUpBaseInfoBatchByMid, mids...)
- if err != nil {
- log.Error("query up base error, err=%v", err)
- return err
- }
- }
- if arg.Flag&upcrmmodel.FlagUpPlayData != 0 {
- playData, err = s.crmdb.QueryPlayInfoBatch(mids, upcrmmodel.BusinessTypeVideo)
- if err != nil {
- log.Error("query play info err, err=%v", err)
- return err
- }
- }
- return nil
- })
- var dataMap = make(map[int64]*upcrmmodel.UpInfoWithViewerData)
- if arg.Flag&upcrmmodel.FlagViewData != 0 {
- for _, v := range mids {
- var mid = v // copy this v
- group.Go(func() error {
- var info, e = s.dataService.GetViewData(ctx, mid)
- if e != nil {
- err = e
- log.Error("query up view info from hbase error, err=%v", err)
- return err
- }
- var data = getOrCreateUpInfo(dataMap, mid)
- data.ViewerBase = info.Base
- data.ViewerTrend = info.Trend
- data.ViewerArea = info.Area
- return err
- })
- }
- }
- if err = group.Wait(); err != nil {
- log.Error("get data fail, err=%v", err)
- return
- }
- for _, baseInfo := range infoData {
- var data = getOrCreateUpInfo(dataMap, baseInfo.Mid)
- data.UpBaseInfo = baseInfo
- }
- for _, playInfo := range playData {
- var data = getOrCreateUpInfo(dataMap, playInfo.Mid)
- data.UpPlayInfo = playInfo
- }
- for _, mid := range mids {
- var data, ok = dataMap[mid]
- if !ok {
- log.Warn("up info not found, mid=%d", mid)
- continue
- }
- data.Mid = mid
- result.Result = append(result.Result, data)
- }
- log.Info("query up with view ok, arg=%+v, result count=%d", arg, len(mids))
- return
- }
- var dataMapMutex sync.Mutex
- func getOrCreateUpInfo(dataMap map[int64]*upcrmmodel.UpInfoWithViewerData, mid int64) (result *upcrmmodel.UpInfoWithViewerData) {
- dataMapMutex.Lock()
- defer dataMapMutex.Unlock()
- var ok bool
- if result, ok = dataMap[mid]; !ok {
- result = &upcrmmodel.UpInfoWithViewerData{}
- dataMap[mid] = result
- }
- return result
- }
|