|
@@ -0,0 +1,300 @@
|
|
|
+package es
|
|
|
+
|
|
|
+import (
|
|
|
+ MC "app.yhyue.com/moapp/jybase/common"
|
|
|
+ elastic "app.yhyue.com/moapp/jybase/esv1"
|
|
|
+ "fmt"
|
|
|
+ "jyBXCore/rpc/entity"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+const (
|
|
|
+ queryByIds = `{"query":{"bool":{"must":[{"terms":{"_id":[%s]}}]}}}`
|
|
|
+ multiMatch = `{"multi_match": {"query": %s,"type": "phrase", "fields": [%s]}}`
|
|
|
+ query = `{"query":{"bool":{"must":[%s],"must_not":[%s],"should":[%s],"minimum_should_match": %d}}}`
|
|
|
+ queryBoolShould = `{"bool":{"should":[%s],"minimum_should_match": 1}}`
|
|
|
+ queryPrice = `{"bool":{"must":[{"range":{"bidamount":{%s}}}]}},{"bool":{"must":[{"range":{"budget":{%s}}}],"must_not":[{"range":{"bidamount":{"gte":-1}}}]}}`
|
|
|
+ queryBoolMust = `{"terms":{"%s":[%s]}}`
|
|
|
+ queryBoolMustAnd = `{"bool":{"must":[%s]%s}}`
|
|
|
+ queryMissing = `{"constant_score":{"filter":{"missing":{"field":"%s"}}}}`
|
|
|
+ queryBoolMustTerm = `{"bool": {"must": [{ "term": {"isValidFile": %d }}]}}`
|
|
|
+ gte = `"gte": %s`
|
|
|
+ lte = `"lte": %s`
|
|
|
+ queryPublishTime = `{"range":{"publishtime":{%s}}}`
|
|
|
+)
|
|
|
+
|
|
|
+var topType = map[string]string{
|
|
|
+ "招标预告": "预告",
|
|
|
+ "招标公告": "招标",
|
|
|
+ "招标结果": "结果",
|
|
|
+ "招标信用信息": "其它",
|
|
|
+ "拟建项目": "拟建",
|
|
|
+ "采购意向": "采购意向",
|
|
|
+}
|
|
|
+
|
|
|
+type SearchQuery struct{}
|
|
|
+
|
|
|
+func (s *SearchQuery) BiddingSearchQuery(bsp *entity.BiddingSearchParams) (qstr string) {
|
|
|
+ if len(bsp.SelectIds) > 0 {
|
|
|
+ return fmt.Sprintf(queryByIds, `"`+strings.Join(bsp.SelectIds, `","`)+`"`)
|
|
|
+ }
|
|
|
+
|
|
|
+ var bools []string
|
|
|
+ var musts = []string{fmt.Sprintf(`{"range":{"comeintime":{"lt":%d}}}`, bsp.ComeInTime)}
|
|
|
+ var mustNot []string
|
|
|
+ //地区
|
|
|
+ var area []string
|
|
|
+ //省份
|
|
|
+ if len(bsp.Province) > 0 {
|
|
|
+ areaquery := `{"terms":{"area":[`
|
|
|
+ for k, v := range bsp.Province {
|
|
|
+ if k > 0 {
|
|
|
+ areaquery += `,`
|
|
|
+ }
|
|
|
+ areaquery += `"` + v + `"`
|
|
|
+ }
|
|
|
+ areaquery += `]}}`
|
|
|
+ area = append(area, areaquery)
|
|
|
+ }
|
|
|
+ //城市
|
|
|
+ if len(bsp.City) > 0 {
|
|
|
+ areaquery := `{"terms":{"city":[`
|
|
|
+ for k, v := range bsp.City {
|
|
|
+ if k > 0 {
|
|
|
+ areaquery += `,`
|
|
|
+ }
|
|
|
+ areaquery += `"` + v + `"`
|
|
|
+ }
|
|
|
+ areaquery += `]}}`
|
|
|
+ area = append(area, areaquery)
|
|
|
+ }
|
|
|
+ if len(area) > 0 {
|
|
|
+ musts = append(musts, fmt.Sprintf(queryBoolShould, strings.Join(area, ",")))
|
|
|
+ }
|
|
|
+ //检索日期
|
|
|
+ //发布时间
|
|
|
+ startTime := ""
|
|
|
+ now := time.Unix(bsp.ComeInTime, 0)
|
|
|
+ endTime := fmt.Sprintf("%d", now.Unix())
|
|
|
+ if strings.Contains(bsp.PublishTime, "_") { //设置检索日期
|
|
|
+ timeQuery := ``
|
|
|
+ startTime = strings.Split(bsp.PublishTime, "_")[0]
|
|
|
+ endTimeTmp := now
|
|
|
+ if etime := strings.Split(bsp.PublishTime, "_")[1]; etime != "" {
|
|
|
+ etTime := time.Unix(MC.Int64All(etime), 0)
|
|
|
+ endTimeTmp = time.Date(etTime.Year(), etTime.Month(), etTime.Day()+1, 0, 0, 0, 0, time.Local)
|
|
|
+ }
|
|
|
+ //结束时间必须小于筛选时间
|
|
|
+ if endTimeTmp.After(now) {
|
|
|
+ endTimeTmp = now
|
|
|
+ }
|
|
|
+ endTime = fmt.Sprintf("%d", endTimeTmp.Unix())
|
|
|
+ if startTime != "" {
|
|
|
+ timeQuery += fmt.Sprintf(gte, startTime)
|
|
|
+ }
|
|
|
+ if startTime != "" && endTime != "" {
|
|
|
+ timeQuery += `,`
|
|
|
+ }
|
|
|
+ if endTime != "" {
|
|
|
+ timeQuery += fmt.Sprintf(lte, endTime)
|
|
|
+ }
|
|
|
+ musts = append(musts, fmt.Sprintf(queryPublishTime, timeQuery))
|
|
|
+ }
|
|
|
+ //信息类型 toptype 一级;subtype 二级;
|
|
|
+ if bsp.Subtype != "" || bsp.Toptype != "" {
|
|
|
+ var subQuery string
|
|
|
+ var topTypes = strings.Split(bsp.Toptype, ",")
|
|
|
+ var subTypes = strings.Split(bsp.Subtype, ",")
|
|
|
+ for _, v := range strings.Split(bsp.Subtype, ",") {
|
|
|
+ if v1, ok := topType[v]; ok {
|
|
|
+ topTypes = append(topTypes, fmt.Sprintf(`"%s"`, v1))
|
|
|
+ } else {
|
|
|
+ subTypes = append(subTypes, fmt.Sprintf(`"%s"`, v))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if len(subTypes) > 0 && len(topTypes) > 0 {
|
|
|
+ subQuery = fmt.Sprintf(`{"bool": {"should": [{"terms": {"subtype": [%s]}},{"terms": {"toptype": [%s]}}]}}`, strings.Join(subTypes, ","), strings.Join(topTypes, ","))
|
|
|
+ } else if len(subTypes) > 0 {
|
|
|
+ subQuery = fmt.Sprintf(`{"terms":{"subtype":[%s]}}`, strings.Join(subTypes, ","))
|
|
|
+ } else if len(topTypes) > 0 {
|
|
|
+ subQuery = fmt.Sprintf(`{"terms":{"toptype":[%s]}}`, strings.Join(topTypes, ","))
|
|
|
+ }
|
|
|
+ musts = append(musts, subQuery)
|
|
|
+ }
|
|
|
+ //行业
|
|
|
+ if len(bsp.Industry) > 0 {
|
|
|
+ musts = append(musts, fmt.Sprintf(queryBoolMust, "s_subscopeclass", `"`+strings.Join(bsp.Industry, `","`)+`"`))
|
|
|
+ }
|
|
|
+ //采购单位
|
|
|
+ if len(bsp.Buyer) > 0 {
|
|
|
+ musts = append(musts, fmt.Sprintf(queryBoolMust, "buyer", `"`+strings.Join(bsp.Buyer, `","`)+`"`))
|
|
|
+ }
|
|
|
+ //采购单位类型
|
|
|
+ if len(bsp.BuyerClass) > 0 {
|
|
|
+ musts = append(musts, fmt.Sprintf(queryBoolMust, "buyerclass", `"`+strings.Join(bsp.BuyerClass, `","`)+`"`))
|
|
|
+ }
|
|
|
+ //中标单位
|
|
|
+ if len(bsp.Winner) > 0 {
|
|
|
+ musts = append(musts, fmt.Sprintf(queryBoolMust, "s_winner", `"`+strings.Join(bsp.Winner, `","`)+`"`))
|
|
|
+ }
|
|
|
+ //价格区间
|
|
|
+ if bsp.MinPrice != "" || bsp.MaxPrice != "" {
|
|
|
+ _minPrice := ""
|
|
|
+ _maxPrice := ""
|
|
|
+ sq := ``
|
|
|
+ if bsp.MinPrice != "" {
|
|
|
+ min, _ := strconv.ParseFloat(bsp.MinPrice, 64)
|
|
|
+ _minPrice = fmt.Sprintf("%.0f", min*10000)
|
|
|
+ if _minPrice == "0" {
|
|
|
+ _minPrice = ""
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if bsp.MaxPrice != "" {
|
|
|
+ max, _ := strconv.ParseFloat(bsp.MaxPrice, 64)
|
|
|
+ _maxPrice = fmt.Sprintf("%.0f", max*10000)
|
|
|
+ if _maxPrice == "0" {
|
|
|
+ _maxPrice = ""
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if _minPrice != "" {
|
|
|
+ sq += fmt.Sprintf(gte, _minPrice)
|
|
|
+ }
|
|
|
+ if _minPrice != "" && _maxPrice != "" {
|
|
|
+ sq += `,`
|
|
|
+ }
|
|
|
+ if _maxPrice != "" {
|
|
|
+ sq += fmt.Sprintf(lte, _maxPrice)
|
|
|
+ }
|
|
|
+ if _minPrice != "" || _maxPrice != "" {
|
|
|
+ musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(queryPrice, sq, sq)))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ boolsNum := 0
|
|
|
+ selectType := bsp.SelectType
|
|
|
+ //关键词
|
|
|
+ if len(bsp.Keyword) > 0 {
|
|
|
+ boolsNum = 1
|
|
|
+ queryItem := ""
|
|
|
+ if selectType == "" {
|
|
|
+ queryItem = "title"
|
|
|
+ } else if selectType == "all" {
|
|
|
+ queryItem = "detail\", \"title"
|
|
|
+ } else {
|
|
|
+ //搜索开关打开 包含标题和正文 只匹配正文
|
|
|
+ if bsp.SearchTypeSwitch && s.DetailANDTitle(selectType) {
|
|
|
+ if strings.Contains(selectType, "title,") {
|
|
|
+ selectType = strings.Replace(selectType, "title,", "", -1)
|
|
|
+ } else if strings.Contains(selectType, ",title") {
|
|
|
+ selectType = strings.Replace(selectType, ",title", "", -1)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ queryItem = strings.ReplaceAll(selectType, ",", "\",\"")
|
|
|
+ }
|
|
|
+ multiMatchNew := fmt.Sprintf(multiMatch, "%s", "\""+queryItem+"\"")
|
|
|
+ for _, v := range bsp.Keyword {
|
|
|
+ var should []string
|
|
|
+ var mustNot []string
|
|
|
+ if v.Keyword != "" {
|
|
|
+ if strings.Contains(v.Keyword, "+") {
|
|
|
+ for _, vk := range strings.Split(v.Keyword, "+") {
|
|
|
+ //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
|
|
|
+ if bsp.ComeInFrom == "supersearchPage" && s.DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vk))) == 1 {
|
|
|
+ queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
|
|
|
+ shouldKeys := fmt.Sprintf(multiMatch, "\""+vk+"\"", "\""+queryItem+"\"")
|
|
|
+ should = append(should, shouldKeys)
|
|
|
+ } else {
|
|
|
+ should = append(should, fmt.Sprintf(multiMatchNew, "\""+vk+"\""))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if strings.Contains(v.Keyword, " ") {
|
|
|
+ for _, vk := range strings.Split(v.Keyword, " ") {
|
|
|
+ //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
|
|
|
+ if bsp.ComeInFrom == "supersearchPage" && s.DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vk))) == 1 {
|
|
|
+ queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
|
|
|
+ shouldKeys := fmt.Sprintf(multiMatch, "\""+vk+"\"", "\""+queryItem+"\"")
|
|
|
+ should = append(should, shouldKeys)
|
|
|
+ } else {
|
|
|
+ should = append(should, fmt.Sprintf(multiMatchNew, "\""+vk+"\""))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
|
|
|
+ if bsp.ComeInFrom == "supersearchPage" && s.DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(v.Keyword))) == 1 {
|
|
|
+ queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
|
|
|
+ shouldKeys := fmt.Sprintf(multiMatch, "\""+v.Keyword+"\"", "\""+queryItem+"\"")
|
|
|
+ should = append(should, shouldKeys)
|
|
|
+ } else {
|
|
|
+ should = append(should, fmt.Sprintf(multiMatchNew, "\""+v.Keyword+"\""))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //附加词
|
|
|
+ for _, vv := range v.Appended {
|
|
|
+ should = append(should, fmt.Sprintf(multiMatchNew, "\""+vv+"\""))
|
|
|
+ }
|
|
|
+
|
|
|
+ //排除词
|
|
|
+ for _, vv := range v.Exclude {
|
|
|
+ //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
|
|
|
+ if bsp.ComeInFrom == "supersearchPage" && s.DetailFileORTitle(selectType) && len([]rune(elastic.ReplaceYH(vv))) == 1 {
|
|
|
+ queryItem = strings.ReplaceAll(selectType+",title", ",", "\",\"")
|
|
|
+ shouldKeys := fmt.Sprintf(multiMatch, "\""+vv+"\"", "\""+queryItem+"\"")
|
|
|
+ should = append(should, shouldKeys)
|
|
|
+ } else {
|
|
|
+ mustNot = append(mustNot, fmt.Sprintf(multiMatchNew, "\""+vv+"\""))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //添加
|
|
|
+ if len(should) > 0 {
|
|
|
+ notStr := ""
|
|
|
+ if len(mustNot) > 0 {
|
|
|
+ notStr = fmt.Sprintf(`,"must_not":[%s]`, strings.Join(mustNot, ","))
|
|
|
+ }
|
|
|
+ bools = append(bools, fmt.Sprintf(queryBoolMustAnd, strings.Join(should, ","), notStr))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //采购单位联系方式
|
|
|
+ if bsp.HasBuyerTel != "" {
|
|
|
+ if bsp.HasBuyerTel == "y" {
|
|
|
+ mustNot = append(mustNot, fmt.Sprintf(queryMissing, "buyertel"))
|
|
|
+ } else {
|
|
|
+ musts = append(musts, fmt.Sprintf(queryMissing, "buyertel"))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //中标企业联系方式
|
|
|
+ if bsp.HasWinnerTel != "" {
|
|
|
+ if bsp.HasWinnerTel == "y" {
|
|
|
+ mustNot = append(mustNot, fmt.Sprintf(queryMissing, "winnertel"))
|
|
|
+ } else {
|
|
|
+ musts = append(musts, fmt.Sprintf(queryMissing, "winnertel"))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //搜索范围是否只有附件
|
|
|
+ //搜索范围只选择附件,是否有附件条件无效;
|
|
|
+ var isFileSearch = strings.ReplaceAll(selectType, ",", "\",\"") == "filetext"
|
|
|
+ if !isFileSearch && bsp.FileExists != "" {
|
|
|
+ if bsp.FileExists == "1" { //有附件
|
|
|
+ mustNot = append(mustNot, fmt.Sprintf(queryMissing, "isValidFile"))
|
|
|
+ musts = append(musts, fmt.Sprintf(queryBoolMustTerm, 1))
|
|
|
+ } else if bsp.FileExists == "-1" { //无附件
|
|
|
+ musts = append(musts, fmt.Sprintf(queryMissing, "isValidFile"))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ qstr = fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(mustNot, ","), strings.Join(bools, ","), boolsNum)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// DetailFileORTitle 包含正文或 附件 不包含标题
|
|
|
+func (s *SearchQuery) DetailFileORTitle(findFields string) bool {
|
|
|
+ return (strings.Contains(findFields, "detail") || strings.Contains(findFields, "filetext")) && !strings.Contains(findFields, "title")
|
|
|
+}
|
|
|
+
|
|
|
+// DetailANDTitle 包含正文包含标题
|
|
|
+func (s *SearchQuery) DetailANDTitle(findFields string) bool {
|
|
|
+ return strings.Contains(findFields, "detail") && strings.Contains(findFields, "title")
|
|
|
+}
|