Browse Source

add:添加研报公有权限标识和研报标题搜索

zqbao 1 year ago
parent
commit
4b23c078e0
10 changed files with 555 additions and 0 deletions
  1. 46 0
      controllers/report.go
  2. 3 0
      go.mod
  3. 14 0
      models/report.go
  4. 21 0
      models/response/report.go
  5. 9 0
      routers/commentsRouter.go
  6. 275 0
      services/elastic/report.go
  7. 120 0
      services/report.go
  8. 17 0
      utils/common.go
  9. 29 0
      utils/config.go
  10. 21 0
      utils/elastic.go

+ 46 - 0
controllers/report.go

@@ -3,6 +3,7 @@ package controllers
 import (
 	"eta/eta_mini_bridge/models"
 	"eta/eta_mini_bridge/models/response"
+	"eta/eta_mini_bridge/services"
 	"eta/eta_mini_bridge/utils"
 	"html"
 	"strconv"
@@ -266,6 +267,9 @@ func (this *ReportController) Detail() {
 			br.Msg = "用户权限不足"
 			return
 		}
+	} else {
+		report.IsPublic = IsPublic
+
 	}
 	resp.Report = report
 	resp.Status = utils.ReportPermissionStatusHas
@@ -325,3 +329,45 @@ func (this *ReportController) Today() {
 	br.Msg = "获取成功"
 	br.Data = resp
 }
+
+// @Title 研报搜索
+// @Description 研报标搜索
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   KeyWord   query   string  true       "关键字"
+// @Success 200 {object} models.ReportDetailResp
+// @router /search [get]
+func (this *ReportController) Search() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	keyWord := this.GetString("KeyWord")
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	if pageSize <= 0 {
+		pageSize = utils.PageSize30
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+
+	if keyWord == "" {
+		br.Msg = "请输入关键字"
+		return
+	}
+
+	reportList, err, errMsg := services.SearchReport(keyWord, currentIndex, pageSize)
+	if err != nil {
+		br.Msg = "研报搜索失败"
+		br.ErrMsg = errMsg + ",Err:" + err.Error()
+		return
+	}
+
+	br.Data = reportList
+	br.Msg = "查询成功"
+	br.Ret = 200
+	br.Success = true
+}

+ 3 - 0
go.mod

@@ -8,6 +8,7 @@ require (
 	github.com/beego/bee/v2 v2.1.0
 	github.com/go-redis/redis/v8 v8.11.5
 	github.com/go-sql-driver/mysql v1.7.0
+	github.com/olivere/elastic/v7 v7.0.32
 	github.com/rdlucklib/rdluck_tools v1.0.3
 	github.com/silenceper/wechat/v2 v2.1.6
 )
@@ -20,7 +21,9 @@ require (
 	github.com/fatih/structs v1.1.0 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
 	github.com/kr/text v0.2.0 // indirect
+	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/pkg/errors v0.9.1 // indirect

+ 14 - 0
models/report.go

@@ -184,6 +184,7 @@ type ReportDetail struct {
 	IsCurrentDate      int    `description:"是否当前日期"`
 	ClassifyName       string `description:"分类名称"`
 	TitleType          string `description:"标题类型,FICC或者权益"`
+	IsPublic           bool   `description:"是否是公共报告 "`
 }
 
 func GetReportById(reportId int) (item *ReportDetail, err error) {
@@ -192,3 +193,16 @@ func GetReportById(reportId int) (item *ReportDetail, err error) {
 	err = o.Raw(sql, reportId).QueryRow(&item)
 	return
 }
+
+type ReportCollectListItem struct {
+	ReportId            int       `description:"报告Id" json:"report_id"`
+	ReportChapterId     int       `json:"report_chapter_id"`
+	ClassifyIdFirst     int       `description:"一级分类id" json:"classify_id_first"`
+	ClassifyNameFirst   string    `description:"一级分类名称" json:"classify_name_first"`
+	ClassifyIdSecond    int       `description:"二级分类id" json:"classify_id_second"`
+	ClassifyNameSecond  string    `description:"二级分类名称" json:"classify_name_second"`
+	ReportChapterTypeId int       `json:"report_chapter_type_id"`
+	PublishTime         time.Time `description:"发布时间" json:"publish_time"`
+	Title               string    `description:"标题" json:"title"`
+	ContentSub          string    `description:"内容前两个章节" json:"content_sub"`
+}

+ 21 - 0
models/response/report.go

@@ -19,3 +19,24 @@ type ReportDetailResp struct {
 	Report *models.ReportDetail `description:"报告"`
 	Status int                  `description:"报告状态"`
 }
+type ReportSearchResp struct {
+	Paging *paging.PagingItem
+	List   []*models.ReportCollectListItem
+}
+
+type EsReportItem struct {
+	Author             string `description:"作者"`
+	BodyContent        string `description:"内容"`
+	Categories         string `description:"品种名称"`
+	ClassifyIdFirst    int    `description:"一级分类id"`
+	ClassifyNameFirst  string `description:"一级分类名称"`
+	ClassifyIdSecond   int    `description:"二级分类id"`
+	ClassifyNameSecond string `description:"二级分类名称"`
+	PublishState       int    `description:"1:未发布,2:已发布"`
+	PublishTime        string `description:"发布时间"`
+	ReportChapterId    int    `description:"报告章节Id"`
+	ReportId           int    `description:"报告Id"`
+	Title              string `description:"标题"`
+	Abstract           string `description:"摘要"`
+	StageStr           string `description:"期数"`
+}

+ 9 - 0
routers/commentsRouter.go

@@ -70,6 +70,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_bridge/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mini_bridge/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "Search",
+            Router: `/search`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_bridge/controllers:WeChatController"] = append(beego.GlobalControllerRouter["eta/eta_mini_bridge/controllers:WeChatController"],
         beego.ControllerComments{
             Method: "SendTemplateMsg",

+ 275 - 0
services/elastic/report.go

@@ -0,0 +1,275 @@
+package elastic
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"eta/eta_mini_bridge/utils"
+	"fmt"
+
+	"github.com/olivere/elastic/v7"
+)
+
+// 首页搜索
+func SearchReport(keyWord string, classifyIdFirsts []int, classifyIdSeconds []int, pageIndex, pageSize int) (searchResp *elastic.SearchResult, total int64, err error) {
+	indexName := utils.EsReportIndexName
+	var must []map[string]interface{}
+
+	shouldSub := []map[string]interface{}{
+		map[string]interface{}{
+			"match_phrase": map[string]interface{}{
+				"Title": map[string]interface{}{
+					"query": keyWord,
+					//"slop": "50",
+					"boost": 5,
+				},
+			},
+		},
+		// map[string]interface{}{
+		// 	"match_phrase": map[string]interface{}{
+		// 		"Categories": map[string]interface{}{
+		// 			"query": keyWord,
+		// 			"boost": 4,
+		// 		},
+		// 	},
+		// },
+		// map[string]interface{}{
+		// 	"match_phrase": map[string]interface{}{
+		// 		"BodyContent": map[string]interface{}{
+		// 			"query": keyWord,
+		// 			"boost": 3,
+		// 		},
+		// 	},
+		// },
+	}
+	mustMap := map[string]interface{}{
+		"bool": map[string]interface{}{
+			"should": shouldSub,
+		},
+	}
+	must = append(must, mustMap)
+	filterMust := []map[string]interface{}{
+		map[string]interface{}{
+			"term": map[string]interface{}{
+				"PublishState": 2, //必须是已发布的报告
+			},
+		},
+		// map[string]interface{}{
+		// 	"terms": map[string]interface{}{
+		// 		"ClassifyIdFirst": classifyIdFirsts, //分类必须是正常显示状态
+		// 	},
+		// },
+		// map[string]interface{}{
+		// 	"terms": map[string]interface{}{
+		// 		"ClassifyIdSecond": classifyIdSeconds, //分类必须是正常显示状态
+		// 	},
+		// },
+	}
+	// filterMustNot := []map[string]interface{}{
+	// 	map[string]interface{}{
+	// 		"term": map[string]interface{}{
+	// 			"BodyContent.keyword": map[string]interface{}{
+	// 				"value": "", //过滤没有内容的报告(晨报和周报)bodyContent 不能为空
+	// 			},
+	// 		},
+	// 	},
+	// }
+	filterMap := map[string]interface{}{
+		"bool": map[string]interface{}{
+			"must": filterMust,
+			// "must_not": filterMustNot,
+		},
+	}
+	source := map[string]interface{}{
+		"query": map[string]interface{}{
+			"bool": map[string]interface{}{
+				"must":   must,
+				"filter": filterMap,
+			},
+		},
+	}
+	source["from"] = (pageIndex - 1) * pageSize
+	source["size"] = pageSize
+	source["highlight"] = map[string]interface{}{
+		"fields": map[string]interface{}{
+			"Title": map[string]interface{}{},
+			// "Categories":  map[string]interface{}{},
+			// "BodyContent": map[string]interface{}{
+			// 	//	"pre_tags" : "{{highlight}}",
+			// 	//	"post_tags": "{{/highlight}}",
+			// },
+		},
+		"pre_tags":  "<span style=\"color:#E3B377\">",
+		"post_tags": "</span>",
+	}
+
+	source["sort"] = []map[string]interface{}{
+		map[string]interface{}{
+			"PublishTime.keyword": map[string]interface{}{
+				"order": "desc",
+			},
+		},
+		map[string]interface{}{
+			"_score": map[string]interface{}{
+				"order": "desc",
+			},
+		},
+	}
+	jsonstr, err := json.Marshal(source)
+	fmt.Printf("%s", jsonstr)
+
+	request := utils.EsClient.Search(indexName).Source(source) // sets the JSON request
+
+	searchResp, err = request.Do(context.Background())
+	if err != nil {
+		fmt.Print("结果err:")
+		fmt.Println(err.Error())
+		return
+	}
+
+	fmt.Print("结果正常:")
+	fmt.Println(searchResp.Status)
+	if searchResp.Status != 0 {
+		err = errors.New("查询失败")
+	}
+	total = searchResp.TotalHits()
+	return
+}
+
+// ReportListSearch 报告列表页的搜索
+func ReportListSearch(keyWord string, classifyIdFirst int, classifyIdSeconds []int, pageIndex, pageSize int) (searchResp *elastic.SearchResult, total int64, err error) {
+	indexName := utils.EsReportIndexName
+	var must []map[string]interface{}
+	shouldSub := []map[string]interface{}{
+		map[string]interface{}{
+			"match": map[string]interface{}{
+				"Title": map[string]interface{}{
+					"query": keyWord,
+					"boost": 3,
+				},
+			},
+		},
+		map[string]interface{}{
+			"match": map[string]interface{}{
+				"StageStr": map[string]interface{}{
+					"query": keyWord,
+					"boost": 2,
+				},
+			},
+		},
+		map[string]interface{}{
+			"match": map[string]interface{}{
+				"Abstract": map[string]interface{}{
+					"query": keyWord,
+					"boost": 2,
+				},
+			},
+		},
+		// map[string]interface{}{
+		// 	"match": map[string]interface{}{
+		// 		"ClassifyNameSecond": map[string]interface{}{
+		// 			"query": keyWord,
+		// 			"boost": 2,
+		// 		},
+		// 	},
+		// },
+		map[string]interface{}{
+			"match_phrase": map[string]interface{}{
+				"Title": map[string]interface{}{
+					"query": keyWord,
+					//"slop": "50",
+					"boost": 5,
+				},
+			},
+		},
+		map[string]interface{}{
+			"match_phrase": map[string]interface{}{
+				"Abstract": map[string]interface{}{
+					"query": keyWord,
+					//"slop": "50",
+					"boost": 5,
+				},
+			},
+		},
+	}
+	mustMap := map[string]interface{}{
+		"bool": map[string]interface{}{
+			"should": shouldSub,
+		},
+	}
+	must = append(must, mustMap)
+
+	filter := []map[string]interface{}{
+		map[string]interface{}{
+			"term": map[string]interface{}{
+				"PublishState": 2,
+			},
+		},
+		map[string]interface{}{
+			"term": map[string]interface{}{
+				"ReportChapterId": 0, //排除章节内容
+			},
+		},
+		// map[string]interface{}{
+		// 	"term": map[string]interface{}{
+		// 		"ClassifyIdFirst": classifyIdFirst,
+		// 	},
+		// },
+		// map[string]interface{}{
+		// 	"terms": map[string]interface{}{
+		// 		"ClassifyIdSecond": classifyIdSeconds,
+		// 	},
+		// },
+	}
+	source := map[string]interface{}{
+		"query": map[string]interface{}{
+			"bool": map[string]interface{}{
+				"must":   must,
+				"filter": filter,
+			},
+		},
+	}
+
+	// source["from"] = (pageIndex - 1) * pageSize
+	// source["size"] = pageSize
+	// source["highlight"] = map[string]interface{}{
+	// 	"fields": map[string]interface{}{
+	// 		"Title":              map[string]interface{}{},
+	// 		"Abstract":           map[string]interface{}{},
+	// 		"StageStr":           map[string]interface{}{},
+	// 		"ClassifyNameSecond": map[string]interface{}{},
+	// 	},
+	// 	"pre_tags":  "<span style=\"color:#E3B377\">",
+	// 	"post_tags": "</span>",
+	// }
+
+	// source["sort"] = []map[string]interface{}{
+	// 	map[string]interface{}{
+	// 		"PublishTime.keyword": map[string]interface{}{
+	// 			"order": "desc",
+	// 		},
+	// 	},
+	// 	map[string]interface{}{
+	// 		"_score": map[string]interface{}{
+	// 			"order": "desc",
+	// 		},
+	// 	},
+	// }
+	jsonstr, err := json.Marshal(source)
+	fmt.Printf("%s", jsonstr)
+	request := utils.EsClient.Search(indexName).Source(source) // sets the JSON request
+	searchResp, err = request.Do(context.Background())
+	if err != nil {
+		fmt.Print("结果err:")
+		fmt.Println(err.Error())
+		return
+	}
+
+	fmt.Print("结果正常:")
+	fmt.Println(searchResp.Status)
+	if searchResp.Status != 0 {
+		err = errors.New("查询失败")
+	}
+	total = searchResp.TotalHits()
+	return
+}

+ 120 - 0
services/report.go

@@ -0,0 +1,120 @@
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_mini_bridge/models"
+	"eta/eta_mini_bridge/models/response"
+	"eta/eta_mini_bridge/services/elastic"
+	"eta/eta_mini_bridge/utils"
+	"html"
+	"strings"
+	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+// addAliasToKeyword 品种别名
+func addAliasToKeyword(keyword string) string {
+	if keyword == "" {
+		return ""
+	}
+	keywordArr := make([]string, 0)
+	keywordArr = append(keywordArr, keyword)
+	if strings.Contains(keyword, "沥青") || strings.Contains(keyword, "BU") {
+		keywordArr = append(keywordArr, "沥青", "BU")
+	}
+	if strings.Contains(keyword, "MEG") || strings.Contains(keyword, "EG") || strings.Contains(keyword, "乙二醇") {
+		keywordArr = append(keywordArr, "MEG", "EG", "乙二醇")
+	}
+	if strings.Contains(keyword, "聚酯") || strings.Contains(keyword, "长丝") || strings.Contains(keyword, "短纤") || strings.Contains(keyword, "瓶片") {
+		keywordArr = append(keywordArr, "聚酯", "长丝", "短纤", "瓶片")
+	}
+	if strings.Contains(keyword, "纯苯") || strings.Contains(keyword, "苯乙烯") || strings.Contains(keyword, "EB") {
+		keywordArr = append(keywordArr, "纯苯", "苯乙烯", "EB")
+	}
+	if strings.Contains(keyword, "甲醇") || strings.Contains(keyword, "MA") {
+		keywordArr = append(keywordArr, "甲醇", "MA")
+	}
+	if strings.Contains(keyword, "橡胶") || strings.Contains(keyword, "RU") {
+		keywordArr = append(keywordArr, "橡胶", "RU")
+	}
+	if strings.Contains(keyword, "聚乙烯") || strings.Contains(keyword, "PP") || strings.Contains(keyword, "PE") {
+		keywordArr = append(keywordArr, "聚乙烯", "PP", "PE")
+	}
+	if strings.Contains(keyword, "玻璃") || strings.Contains(keyword, "纯碱") || strings.Contains(keyword, "FG") || strings.Contains(keyword, "SA") {
+		keywordArr = append(keywordArr, "玻璃", "纯碱", "FG", "SA")
+	}
+	keyword = strings.Join(keywordArr, ",")
+	return keyword
+}
+
+func SearchReport(keyWord string, pageIndex, pageSize int) (ret *response.ReportSearchResp, err error, errMsg string) {
+	//查询正常状态的分类
+	keyWord = addAliasToKeyword(keyWord)
+	searchResp, total, err := elastic.SearchReport(keyWord, []int{}, []int{}, pageIndex, pageSize)
+	if err != nil {
+		errMsg = err.Error()
+		err = errors.New("查询失败")
+		return
+	}
+	var reportList []*models.ReportCollectListItem
+	if searchResp.Hits != nil {
+		for _, v := range searchResp.Hits.Hits {
+			temp := new(models.ReportCollectListItem)
+			itemJson, tmpErr := v.Source.MarshalJSON()
+			if tmpErr != nil {
+				errMsg = tmpErr.Error()
+				err = errors.New("解析出错")
+				return
+			}
+			reportItem := new(response.EsReportItem)
+			tmpErr = json.Unmarshal(itemJson, &reportItem)
+			if tmpErr != nil {
+				errMsg = tmpErr.Error()
+				err = errors.New("解析json出错")
+				return
+			}
+			temp.ReportId = reportItem.ReportId
+			temp.ReportChapterId = reportItem.ReportChapterId
+			temp.ClassifyIdFirst = reportItem.ClassifyIdFirst
+			temp.ClassifyNameFirst = reportItem.ClassifyNameFirst
+			temp.ClassifyIdSecond = reportItem.ClassifyIdSecond
+			temp.ClassifyNameSecond = reportItem.ClassifyNameSecond
+			temp.Title = reportItem.Title
+			temp.ContentSub = reportItem.BodyContent
+			temp.PublishTime, err = time.ParseInLocation(utils.FormatDateTime, reportItem.PublishTime, time.Local)
+
+			if len(v.Highlight["Title"]) > 0 {
+				temp.Title = v.Highlight["Title"][0]
+			}
+			if len(v.Highlight["BodyContent"]) > 0 {
+				temp.ContentSub = v.Highlight["BodyContent"][0]
+			}
+			//if len(v.Highlight["Categories"]) > 0 {
+			//	if temp.ClassifyNameSecond != "" {
+			//		temp.ClassifyNameSecond = "<span style=\"color:#E3B377\">"+temp.ClassifyNameSecond+"</span>"
+			//	}
+			//	if temp.ClassifyNameFirst != "" {
+			//		temp.ClassifyNameFirst = "<span style=\"color:#E3B377\">"+temp.ClassifyNameFirst+"</span>"
+			//	}
+			//}
+			temp.ContentSub = GetReportContentSub(temp.ContentSub, false)
+			reportList = append(reportList, temp)
+		}
+	}
+	ret = new(response.ReportSearchResp)
+	ret.List = reportList
+	ret.Paging = paging.GetPaging(pageIndex, pageSize, int(total))
+	return
+}
+
+// GetReportContentSub 特殊处理contentSub
+func GetReportContentSub(content string, scapeFlag bool) (contentSub string) {
+	if scapeFlag {
+		content = html.UnescapeString(content)
+		content = utils.TrimHtml(content) //只展示纯文本
+	}
+	contentSub = "<div style=\"-webkit-line-clamp: 3;-webkit-box-orient: vertical;display: -webkit-box;overflow: hidden;text-overflow: ellipsis;\">" + content + "</div>"
+	return
+}

+ 17 - 0
utils/common.go

@@ -5,6 +5,7 @@ import (
 	"crypto/sha256"
 	"encoding/base64"
 	"fmt"
+	"regexp"
 	"sort"
 	"strconv"
 	"strings"
@@ -71,3 +72,19 @@ func StartIndex(page, pagesize int) int {
 	}
 	return 0
 }
+
+// TrimHtml
+func TrimHtml(src string) string {
+	//将HTML标签全转换成小写
+	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
+	src = re.ReplaceAllStringFunc(src, strings.ToLower)
+
+	re, _ = regexp.Compile("\\<img[\\S\\s]+?\\>")
+	src = re.ReplaceAllString(src, "")
+
+	re, _ = regexp.Compile("class[\\S\\s]+?>")
+	src = re.ReplaceAllString(src, "")
+	re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
+	src = re.ReplaceAllString(src, "")
+	return strings.TrimSpace(src)
+}

+ 29 - 0
utils/config.go

@@ -16,6 +16,7 @@ var (
 
 	REDIS_CACHE string      //缓存地址
 	Rc          RedisClient //redis缓存
+
 )
 
 var (
@@ -44,6 +45,20 @@ var (
 	TEMPLATE_ID_BY_PRODUCT string
 )
 
+// ES配置
+var (
+	ES_URL      string // ES服务器地址
+	ES_USERNAME string // ES账号
+	ES_PASSWORD string // ES密码
+)
+
+// ES索引配置
+var (
+	EsReportIndexName              string //研报ES索引
+	EsSemanticAnalysisDocIndexName string //ES语义分析文档索引名
+	SmartReportIndexName           string //智能研报ES索引
+)
+
 func init() {
 	tmpRunMode, err := web.AppConfig.String("run_mode")
 	if err != nil {
@@ -87,4 +102,18 @@ func init() {
 
 	Rc = redisClient
 
+	// ES配置
+	{
+		ES_URL = config["es_url"]
+		ES_USERNAME = config["es_username"]
+		ES_PASSWORD = config["es_password"]
+	}
+	// ES 索引
+	{
+		EsReportIndexName = config["es_report_index_name"]
+		EsSemanticAnalysisDocIndexName = config["es_semantic_analysis_doc_index_name"]
+		SmartReportIndexName = config["es_smart_report_index_name"]
+	}
+	initEs()
+
 }

+ 21 - 0
utils/elastic.go

@@ -0,0 +1,21 @@
+package utils
+
+import (
+	"github.com/olivere/elastic/v7"
+)
+
+// EsClient es客户端
+var EsClient *elastic.Client
+
+func initEs() {
+	client, err := elastic.NewClient(
+		elastic.SetURL(ES_URL),
+		elastic.SetBasicAuth(ES_USERNAME, ES_PASSWORD),
+		elastic.SetSniff(false))
+	EsClient = client
+	if err != nil {
+		panic("ElasticSearch连接失败,err:" + err.Error())
+		//go alarm_msg.SendAlarmMsg("ElasticSearch连接失败", 2)
+	}
+	return
+}