diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index c3caa50d..d63b765f 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -184,7 +184,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, questionController := controller.NewQuestionController(questionService, answerService, rankService, siteInfoCommonService, captchaService) answerController := controller.NewAnswerController(answerService, rankService, captchaService) searchParser := search_parser.NewSearchParser(tagCommonService, userCommon) - searchRepo := search_common.NewSearchRepo(dataData, uniqueIDRepo, userCommon) + searchRepo := search_common.NewSearchRepo(dataData, uniqueIDRepo, userCommon, tagCommonService) searchService := service.NewSearchService(searchParser, searchRepo) searchController := controller.NewSearchController(searchService, captchaService) serviceRevisionService := service.NewRevisionService(revisionRepo, userCommon, questionCommon, answerService, objService, questionRepo, answerRepo, tagRepo, tagCommonService, notificationQueueService, activityQueueService) diff --git a/internal/repo/search_common/search_repo.go b/internal/repo/search_common/search_repo.go index fcc0d74c..78985df1 100644 --- a/internal/repo/search_common/search_repo.go +++ b/internal/repo/search_common/search_repo.go @@ -3,6 +3,7 @@ package search_common import ( "context" "fmt" + tagcommon "github.com/answerdev/answer/internal/service/tag_common" "github.com/answerdev/answer/plugin" "strconv" "strings" @@ -19,7 +20,6 @@ import ( usercommon "github.com/answerdev/answer/internal/service/user_common" "github.com/answerdev/answer/pkg/converter" "github.com/answerdev/answer/pkg/obj" - "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "xorm.io/builder" ) @@ -58,19 +58,26 @@ type searchRepo struct { data *data.Data userCommon *usercommon.UserCommon uniqueIDRepo unique.UniqueIDRepo + tagCommon *tagcommon.TagCommonService } // NewSearchRepo new repository -func NewSearchRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo, userCommon *usercommon.UserCommon) search_common.SearchRepo { +func NewSearchRepo( + data *data.Data, + uniqueIDRepo unique.UniqueIDRepo, + userCommon *usercommon.UserCommon, + tagCommon *tagcommon.TagCommonService, +) search_common.SearchRepo { return &searchRepo{ data: data, uniqueIDRepo: uniqueIDRepo, userCommon: userCommon, + tagCommon: tagCommon, } } // SearchContents search question and answer data -func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagIDs []string, userID string, votes int, page, size int, order string) (resp []schema.SearchResult, total int64, err error) { +func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagIDs []string, userID string, votes int, page, size int, order string) (resp []*schema.SearchResult, total int64, err error) { words = filterWords(words) var ( @@ -210,7 +217,7 @@ func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagIDs } // SearchQuestions search question data -func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, tagIDs []string, notAccepted bool, views, answers int, page, size int, order string) (resp []schema.SearchResult, total int64, err error) { +func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, tagIDs []string, notAccepted bool, views, answers int, page, size int, order string) (resp []*schema.SearchResult, total int64, err error) { words = filterWords(words) var ( qfs = qFields @@ -319,7 +326,7 @@ func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, tagID } // SearchAnswers search answer data -func (sr *searchRepo) SearchAnswers(ctx context.Context, words []string, tagIDs []string, accepted bool, questionID string, page, size int, order string) (resp []schema.SearchResult, total int64, err error) { +func (sr *searchRepo) SearchAnswers(ctx context.Context, words []string, tagIDs []string, accepted bool, questionID string, page, size int, order string) (resp []*schema.SearchResult, total int64, err error) { words = filterWords(words) var ( @@ -428,7 +435,7 @@ func (sr *searchRepo) parseOrder(ctx context.Context, order string) (res string) } // ParseSearchPluginResult parse search plugin result -func (sr *searchRepo) ParseSearchPluginResult(ctx context.Context, sres []plugin.SearchResult) (resp []schema.SearchResult, err error) { +func (sr *searchRepo) ParseSearchPluginResult(ctx context.Context, sres []plugin.SearchResult) (resp []*schema.SearchResult, err error) { var ( qres []map[string][]byte res = make([]map[string][]byte, 0) @@ -455,82 +462,79 @@ func (sr *searchRepo) ParseSearchPluginResult(ctx context.Context, sres []plugin } // parseResult parse search result, return the data structure -func (sr *searchRepo) parseResult(ctx context.Context, res []map[string][]byte) (resp []schema.SearchResult, err error) { +func (sr *searchRepo) parseResult(ctx context.Context, res []map[string][]byte) (resp []*schema.SearchResult, err error) { + questionIDs := make([]string, 0) + userIDs := make([]string, 0) + resultList := make([]*schema.SearchResult, 0) for _, r := range res { - var ( - objectKey, - status string + questionIDs = append(questionIDs, string(r["question_id"])) + userIDs = append(userIDs, string(r["user_id"])) + tp, _ := time.ParseInLocation("2006-01-02 15:04:05", string(r["created_at"]), time.Local) + object := &schema.SearchObject{ + ID: string(r["id"]), + QuestionID: string(r["question_id"]), + Title: string(r["title"]), + Excerpt: htmltext.FetchExcerpt(string(r["parsed_text"]), "...", 240), + CreatedAtParsed: tp.Unix(), + UserInfo: &schema.SearchObjectUser{ + ID: string(r["user_id"]), + }, + Tags: make([]*schema.TagResp, 0), + VoteCount: converter.StringToInt(string(r["vote_count"])), + Accepted: string(r["accepted"]) == "2", + AnswerCount: converter.StringToInt(string(r["answer_count"])), + } - tags []schema.TagResp - tagsEntity []entity.Tag - object schema.SearchObject - ) - objectKey, err = obj.GetObjectTypeStrByObjectID(string(r["id"])) + objectKey, err := obj.GetObjectTypeStrByObjectID(string(r["id"])) if err != nil { continue } - tp, _ := time.ParseInLocation("2006-01-02 15:04:05", string(r["created_at"]), time.Local) - - // get user info - userInfo, _, e := sr.userCommon.GetUserBasicInfoByID(ctx, string(r["user_id"])) - if e != nil { - err = errors.InternalServer(reason.DatabaseError).WithError(e).WithStack() - return - } - - // get tags - err = sr.data.DB.Context(ctx). - Select("`display_name`,`slug_name`,`main_tag_slug_name`,`recommend`,`reserved`"). - Table("tag"). - Join("INNER", "tag_rel", "tag.id = tag_rel.tag_id"). - Where(builder.Eq{"tag_rel.object_id": r["question_id"]}). - And(builder.Eq{"tag_rel.status": entity.TagRelStatusAvailable}). - UseBool("recommend", "reserved"). - OrderBy("tag.recommend DESC, tag.reserved DESC, tag.id DESC"). - Find(&tagsEntity) - - if err != nil { - err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() - return - } - _ = copier.Copy(&tags, tagsEntity) switch objectKey { case "question": for k, v := range entity.AdminQuestionSearchStatus { if v == converter.StringToInt(string(r["status"])) { - status = k + object.StatusStr = k break } } case "answer": for k, v := range entity.AdminAnswerSearchStatus { if v == converter.StringToInt(string(r["status"])) { - status = k + object.StatusStr = k break } } } - object = schema.SearchObject{ - ID: string(r["id"]), - QuestionID: string(r["question_id"]), - Title: string(r["title"]), - Excerpt: htmltext.FetchExcerpt(string(r["parsed_text"]), "...", 240), - CreatedAtParsed: tp.Unix(), - UserInfo: userInfo, - Tags: tags, - VoteCount: converter.StringToInt(string(r["vote_count"])), - Accepted: string(r["accepted"]) == "2", - AnswerCount: converter.StringToInt(string(r["answer_count"])), - StatusStr: status, - } - resp = append(resp, schema.SearchResult{ + resultList = append(resultList, &schema.SearchResult{ ObjectType: objectKey, Object: object, }) } - return + + tagsMap, err := sr.tagCommon.BatchGetObjectTag(ctx, questionIDs) + if err != nil { + return nil, err + } + userInfoMap, err := sr.userCommon.BatchUserBasicInfoByID(ctx, userIDs) + if err != nil { + return nil, err + } + + for _, item := range resultList { + tags, ok := tagsMap[item.Object.QuestionID] + if ok { + item.Object.Tags = tags + } + if userInfo := userInfoMap[item.Object.UserInfo.ID]; userInfo != nil { + item.Object.UserInfo.Username = userInfo.Username + item.Object.UserInfo.DisplayName = userInfo.DisplayName + item.Object.UserInfo.Rank = userInfo.Rank + item.Object.UserInfo.Status = userInfo.Status + } + } + return resultList, nil } func addRelevanceField(searchFields, words, fields []string) (res []string, args []interface{}) { diff --git a/internal/schema/search_schema.go b/internal/schema/search_schema.go index 58585176..aaf0c8ae 100644 --- a/internal/schema/search_schema.go +++ b/internal/schema/search_schema.go @@ -90,13 +90,21 @@ type SearchObject struct { Accepted bool `json:"accepted"` AnswerCount int `json:"answer_count"` // user info - UserInfo *UserBasicInfo `json:"user_info"` + UserInfo *SearchObjectUser `json:"user_info"` // tags - Tags []TagResp `json:"tags"` + Tags []*TagResp `json:"tags"` // Status StatusStr string `json:"status"` } +type SearchObjectUser struct { + ID string `json:"id"` + Username string `json:"username"` + DisplayName string `json:"display_name"` + Rank int `json:"rank"` + Status string `json:"status"` +} + type TagResp struct { ID string `json:"-"` SlugName string `json:"slug_name"` @@ -111,13 +119,13 @@ type SearchResult struct { // object_type ObjectType string `json:"object_type"` // this object - Object SearchObject `json:"object"` + Object *SearchObject `json:"object"` } type SearchResp struct { Total int64 `json:"count"` // search response - SearchResults []SearchResult `json:"list"` + SearchResults []*SearchResult `json:"list"` } type SearchDescResp struct { diff --git a/internal/service/search_common/search.go b/internal/service/search_common/search.go index 8d35ee1b..6459d02f 100644 --- a/internal/service/search_common/search.go +++ b/internal/service/search_common/search.go @@ -7,8 +7,8 @@ import ( ) type SearchRepo interface { - SearchContents(ctx context.Context, words []string, tagIDs []string, userID string, votes, page, size int, order string) (resp []schema.SearchResult, total int64, err error) - SearchQuestions(ctx context.Context, words []string, tagIDs []string, notAccepted bool, views, answers int, page, size int, order string) (resp []schema.SearchResult, total int64, err error) - SearchAnswers(ctx context.Context, words []string, tagIDs []string, accepted bool, questionID string, page, size int, order string) (resp []schema.SearchResult, total int64, err error) - ParseSearchPluginResult(ctx context.Context, sres []plugin.SearchResult) (resp []schema.SearchResult, err error) + SearchContents(ctx context.Context, words []string, tagIDs []string, userID string, votes, page, size int, order string) (resp []*schema.SearchResult, total int64, err error) + SearchQuestions(ctx context.Context, words []string, tagIDs []string, notAccepted bool, views, answers int, page, size int, order string) (resp []*schema.SearchResult, total int64, err error) + SearchAnswers(ctx context.Context, words []string, tagIDs []string, accepted bool, questionID string, page, size int, order string) (resp []*schema.SearchResult, total int64, err error) + ParseSearchPluginResult(ctx context.Context, sres []plugin.SearchResult) (resp []*schema.SearchResult, err error) } diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index 60cc9875..7979719a 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -436,6 +436,9 @@ func (ts *TagCommonService) tagFormatRecommendAndReserved(ctx context.Context, t // BatchGetObjectTag batch get object tag func (ts *TagCommonService) BatchGetObjectTag(ctx context.Context, objectIds []string) (map[string][]*schema.TagResp, error) { objectIDTagMap := make(map[string][]*schema.TagResp) + if len(objectIds) == 0 { + return objectIDTagMap, nil + } objectTagRelList, err := ts.tagRelRepo.BatchGetObjectTagRelList(ctx, objectIds) if err != nil { return objectIDTagMap, err diff --git a/internal/service/user_common/user.go b/internal/service/user_common/user.go index c1886041..34ab7a75 100644 --- a/internal/service/user_common/user.go +++ b/internal/service/user_common/user.go @@ -106,9 +106,12 @@ func (us *UserCommon) UpdateQuestionCount(ctx context.Context, userID string, nu return us.userRepo.UpdateQuestionCount(ctx, userID, num) } -func (us *UserCommon) BatchUserBasicInfoByID(ctx context.Context, IDs []string) (map[string]*schema.UserBasicInfo, error) { +func (us *UserCommon) BatchUserBasicInfoByID(ctx context.Context, userIDs []string) (map[string]*schema.UserBasicInfo, error) { userMap := make(map[string]*schema.UserBasicInfo) - userList, err := us.userRepo.BatchGetByID(ctx, IDs) + if len(userIDs) == 0 { + return userMap, nil + } + userList, err := us.userRepo.BatchGetByID(ctx, userIDs) if err != nil { return userMap, err }