This is an automated email from the ASF dual-hosted git repository.

kumfo pushed a commit to branch feat/1.2.5/search
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git


The following commit(s) were added to refs/heads/feat/1.2.5/search by this push:
     new 6cd0f3e8 feat: optimize search results
6cd0f3e8 is described below

commit 6cd0f3e8144070c0dc0c038d56f08f7efe047518
Author: kumfo <[email protected]>
AuthorDate: Mon Dec 11 16:30:20 2023 +0800

    feat: optimize search results
---
 internal/repo/search_common/search_repo.go      | 124 +++++++++---------------
 internal/service/search_common/search.go        |   4 +-
 internal/service/search_parser/search_parser.go |  15 ++-
 internal/service/search_service.go              |   4 +-
 4 files changed, 62 insertions(+), 85 deletions(-)

diff --git a/internal/repo/search_common/search_repo.go 
b/internal/repo/search_common/search_repo.go
index de3c03eb..7e282876 100644
--- a/internal/repo/search_common/search_repo.go
+++ b/internal/repo/search_common/search_repo.go
@@ -50,10 +50,10 @@ var (
                "`question`.`id`",
                "`question`.`id` as `question_id`",
                "`title`",
-               "`parsed_text`",
+               "`question`.`parsed_text` as `parsed_text`",
                "`question`.`created_at` as `created_at`",
-               "`user_id`",
-               "`vote_count`",
+               "`question`.`user_id` as `user_id`",
+               "`question`.`vote_count` as `vote_count`",
                "`answer_count`",
                "CASE WHEN `accepted_answer_id` > 0 THEN 2 ELSE 0 END as 
`accepted`",
                "`question`.`status` as `status`",
@@ -98,54 +98,41 @@ func NewSearchRepo(
 }
 
 // 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, page, size int, order string) (resp 
[]*schema.SearchResult, total int64, err error) {
        words = filterWords(words)
-
        var (
-               b     *builder.Builder
-               ub    *builder.Builder
-               qfs   = qFields
-               afs   = aFields
-               argsQ = []interface{}{}
-               argsA = []interface{}{}
+               b    *builder.Builder
+               qfs  = qFields
+               args = []interface{}{}
        )
 
        if order == "relevance" {
                if len(words) > 0 {
-                       qfs, argsQ = addRelevanceField([]string{"title", 
"original_text"}, words, qfs)
-                       afs, argsA = 
addRelevanceField([]string{"`answer`.`original_text`"}, words, afs)
+                       qfs, args = 
addRelevanceField([]string{"`question`.`title`", "`question`.`original_text`"}, 
words, qfs)
                } else {
                        order = "newest"
                }
        }
 
-       b = builder.MySQL().Select(qfs...).From("`question`")
-       ub = builder.MySQL().Select(afs...).From("`answer`").
-               LeftJoin("`question`", "`question`.id = `answer`.question_id")
-
-       b.Where(builder.Lt{"`question`.`status`": 
entity.QuestionStatusDeleted}).
-               And(builder.Eq{"`question`.`show`": entity.QuestionShow})
-       ub.Where(builder.Lt{"`question`.`status`": 
entity.QuestionStatusDeleted}).
-               And(builder.Lt{"`answer`.`status`": 
entity.AnswerStatusDeleted}).
-               And(builder.Eq{"`question`.`show`": entity.QuestionShow})
-
-       argsQ = append(argsQ, entity.QuestionStatusDeleted, entity.QuestionShow)
-       argsA = append(argsA, entity.QuestionStatusDeleted, 
entity.AnswerStatusDeleted, entity.QuestionShow)
+       // create builder
+       b = builder.MySQL().Select(qfs...).From("`question`").
+               LeftJoin("`answer`", "`question`.`id` = 
`answer`.`question_id`").
+               Where(builder.Lt{"`question`.`status`": 
entity.QuestionStatusDeleted}).
+               And(builder.Eq{"`question`.`show`": entity.QuestionShow}).
+               And(builder.Lt{"`answer`.`status`": entity.AnswerStatusDeleted})
+       args = append(args, entity.QuestionStatusDeleted, entity.QuestionShow, 
entity.AnswerStatusDeleted)
 
-       likeConQ := builder.NewCond()
-       likeConA := builder.NewCond()
+       // add content like match conditions
+       likeCon := builder.NewCond()
        for _, word := range words {
-               likeConQ = likeConQ.Or(builder.Like{"title", word}).
-                       Or(builder.Like{"original_text", word})
-               argsQ = append(argsQ, "%"+word+"%")
-               argsQ = append(argsQ, "%"+word+"%")
-
-               likeConA = likeConA.Or(builder.Like{"`answer`.original_text", 
word})
-               argsA = append(argsA, "%"+word+"%")
+               likeCon = likeCon.Or(builder.Like{"`question`.`title`", word}).
+                       Or(builder.Like{"`question`.`original_text`", word}).
+                       Or(builder.Like{"`answer`.original_text", word})
+               args = append(args, "%"+word+"%")
+               args = append(args, "%"+word+"%")
+               args = append(args, "%"+word+"%")
        }
-
-       b.Where(likeConQ)
-       ub.Where(likeConA)
+       b.Where(likeCon)
 
        // check tag
        for ti, tagID := range tagIDs {
@@ -155,53 +142,25 @@ func (sr *searchRepo) SearchContents(ctx context.Context, 
words []string, tagIDs
                                ast + ".tag_id": tagID,
                                ast + ".status": entity.TagRelStatusAvailable,
                        })
-               ub.Join("INNER", "tag_rel as "+ast, "question_id = 
"+ast+".object_id").
-                       And(builder.Eq{
-                               ast + ".tag_id": tagID,
-                               ast + ".status": entity.TagRelStatusAvailable,
-                       })
-               argsQ = append(argsQ, entity.TagRelStatusAvailable, tagID)
-               argsA = append(argsA, entity.TagRelStatusAvailable, tagID)
+               args = append(args, entity.TagRelStatusAvailable, tagID)
        }
 
        // check user
        if userID != "" {
-               b.Where(builder.Eq{"question.user_id": userID})
-               ub.Where(builder.Eq{"answer.user_id": userID})
-               argsQ = append(argsQ, userID)
-               argsA = append(argsA, userID)
-       }
-
-       // check vote
-       if votes == 0 {
-               b.Where(builder.Eq{"question.vote_count": votes})
-               ub.Where(builder.Eq{"answer.vote_count": votes})
-               argsQ = append(argsQ, votes)
-               argsA = append(argsA, votes)
-       } else if votes > 0 {
-               b.Where(builder.Gte{"question.vote_count": votes})
-               ub.Where(builder.Gte{"answer.vote_count": votes})
-               argsQ = append(argsQ, votes)
-               argsA = append(argsA, votes)
-       }
-
-       //b = b.Union("all", ub)
-       ubSQL, _, err := ub.ToSQL()
-       if err != nil {
-               return
-       }
-       bSQL, _, err := b.ToSQL()
-       if err != nil {
-               return
+               userCond := builder.NewCond()
+               userCond.Or(builder.Eq{"question.user_id": userID}).
+                       Or(builder.Eq{"answer.user_id": userID})
+               args = append(args, userID)
+               args = append(args, userID)
+               b.Where(userCond)
        }
-       sql := fmt.Sprintf("(%s UNION ALL %s)", bSQL, ubSQL)
 
-       countSQL, _, err := builder.MySQL().Select("count(*) total").From(sql, 
"c").ToSQL()
+       countSQL, _, err := builder.MySQL().Select("count(*) total").From(b, 
"c").ToSQL()
        if err != nil {
                return
        }
 
-       querySQL, _, err := builder.MySQL().Select("*").From(sql, 
"t").OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL()
+       querySQL, _, err := b.OrderBy(sr.parseOrder(ctx, order)).Limit(size, 
page-1).ToSQL()
        if err != nil {
                return
        }
@@ -210,12 +169,10 @@ func (sr *searchRepo) SearchContents(ctx context.Context, 
words []string, tagIDs
        countArgs := []interface{}{}
 
        queryArgs = append(queryArgs, querySQL)
-       queryArgs = append(queryArgs, argsQ...)
-       queryArgs = append(queryArgs, argsA...)
+       queryArgs = append(queryArgs, args...)
 
        countArgs = append(countArgs, countSQL)
-       countArgs = append(countArgs, argsQ...)
-       countArgs = append(countArgs, argsA...)
+       countArgs = append(countArgs, args...)
 
        res, err := sr.data.DB.Context(ctx).Query(queryArgs...)
        if err != nil {
@@ -236,7 +193,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, votes, views, answers int, page, size int, 
order string) (resp []*schema.SearchResult, total int64, err error) {
        words = filterWords(words)
        var (
                qfs  = qFields
@@ -255,6 +212,15 @@ func (sr *searchRepo) SearchQuestions(ctx context.Context, 
words []string, tagID
        b.Where(builder.Lt{"`question`.`status`": 
entity.QuestionStatusDeleted}).And(builder.Eq{"`question`.`show`": 
entity.QuestionShow})
        args = append(args, entity.QuestionStatusDeleted, entity.QuestionShow)
 
+       // check vote
+       if votes == 0 {
+               b.And(builder.Eq{"question.vote_count": votes})
+               args = append(args, votes)
+       } else if votes > 0 {
+               b.And(builder.Gte{"question.vote_count": votes})
+               args = append(args, votes)
+       }
+
        likeConQ := builder.NewCond()
        for _, word := range words {
                likeConQ = likeConQ.Or(builder.Like{"title", word}).
diff --git a/internal/service/search_common/search.go 
b/internal/service/search_common/search.go
index d1aea547..3ff83957 100644
--- a/internal/service/search_common/search.go
+++ b/internal/service/search_common/search.go
@@ -26,8 +26,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)
+       SearchContents(ctx context.Context, words []string, tagIDs []string, 
userID string, page, size int, order string) (resp []*schema.SearchResult, 
total int64, err error)
+       SearchQuestions(ctx context.Context, words []string, tagIDs []string, 
notAccepted bool, votes, 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/search_parser/search_parser.go 
b/internal/service/search_parser/search_parser.go
index a5dfd670..ae0363d0 100644
--- a/internal/service/search_parser/search_parser.go
+++ b/internal/service/search_parser/search_parser.go
@@ -56,12 +56,15 @@ func (sp *SearchParser) ParseStructure(ctx context.Context, 
dto *schema.SearchDT
        // match tags
        cond.Tags = sp.parseTags(ctx, &query)
 
-       // match all
+       //default: match all
        cond.UserID = sp.parseUserID(ctx, &query, dto.UserID)
-       cond.VoteAmount = sp.parseVotes(&query)
        cond.Words = sp.parseWithin(&query)
 
        // match questions
+       cond.VoteAmount = sp.parseVotes(&query)
+       if cond.VoteAmount > -1 {
+               cond.TargetType = constant.QuestionObjectType
+       }
        cond.NotAccepted = sp.parseNotAccepted(&query)
        if cond.NotAccepted {
                cond.TargetType = constant.QuestionObjectType
@@ -101,6 +104,14 @@ func (sp *SearchParser) ParseStructure(ctx 
context.Context, dto *schema.SearchDT
        if len(cond.Words) > limitWords {
                cond.Words = cond.Words[:limitWords]
        }
+
+       // only tags, not words and search is default, only search question
+       if len(cond.Words) == 0 &&
+               len(cond.Tags) > 0 &&
+               cond.TargetType != constant.QuestionObjectType &&
+               cond.TargetType != constant.AnswerObjectType {
+               cond.TargetType = constant.QuestionObjectType
+       }
        return
 }
 
diff --git a/internal/service/search_service.go 
b/internal/service/search_service.go
index 46d71374..73c96436 100644
--- a/internal/service/search_service.go
+++ b/internal/service/search_service.go
@@ -69,10 +69,10 @@ func (ss *SearchService) Search(ctx context.Context, dto 
*schema.SearchDTO) (res
        if finder == nil {
                if cond.SearchAll() {
                        resp.SearchResults, resp.Total, err =
-                               ss.searchRepo.SearchContents(ctx, cond.Words, 
cond.Tags, cond.UserID, cond.VoteAmount, dto.Page, dto.Size, dto.Order)
+                               ss.searchRepo.SearchContents(ctx, cond.Words, 
cond.Tags, cond.UserID, dto.Page, dto.Size, dto.Order)
                } else if cond.SearchQuestion() {
                        resp.SearchResults, resp.Total, err =
-                               ss.searchRepo.SearchQuestions(ctx, cond.Words, 
cond.Tags, cond.NotAccepted, cond.Views, cond.AnswerAmount, dto.Page, dto.Size, 
dto.Order)
+                               ss.searchRepo.SearchQuestions(ctx, cond.Words, 
cond.Tags, cond.NotAccepted, cond.VoteAmount, cond.Views, cond.AnswerAmount, 
dto.Page, dto.Size, dto.Order)
                } else if cond.SearchAnswer() {
                        resp.SearchResults, resp.Total, err =
                                ss.searchRepo.SearchAnswers(ctx, cond.Words, 
cond.Tags, cond.Accepted, cond.QuestionID, dto.Page, dto.Size, dto.Order)

Reply via email to