package vidhkwsearcher import ( "91porn-server/common/constant" "errors" "fmt" "time" "91porn-server/app/service/searcher" "91porn-server/app/service/searcher/vidsearcher" "91porn-server/common" "91porn-server/common/log" "91porn-server/models/s/kwrankmod" ) // VidHKWSearcher VidHKWSearcher type VidHKWSearcher struct { uid uint64 vidOpt searcher.Opter } // NewVidHKWSearcher NewVidHKWSearcher func NewVidHKWSearcher(uid uint64, vidOpt searcher.Opter) searcher.Searcher { return &VidHKWSearcher{ uid: uid, vidOpt: vidOpt, } } type pair struct { Word string Result searcher.Resulter } const timeout = 3 * time.Second const gorouCountMax = 20 // Search Search func (v *VidHKWSearcher) Search(unuse searcher.KeyWorder, opt searcher.Opter) (result searcher.Resulter, err error) { limitEx1 := opt.Limit() + 1 //获取热词 words, err := kwrankmod.RecentRanking(limitEx1) if err != nil { return nil, errors.New("vidhkwsearcher RecentRanking error") } //没有热词 if len(words) == 0 { return &Result{[]VideoRes{}, false}, nil } hasNext := false if len(words) > int(opt.Limit()) { words = words[:opt.Limit()] hasNext = true } gorouCount := opt.Limit() if gorouCount > gorouCountMax { gorouCount = gorouCountMax } ch := make(chan pair, gorouCount) err_ch := make(chan error) for _, w := range words { word := w.KeyWord common.Go(func() { k := &searcher.Keyword{Word: word} result, err := vidsearcher.NewVidSearcher(v.uid, constant.SearchSP, 0).Search(k, v.vidOpt) if err != nil { err_ch <- err return } pair := pair{ Word: word, Result: result, } ch <- pair }) } count := len(words) resultMap := make(map[string]searcher.Resulter, count) timer := time.NewTimer(timeout) for i := 0; i < count; i++ { timer.Reset(timeout) select { case pair := <-ch: resultMap[pair.Word] = pair.Result if i == count-1 { return toResult(words, v.vidOpt.Limit(), resultMap, hasNext), nil } case err := <-err_ch: //获取出错前搜索到的视屏 log.Error(fmt.Sprintf("VidKWSearcher error:%+v\n", err)) return toResult(words, v.vidOpt.Limit(), resultMap, hasNext), nil case <-timer.C: //获取超时前搜索到的视屏 log.Warn(fmt.Sprintf("VidKWSearcher timeout::%+v\n", timeout)) return toResult(words, v.vidOpt.Limit(), resultMap, hasNext), nil } } return &Result{[]VideoRes{}, false}, nil } func toResult(words []kwrankmod.Keyword, vidCountPer int64, resultMap map[string]searcher.Resulter, hasNext bool) searcher.Resulter { resList := make([]VideoRes, 0, vidCountPer) //还原视屏的排序 for _, w := range words { word := w.KeyWord result, ok := resultMap[word] if !ok { continue } videoList := result.Data().([]VideoRes) resList = append(resList, videoList...) } return &Result{resList, hasNext} }