go-common/app/interface/bbq/app-bbq/service/search.go

331 lines
8.0 KiB
Go
Raw Normal View History

2019-04-22 10:49:16 +00:00
package service
import (
"context"
"encoding/json"
"go-common/app/interface/bbq/app-bbq/api/http/v1"
"go-common/app/interface/bbq/app-bbq/model"
"go-common/app/service/bbq/common"
"go-common/library/ecode"
"go-common/library/log"
"github.com/json-iterator/go"
)
const (
searchTypeVideo = "bbq_video"
searchTypeUser = "bbq_user"
suggestType = "bbq"
suggestVer = "v4"
searchLen = 20
)
// SearchCursor .
type SearchCursor struct {
Offset int64 `json:"offset"` // 默认为0数据从1开始
}
func parseSearchCursor(c context.Context, cursorPrev, cursorNext string) (cursor *SearchCursor, directionNext bool, err error) {
cursor = new(SearchCursor)
// 判断是向前还是向后查询
directionNext = true
cursorStr := cursorNext
if len(cursorNext) == 0 && len(cursorPrev) > 0 {
directionNext = false
cursorStr = cursorPrev
}
// 解析
if len(cursorStr) != 0 {
var cursorData = []byte(cursorStr)
err = json.Unmarshal(cursorData, &cursor)
if err != nil {
err = ecode.ReqParamErr
return
}
}
return
}
//HotWord .
func (s *Service) HotWord(c context.Context, req *v1.HotWordRequest) (res *v1.HotWordResponse, err error) {
res = new(v1.HotWordResponse)
res.List = append(res.List, "小姐姐")
res.List = append(res.List, "舞蹈")
res.List = append(res.List, "MMD")
return
}
// VideoSearch 视频搜索
func (s *Service) VideoSearch(c context.Context, arg *v1.BaseSearchReq) (res *v1.VideoSearchRes, err error) {
res = new(v1.VideoSearchRes)
var (
sres []*model.VideoSearchResult
searchRes *model.RawSearchRes
relids []int32
svids []int64
svidMap map[int64]int64
)
// 0. check
// 1. 生成请求,会根据请求参数
// v2接口
reqPage := int64(1)
firstItemOffset := int64(0)
var cursor *SearchCursor
var directionNext bool
if arg.Page == 0 {
cursor, directionNext, err = parseSearchCursor(c, arg.CursorPrev, arg.CursorNext)
if err != nil {
log.Warnw(c, "log", "parse search cursor fail", "prev", arg.CursorPrev, "next", arg.CursorNext)
return
}
firstItemOffset = cursor.Offset - 1
if directionNext {
firstItemOffset = cursor.Offset + 1
}
reqPage = (firstItemOffset-1)/searchLen + 1
log.V(1).Infow(c, "log", "v2 request", "next", arg.CursorNext, "prev", arg.CursorPrev)
} else {
reqPage = arg.Page
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
sp := &model.SearchBaseReq{
KeyWord: arg.Key,
Type: searchTypeVideo,
Page: reqPage,
PageSize: searchLen,
Highlight: int64(arg.Highlight),
}
// 相信搜索结果返回的就是searchLen
searchRes, err = s.dao.SearchBBQ(c, sp)
if searchRes.Res == nil {
return
}
if err = json.Unmarshal(searchRes.Res, &sres); err != nil {
return
}
for _, v := range sres {
relids = append(relids, v.ID)
}
if len(relids) == 0 {
log.Infov(c, log.KV("log", "search ret empty"))
return
}
ids := s.dao.ParseRel2ID(relids)
svidMap, err = s.dao.ConvID2SVID(c, ids)
if err != nil {
log.Error("ConvID2SVID err [%v]", err)
err = nil
return
}
for _, svid := range svidMap {
svids = append(svids, svid)
}
svMap, _ := s.svInfos(c, svids, 0, false)
for index, sinfo := range sres {
id := s.dao.ParseRel2ID([]int32{sinfo.ID})
if id[0] == 0 {
continue
}
if svid, ok := svidMap[id[0]]; ok {
if sv, ok := svMap[svid]; ok {
if common.IsSearchSvStateAvailable(int64(sv.State)) {
r := new(v1.VideoSearchList)
r.VideoResponse = *sv
r.SVID = svid
r.HitColumns = sinfo.HitColumns
r.TitleHighlight = sinfo.Title
r.Offset = (reqPage-1)*int64(searchLen) + int64(index) + 1
res.List = append(res.List, r)
} else {
log.Warnw(c, "log", "get error svid in search list", "svid", svid, "sv", sv)
}
}
}
}
res.NumPage = searchRes.PageNum
res.Page = searchRes.Page
res.HasMore = false
if arg.Page == 0 {
if (directionNext && searchRes.PageNum > searchRes.Page) || (!directionNext && searchRes.Page > 1) {
res.HasMore = true
}
var list []*v1.VideoSearchList
if directionNext {
for _, item := range res.List {
if item.Offset < firstItemOffset {
continue
}
list = append(list, item)
}
} else {
if firstItemOffset >= int64(len(res.List)) {
firstItemOffset = int64(len(res.List)) - 1
}
for i := firstItemOffset - 1; i >= 0; i-- {
list = append(list, res.List[i])
}
}
res.List = list
}
var cursorValue SearchCursor
for _, item := range res.List {
cursorValue.Offset = item.Offset
data, _ := json.Marshal(cursorValue)
item.CursorValue = string(data)
}
return
}
// UserSearch 用户搜索
func (s *Service) UserSearch(c context.Context, mid int64, arg *v1.BaseSearchReq) (res *v1.UserSearchRes, err error) {
res = new(v1.UserSearchRes)
var (
sres []*model.UserSearchResult
searchRes *model.RawSearchRes
mids []int64
)
// 1. 生成请求,会根据请求参数
// v2接口
reqPage := int64(1)
firstItemOffset := int64(0)
var cursor *SearchCursor
var directionNext bool
if arg.Page == 0 {
cursor, directionNext, err = parseSearchCursor(c, arg.CursorPrev, arg.CursorNext)
if err != nil {
log.Warnw(c, "log", "parse search cursor fail", "prev", arg.CursorPrev, "next", arg.CursorNext)
return
}
firstItemOffset = cursor.Offset - 1
if directionNext {
firstItemOffset = cursor.Offset + 1
}
reqPage = (firstItemOffset-1)/searchLen + 1
log.V(1).Infow(c, "log", "v2 request", "next", arg.CursorNext, "prev", arg.CursorPrev)
} else {
reqPage = arg.Page
}
sp := &model.SearchBaseReq{
KeyWord: arg.Key,
Type: searchTypeUser,
Page: reqPage,
PageSize: searchLen,
Highlight: int64(arg.Highlight),
}
searchRes, err = s.dao.SearchBBQ(c, sp)
if searchRes.Res == nil {
return
}
if err = json.Unmarshal(searchRes.Res, &sres); err != nil {
return
}
for _, v := range sres {
mids = append(mids, v.ID)
}
if len(mids) == 0 {
log.Infov(c, log.KV("log", "search ret empty"))
return
}
uMap, _ := s.dao.BatchUserInfo(c, mid, mids, false, true, true)
for index, sinfo := range sres {
if u, ok := uMap[sinfo.ID]; ok {
r := &v1.UserSearchList{
UserInfo: *u,
}
st := new(v1.UserStatic)
st.Fan = u.Fan
st.Follow = u.Follow
st.Like = u.Like
st.Liked = u.Liked
st.FollowState = u.FollowState
r.UserStatic = st
r.HitColumns = sinfo.HitColumns
r.UnameHighlight = sinfo.Uname
r.Offset = (reqPage-1)*int64(searchLen) + int64(index) + 1
res.List = append(res.List, r)
}
}
res.NumPage = searchRes.PageNum
res.Page = searchRes.Page
res.HasMore = false
if arg.Page == 0 {
if (directionNext && searchRes.PageNum > searchRes.Page) || (!directionNext && searchRes.Page > 1) {
res.HasMore = true
}
var list []*v1.UserSearchList
if directionNext {
for _, item := range res.List {
if item.Offset < firstItemOffset {
continue
}
list = append(list, item)
}
} else {
if firstItemOffset >= int64(len(res.List)) {
firstItemOffset = int64(len(res.List)) - 1
}
for i := firstItemOffset - 1; i >= 0; i-- {
list = append(list, res.List[i])
}
}
res.List = list
}
var cursorValue SearchCursor
for _, item := range res.List {
cursorValue.Offset = item.Offset
data, _ := json.Marshal(cursorValue)
item.CursorValue = string(data)
}
return
}
// BBQSug BBQSUG服务
func (s *Service) BBQSug(c context.Context, arg *v1.SugReq) (res []*v1.SugTag, err error) {
var (
sres []*model.RawSugTag
data json.RawMessage
)
sp := &model.SugBaseReq{
Term: arg.KeyWord,
SuggestType: suggestType,
MainVer: suggestVer,
SugNum: arg.PageSize,
Highlight: int64(arg.Highlight),
}
data, err = s.dao.SugBBQ(c, sp)
if err != nil {
log.Error("s.dao.SugBBQ err[%v] data [%s]", err, string(data))
return
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
if err = json.Unmarshal(data, &sres); err != nil {
log.Error("json.Unmarshal err[%v] data [%s]", err, string(data))
return
}
for _, sinfo := range sres {
r := new(v1.SugTag)
name := sinfo.Name
r.Name = name
r.Value = sinfo.Value
r.Type = sinfo.Type
r.Ref = sinfo.Ref
res = append(res, r)
}
return
}