|
@@ -0,0 +1,624 @@
|
|
|
|
+package bidSearch
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "context"
|
|
|
|
+ "fmt"
|
|
|
|
+ "strconv"
|
|
|
|
+ "strings"
|
|
|
|
+ "time"
|
|
|
|
+
|
|
|
|
+ . "app.yhyue.com/moapp/jybase/common"
|
|
|
|
+ . "app.yhyue.com/moapp/jybase/encrypt"
|
|
|
|
+ elastic "app.yhyue.com/moapp/jybase/es"
|
|
|
|
+ "github.com/gogf/gf/v2/encoding/gjson"
|
|
|
|
+ "github.com/gogf/gf/v2/frame/g"
|
|
|
|
+ "github.com/gogf/gf/v2/os/gtime"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+const (
|
|
|
|
+ JYKeyMark = "+"
|
|
|
|
+ MultiMatch = `{"multi_match": {"query": "%s","type": "phrase", "fields": [%s]}}`
|
|
|
|
+ Query = `{"query":{"bool":{"must":[%s],"must_not":[%s]}}%s}`
|
|
|
|
+ QueryBoolShould = `{"bool":{"should":[%s],"minimum_should_match": 1}}`
|
|
|
|
+ queryBoolMustBoolShould = `{"bool":{"must":[{"range":{"bidamount":{%s}}}]}},{"bool":{"must":[{"range":{"budget":{%s}}}],"must_not":[{"range":{"bidamount":{"gte":-1}}}]}}`
|
|
|
|
+ QueryBoolMustTermBool = `{"bool": {"must": [{ "term": {"%s": %t }}]}}`
|
|
|
|
+ QueryBoolMustA = `{"bool":{"must":[{"terms":{"%s":[%s]}}]}}`
|
|
|
|
+ queryExists = `{"constant_score":{"filter":{"exists":{"field":"%s"}}}}`
|
|
|
|
+ gte = `"gte": %s`
|
|
|
|
+ lte = `"lte": %s`
|
|
|
|
+ INDEX = "bidding"
|
|
|
|
+ TYPE = "bidding"
|
|
|
|
+ BidSearchSort = `{"dataweight":"desc","publishtime":"desc"}`
|
|
|
|
+ BidSearchFieldBase = `"_id","title","publishtime","dataweight","toptype","subtype","type","area","city","s_subscopeclass","bidamount","budget","buyerclass","isValidFile","district"` //搜索列表基础字段
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+var (
|
|
|
|
+ //信息类型 一级类型参数和数据类型转换
|
|
|
|
+ topTypeMap = map[string]string{
|
|
|
|
+ "招标预告": "预告",
|
|
|
|
+ "招标公告": "招标",
|
|
|
|
+ "招标结果": "结果",
|
|
|
|
+ "招标信用信息": "其它",
|
|
|
|
+ "拟建项目": "拟建",
|
|
|
|
+ "采购意向": "采购意向",
|
|
|
|
+ }
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+type BidSearch struct {
|
|
|
|
+ ctx context.Context
|
|
|
|
+ PositionId int64
|
|
|
|
+ PageNum int64 //当前页码
|
|
|
|
+ PageSize int64 //每页数量
|
|
|
|
+ Province string //省份
|
|
|
|
+ City string //城市
|
|
|
|
+ Subtype string //信息类型-二级
|
|
|
|
+ TopType string //信息类型-一级分类
|
|
|
|
+ PublishTime string //发布时间
|
|
|
|
+ SelectType string //搜索范围:标题;正文等
|
|
|
|
+ Price string //价格
|
|
|
|
+ Industry string //行业
|
|
|
|
+ BuyerClass string //采购单位类型
|
|
|
|
+ BuyerTel string //采购单位联系方式
|
|
|
|
+ WinnerTel string //中标单位联系方式
|
|
|
|
+ FileExists string //是否有附件
|
|
|
|
+ WordsMode int64 //搜索关键词模式;默认0:包含所有,1:包含任意
|
|
|
|
+ KeyWords string //关键词:多个空格隔开(主)
|
|
|
|
+ AdditionalWords string //关键词:附加关键词(副:五组,每组最多15个字符)
|
|
|
|
+ ExclusionWords string //关键词:排除词(副:五组,每组最多15个字符)
|
|
|
|
+ District string //区县
|
|
|
|
+ Buyer string //采购单位
|
|
|
|
+ Winner string //中标企业
|
|
|
|
+ Agency string //代理机构
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func NewBidSearch(ctx context.Context, positionId int64, content string) (*BidSearch, error) {
|
|
|
|
+ c, e := gjson.LoadJson([]byte(content))
|
|
|
|
+ if e != nil {
|
|
|
|
+ g.Log().Error(ctx, positionId, "查询条件转换出错", e)
|
|
|
|
+ return nil, e
|
|
|
|
+ }
|
|
|
|
+ keyWords, exclusionWords := []string{}, []string{}
|
|
|
|
+ if keyWordJson := c.GetJson("关键词"); keyWordJson != nil {
|
|
|
|
+ keyWords = keyWordJson.Get("选择").Strings()
|
|
|
|
+ exclusionWords = keyWordJson.Get("排除").Strings()
|
|
|
|
+ }
|
|
|
|
+ area, city := []string{}, []string{}
|
|
|
|
+ if areaJson := c.GetJson("地区"); areaJson != nil {
|
|
|
|
+ area = areaJson.Get("选择").Strings()
|
|
|
|
+ //exclusionArea = areaJson.Get("排除").Strings()
|
|
|
|
+ }
|
|
|
|
+ subtype, topType := []string{}, []string{}
|
|
|
|
+ publishTime := "lately-30"
|
|
|
|
+ var paramFilter = func(v string) string {
|
|
|
|
+ if v == "全部" || v == "不限" {
|
|
|
|
+ return ""
|
|
|
|
+ }
|
|
|
|
+ return strings.ReplaceAll(v, " ", "")
|
|
|
|
+ }
|
|
|
|
+ pt := paramFilter(c.Get("发布时间范围").String())
|
|
|
|
+ if pts := strings.Split(pt, "-"); len(pts) == 2 {
|
|
|
|
+ pt_s, pt_s_e := gtime.StrToTimeFormat(pts[0], "Ymd")
|
|
|
|
+ pt_e, pt_e_e := gtime.StrToTimeFormat(pts[1], "Ymd")
|
|
|
|
+ if pt_s_e != nil || pt_e_e != nil {
|
|
|
|
+ g.Log().Error(ctx, positionId, "发布时间转换出错", pt, pt_s_e, pt_e_e)
|
|
|
|
+ } else {
|
|
|
|
+ publishTime = fmt.Sprintf("%d-%d", pt_s.Unix(), pt_e.Unix())
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ price := strings.ReplaceAll(paramFilter(c.Get("金额").String()), "万", "")
|
|
|
|
+ industry := paramFilter(c.Get("industry").String())
|
|
|
|
+ buyerClass := paramFilter(c.Get("采购单位类型").String())
|
|
|
|
+ buyerTel := paramFilter(c.Get("采购单位联系方式").String())
|
|
|
|
+ winnerTel := paramFilter(c.Get("中标单位联系方式").String())
|
|
|
|
+ selectType := []string{}
|
|
|
|
+ for _, t := range strings.Split(paramFilter(c.Get("搜索范围").String()), ",") {
|
|
|
|
+ if t == "content" {
|
|
|
|
+ selectType = append(selectType, "detail")
|
|
|
|
+ } else if t == "buyer" {
|
|
|
|
+ selectType = append(selectType, "buyer.mbuyer")
|
|
|
|
+ } else if t == "winner" {
|
|
|
|
+ selectType = append(selectType, "s_winner.mwinner")
|
|
|
|
+ } else if t == "agency" {
|
|
|
|
+ selectType = append(selectType, "agency.magency")
|
|
|
|
+ } else if t == "title" {
|
|
|
|
+ selectType = append(selectType, "title")
|
|
|
|
+ } else if t == "ppa" {
|
|
|
|
+ selectType = append(selectType, []string{"purchasing", "projectnamb.pname"}...)
|
|
|
|
+ } else if t == "file" { //dev4.7.8 标讯优化:搜索范围附件-》全部用户可用
|
|
|
|
+ selectType = append(selectType, "filetext")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if len(selectType) == 0 {
|
|
|
|
+ selectType = []string{"title", "detail"}
|
|
|
|
+ }
|
|
|
|
+ var wordsMode int64
|
|
|
|
+ if c.Get("匹配模式").String() == "模糊匹配" {
|
|
|
|
+ wordsMode = 1
|
|
|
|
+ }
|
|
|
|
+ bs := &BidSearch{
|
|
|
|
+ PositionId: positionId,
|
|
|
|
+ PageNum: 0, //当前页码
|
|
|
|
+ PageSize: g.Cfg("ai_search.yaml").MustGet(ctx, "allBidListMaxLen").Int64(), //每页数量
|
|
|
|
+ Province: strings.Join(area, ","), //省份
|
|
|
|
+ City: strings.Join(city, ","), //城市
|
|
|
|
+ Subtype: strings.Join(subtype, ","), //信息类型-二级
|
|
|
|
+ TopType: strings.Join(topType, ","), //信息类型-一级分类
|
|
|
|
+ PublishTime: publishTime, //发布时间
|
|
|
|
+ SelectType: strings.Join(selectType, ","), //搜索范围:标题;正文等
|
|
|
|
+ Price: price, //价格
|
|
|
|
+ Industry: industry, //行业
|
|
|
|
+ BuyerClass: buyerClass, //采购单位类型
|
|
|
|
+ BuyerTel: buyerTel, //采购单位联系方式
|
|
|
|
+ WinnerTel: winnerTel, //中标单位联系方式
|
|
|
|
+ FileExists: "", //是否有附件
|
|
|
|
+ WordsMode: wordsMode, //搜索关键词模式;默认0:包含所有,1:包含任意
|
|
|
|
+ KeyWords: strings.Join(keyWords, " "), //关键词:多个空格隔开(主)
|
|
|
|
+ AdditionalWords: "", //关键词:附加关键词(副:五组,每组最多15个字符)
|
|
|
|
+ ExclusionWords: strings.Join(exclusionWords, ","), //关键词:排除词(副:五组,每组最多15个字符)
|
|
|
|
+ District: "",
|
|
|
|
+ Buyer: paramFilter(c.Get("采购单位").String()),
|
|
|
|
+ Winner: paramFilter(c.Get("中标企业").String()),
|
|
|
|
+ Agency: paramFilter(c.Get("招标代理").String()),
|
|
|
|
+ }
|
|
|
|
+ return bs, nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (b *BidSearch) Search() (string, []map[string]interface{}) {
|
|
|
|
+ qstr := b.GetSearchQuery()
|
|
|
|
+ list := elastic.Get(INDEX, TYPE, qstr)
|
|
|
|
+ result := []map[string]interface{}{}
|
|
|
|
+ if list != nil {
|
|
|
|
+ for _, v := range *list {
|
|
|
|
+ m := map[string]interface{}{
|
|
|
|
+ "id": EncodeArticleId2ByCheck(ObjToString(v["_id"])), //ME.EncodeArticleId2ByCheck(ObjToString(v["_id"])) //加密信息id
|
|
|
|
+ "area": ObjToString(v["area"]), //地区
|
|
|
|
+ "buyerClass": ObjToString(v["buyerclass"]), //采购单位类型
|
|
|
|
+ "city": ObjToString(v["city"]), //城市
|
|
|
|
+ "district": ObjToString(v["district"]), // 区县 //城市
|
|
|
|
+ "industry": b.IndustryFormat(b.Industry, strings.Trim(ObjToString(v["s_subscopeclass"]), ",")), //行业
|
|
|
|
+ "publishTime": Int64All(v["publishtime"]), //发布时间
|
|
|
|
+ "subtype": ObjToString(v["subtype"]), //信息类型
|
|
|
|
+ "title": ObjToString(v["title"]),
|
|
|
|
+ }
|
|
|
|
+ m["fileExists"], _ = v["isValidFile"].(bool) //是否有附件
|
|
|
|
+ if budget, ok := v["budget"].(float64); ok && budget > 0 { //预算
|
|
|
|
+ m["budget"] = int64(budget)
|
|
|
|
+ }
|
|
|
|
+ if bidAmount, ok := v["bidamount"].(float64); ok && bidAmount > 0 { //中标金额
|
|
|
|
+ m["bidamount"] = int64(bidAmount)
|
|
|
|
+ }
|
|
|
|
+ result = append(result, m)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return qstr, result
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// GetSearchQuery 整理关键词等查询条件
|
|
|
|
+func (b *BidSearch) GetSearchQuery() (qstr string) {
|
|
|
|
+ mustQuery := b.MustQuery()
|
|
|
|
+ var (
|
|
|
|
+ //搜索范围是否只有附件
|
|
|
|
+ //搜索范围只选择附件,是否有附件条件无效;
|
|
|
|
+ isFileSearch = b.SelectType == "filetext"
|
|
|
|
+ wordsMusts, wordsShould, musts, mustNot []string
|
|
|
|
+ findFields string
|
|
|
|
+ selectTypeArr = strings.Split(b.SelectType, ",")
|
|
|
|
+ )
|
|
|
|
+ if selectTypeArr == nil || len(selectTypeArr) == 0 {
|
|
|
|
+ findFields = `"title"`
|
|
|
|
+ } else {
|
|
|
|
+ findFields = fmt.Sprintf(`"%s"`, strings.Join(selectTypeArr, "\",\""))
|
|
|
|
+ }
|
|
|
|
+ switchBool := strings.Contains(findFields, "detail") && strings.Contains(findFields, "title")
|
|
|
|
+ if mustQuery != "" {
|
|
|
|
+ musts = append(musts, mustQuery)
|
|
|
|
+ }
|
|
|
|
+ //采购单位
|
|
|
|
+ if b.Buyer != "" {
|
|
|
|
+ musts = append(musts, b.GetMatchArrSql("buyer.mbuyer", strings.Split(b.Buyer, ",")...))
|
|
|
|
+ }
|
|
|
|
+ //中标单位
|
|
|
|
+ if b.Winner != "" {
|
|
|
|
+ musts = append(musts, b.GetMatchArrSql("s_winner.mwinner", strings.Split(b.Winner, ",")...))
|
|
|
|
+ }
|
|
|
|
+ //代理机构
|
|
|
|
+ if b.Agency != "" {
|
|
|
|
+ musts = append(musts, b.GetMatchArrSql("agency.magency", strings.Split(b.Agency, ",")...))
|
|
|
|
+ }
|
|
|
|
+ //此时关键词中间有IC.C.JYKeyMark进行隔离
|
|
|
|
+ if b.KeyWords != "" {
|
|
|
|
+ var (
|
|
|
|
+ keyWordsMusts []string
|
|
|
|
+ )
|
|
|
|
+ for _, v := range strings.Split(b.KeyWords, JYKeyMark) {
|
|
|
|
+ if elastic.ReplaceYH(v) == "" {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
|
|
|
|
+ //detail 正文不支持单字查询
|
|
|
|
+ if len([]rune(elastic.ReplaceYH(v))) == 1 && b.DetailFileORTitle(findFields) {
|
|
|
|
+ findFields += `,"title"`
|
|
|
|
+ } else if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
|
|
|
|
+ //标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
|
|
|
|
+ if strings.Contains(findFields, `"title",`) {
|
|
|
|
+ findFields = strings.Replace(findFields, `"title",`, ``, -1)
|
|
|
|
+ } else if strings.Contains(findFields, `,"title"`) {
|
|
|
|
+ findFields = strings.Replace(findFields, `,"title"`, ``, -1)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ keyWordsMusts = append(keyWordsMusts, fmt.Sprintf(fmt.Sprintf(MultiMatch, "%s", findFields), elastic.ReplaceYH(v)))
|
|
|
|
+ }
|
|
|
|
+ //搜索关键词模式;默认0:包含所有,1:包含任意
|
|
|
|
+ if b.WordsMode == 1 {
|
|
|
|
+ wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(keyWordsMusts, ",")))
|
|
|
|
+ } else {
|
|
|
|
+ wordsMusts = append(wordsMusts, keyWordsMusts...)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //附加词
|
|
|
|
+ if b.AdditionalWords != "" {
|
|
|
|
+ //多组附加词,每组间,号隔开。每组内如果关键词中间有空格,自动分词
|
|
|
|
+ var (
|
|
|
|
+ addWordsMusts []string
|
|
|
|
+ )
|
|
|
|
+ for _, aws := range strings.Split(b.AdditionalWords, ",") {
|
|
|
|
+ var (
|
|
|
|
+ addWordsMust []string
|
|
|
|
+ )
|
|
|
|
+ for _, v := range strings.Split(aws, JYKeyMark) {
|
|
|
|
+ if elastic.ReplaceYH(v) == "" {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
|
|
|
|
+ //detail 正文不支持单字查询
|
|
|
|
+ if len([]rune(elastic.ReplaceYH(v))) == 1 && b.DetailFileORTitle(findFields) {
|
|
|
|
+ findFields += `,"title"`
|
|
|
|
+ } else if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
|
|
|
|
+ //标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
|
|
|
|
+ if strings.Contains(findFields, `"title",`) {
|
|
|
|
+ findFields = strings.Replace(findFields, `"title",`, ``, -1)
|
|
|
|
+ } else if strings.Contains(findFields, `,"title"`) {
|
|
|
|
+ findFields = strings.Replace(findFields, `,"title"`, ``, -1)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ addWordsMust = append(addWordsMust, fmt.Sprintf(fmt.Sprintf(MultiMatch, "%s", findFields), elastic.ReplaceYH(v)))
|
|
|
|
+ addWordsMusts = append(addWordsMusts, addWordsMust...)
|
|
|
|
+ if b.WordsMode == 0 {
|
|
|
|
+ wordsMusts = append(wordsMusts, addWordsMust...)
|
|
|
|
+ }
|
|
|
|
+ addWordsMust = []string{}
|
|
|
|
+ }
|
|
|
|
+ //搜索关键词模式;默认0:包含所有,1:包含任意
|
|
|
|
+ if b.WordsMode == 1 {
|
|
|
|
+ wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(addWordsMusts, ",")))
|
|
|
|
+ addWordsMusts = []string{}
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //搜索关键词模式;默认0:包含所有,1:包含任意
|
|
|
|
+ //包含任意一组
|
|
|
|
+ if len(wordsShould) > 0 {
|
|
|
|
+ musts = append(musts, fmt.Sprintf(QueryBoolShould, strings.Join(wordsShould, ",")))
|
|
|
|
+ } else if len(wordsMusts) > 0 {
|
|
|
|
+ musts = append(musts, fmt.Sprintf(elastic.NgramMust, strings.Join(wordsMusts, ",")))
|
|
|
|
+ }
|
|
|
|
+ //排除词
|
|
|
|
+ if notKey := strings.TrimSpace(b.ExclusionWords); notKey != "" {
|
|
|
|
+ notKeyMultiMatch := fmt.Sprintf(MultiMatch, "%s", findFields)
|
|
|
|
+ var notKeyMustNot []string
|
|
|
|
+ //多组排除词
|
|
|
|
+ for _, nks := range strings.Split(notKey, ",") {
|
|
|
|
+ //单组排除词 空格分割
|
|
|
|
+ for _, v := range strings.Split(nks, JYKeyMark) {
|
|
|
|
+ v = strings.TrimSpace(v)
|
|
|
|
+ if v == "" {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ if len([]rune(elastic.ReplaceYH(v))) == 1 {
|
|
|
|
+ //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
|
|
|
|
+ if b.DetailFileORTitle(findFields) {
|
|
|
|
+ notKeyMultiMatch = fmt.Sprintf(MultiMatch, "%s", findFields+`,"title"`)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ notKeyMustNot = append(notKeyMustNot, fmt.Sprintf(notKeyMultiMatch, elastic.ReplaceYH(v)))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ mustNot = append(mustNot, fmt.Sprintf(QueryBoolShould, strings.Join(notKeyMustNot, ",")))
|
|
|
|
+ }
|
|
|
|
+ //行业
|
|
|
|
+ if b.Industry != "" {
|
|
|
|
+ musts = append(musts, fmt.Sprintf(QueryBoolMustA, "s_subscopeclass", `"`+strings.ReplaceAll(b.Industry, ",", `","`)+`"`))
|
|
|
|
+ }
|
|
|
|
+ //价格
|
|
|
|
+ if b.Price != "" && len(strings.Split(b.Price, "-")) > 1 {
|
|
|
|
+ minPrice, maxPrice := strings.Split(b.Price, "-")[0], strings.Split(b.Price, "-")[1]
|
|
|
|
+ if minPrice != "" || maxPrice != "" {
|
|
|
|
+ sq := ``
|
|
|
|
+ if minPrice != "" {
|
|
|
|
+ min, _ := strconv.ParseFloat(minPrice, 64)
|
|
|
|
+ minPrice = fmt.Sprintf("%.0f", min*10000)
|
|
|
|
+ if minPrice == "0" {
|
|
|
|
+ minPrice = ""
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if maxPrice != "" {
|
|
|
|
+ max, _ := strconv.ParseFloat(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 != "" {
|
|
|
|
+ query_price := fmt.Sprintf(QueryBoolShould, fmt.Sprintf(queryBoolMustBoolShould, sq, sq))
|
|
|
|
+ musts = append(musts, query_price)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //采购单位联系方式
|
|
|
|
+ hasBuyerTel := b.BuyerTel
|
|
|
|
+ if hasBuyerTel != "" {
|
|
|
|
+ if hasBuyerTel == "y" {
|
|
|
|
+ musts = append(musts, fmt.Sprintf(queryExists, "buyertel"))
|
|
|
|
+ } else {
|
|
|
|
+ mustNot = append(mustNot, fmt.Sprintf(queryExists, "buyertel"))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //中标企业联系方式
|
|
|
|
+ hasWinnerTel := b.WinnerTel
|
|
|
|
+ if hasWinnerTel != "" {
|
|
|
|
+ if hasWinnerTel == "y" {
|
|
|
|
+ musts = append(musts, fmt.Sprintf(queryExists, "winnertel"))
|
|
|
|
+ } else {
|
|
|
|
+ mustNot = append(mustNot, fmt.Sprintf(queryExists, "winnertel"))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //附件--非BI
|
|
|
|
+ fileExists := b.FileExists
|
|
|
|
+ if !isFileSearch && fileExists != "" {
|
|
|
|
+ if fileExists == "1" { //有附件
|
|
|
|
+ musts = append(musts, fmt.Sprintf(QueryBoolMustTermBool, "isValidFile", true))
|
|
|
|
+ } else if fileExists == "-1" { //无附件
|
|
|
|
+ mustNot = append(mustNot, fmt.Sprintf(QueryBoolMustTermBool, "isValidFile", true))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //b.BidField 剑鱼默认招标信息搜索 此参数为空**
|
|
|
|
+ qstr = fmt.Sprintf(Query, strings.Join(musts, ","), strings.Join(mustNot, ","), fmt.Sprintf(`,"_source":[%s],"sort":[%s],"from":%d,"size":%d`, BidSearchFieldBase, BidSearchSort, b.PageNum, b.PageSize))
|
|
|
|
+ return
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// GetBidSearchQuery 整理地区、城市、发布时间、信息类型、采购单位类型 查询条件
|
|
|
|
+func (b *BidSearch) MustQuery() string {
|
|
|
|
+ query := ``
|
|
|
|
+ //省份
|
|
|
|
+ area := b.Province
|
|
|
|
+ if area != "" {
|
|
|
|
+ query += `{"terms":{"area":[`
|
|
|
|
+ for k, v := range strings.Split(area, ",") {
|
|
|
|
+ if k > 0 {
|
|
|
|
+ query += `,`
|
|
|
|
+ }
|
|
|
|
+ query += `"` + v + `"`
|
|
|
|
+ }
|
|
|
|
+ query += `]}}`
|
|
|
|
+ }
|
|
|
|
+ //市--未登录用户不能根据市和地区筛选
|
|
|
|
+ city := b.City
|
|
|
|
+ if city != "" {
|
|
|
|
+ if len(query) > 0 {
|
|
|
|
+ query += ","
|
|
|
|
+ }
|
|
|
|
+ query += `{"terms":{"city":[`
|
|
|
|
+ for k, v := range strings.Split(city, ",") {
|
|
|
|
+ if k > 0 {
|
|
|
|
+ query += `,`
|
|
|
|
+ }
|
|
|
|
+ query += `"` + v + `"`
|
|
|
|
+ }
|
|
|
|
+ query += `]}}`
|
|
|
|
+ }
|
|
|
|
+ district := b.District
|
|
|
|
+ if district != "" {
|
|
|
|
+ if len(query) > 0 {
|
|
|
|
+ query += ","
|
|
|
|
+ }
|
|
|
|
+ for k, v := range strings.Split(district, ",") {
|
|
|
|
+ if k > 0 {
|
|
|
|
+ query += `,`
|
|
|
|
+ }
|
|
|
|
+ cityName := strings.Split(v, "_")[0]
|
|
|
|
+ districtName := strings.Split(v, "_")[1]
|
|
|
|
+ queryBoolMustAndDistrict := `{"bool":{"must":[{"terms":{"city":["%s"]}},{"terms":{"district":["%s"]}}]}}`
|
|
|
|
+ query += fmt.Sprintf(queryBoolMustAndDistrict, cityName, districtName)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if query != "" {
|
|
|
|
+ query = fmt.Sprintf(QueryBoolShould, query)
|
|
|
|
+ }
|
|
|
|
+ //发布时间
|
|
|
|
+ publishTime := b.PublishTime
|
|
|
|
+ if publishTime != "" {
|
|
|
|
+ startTime, endTime := "", ""
|
|
|
|
+ now := time.Now()
|
|
|
|
+ switch publishTime {
|
|
|
|
+ case "lately-7":
|
|
|
|
+ startTime = fmt.Sprint(time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, time.Local).Unix())
|
|
|
|
+ case "lately-30":
|
|
|
|
+ startTime = fmt.Sprint(time.Date(now.Year(), now.Month(), now.Day()-30, 0, 0, 0, 0, time.Local).Unix())
|
|
|
|
+ case "thisyear":
|
|
|
|
+ startTime = fmt.Sprint(time.Date(now.Year()-1, now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Unix())
|
|
|
|
+ endTime = fmt.Sprint(now.Unix())
|
|
|
|
+ case "threeyear":
|
|
|
|
+ startTime = fmt.Sprint(time.Date(now.Year()-3, now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Unix())
|
|
|
|
+ endTime = fmt.Sprint(now.Unix())
|
|
|
|
+ case "fiveyear":
|
|
|
|
+ startTime = fmt.Sprint(time.Date(now.Year()-5, now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Unix())
|
|
|
|
+ endTime = fmt.Sprint(now.Unix())
|
|
|
|
+ default:
|
|
|
|
+ if len(strings.Split(publishTime, "-")) > 1 {
|
|
|
|
+ startTime = strings.Split(publishTime, "-")[0]
|
|
|
|
+ endTime = strings.Split(publishTime, "-")[1]
|
|
|
|
+ //电脑端 时间选择 开始时间当天和结束时间当天相同
|
|
|
|
+ if startTime == endTime {
|
|
|
|
+ et, _ := strconv.ParseInt(endTime, 0, 64)
|
|
|
|
+ etTime := time.Unix(et, 0)
|
|
|
|
+ endTime = fmt.Sprint(time.Date(etTime.Year(), etTime.Month(), etTime.Day()+1, 0, 0, 0, 0, time.Local).Unix())
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if startTime != "" || endTime != "" {
|
|
|
|
+ if len(query) > 0 {
|
|
|
|
+ query += ","
|
|
|
|
+ }
|
|
|
|
+ query += `{"range":{"publishtime":{`
|
|
|
|
+ if startTime != "" {
|
|
|
|
+ query += `"gte":` + startTime
|
|
|
|
+ }
|
|
|
|
+ if startTime != "" && endTime != "" {
|
|
|
|
+ query += `,`
|
|
|
|
+ }
|
|
|
|
+ if endTime != "" {
|
|
|
|
+ query += `"lt":` + endTime
|
|
|
|
+ }
|
|
|
|
+ query += `}}}`
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //信息类型-二级
|
|
|
|
+ subtype := b.Subtype
|
|
|
|
+ topType := If(b.TopType != "", strings.Split(b.TopType, ","), []string{}).([]string)
|
|
|
|
+ allType := ``
|
|
|
|
+ //二级分类
|
|
|
|
+ if subtype != "" {
|
|
|
|
+ var typeInt = 0
|
|
|
|
+ allType += `{"terms":{"subtype":[`
|
|
|
|
+ for k, v := range strings.Split(subtype, ",") {
|
|
|
|
+ if tType := If(topTypeMap[v] != "" && b.TopType == "", topTypeMap[v], "").(string); tType != "" {
|
|
|
|
+ topType = append(topType, tType)
|
|
|
|
+ typeInt += 1
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ if k > typeInt {
|
|
|
|
+ allType += `,`
|
|
|
|
+ }
|
|
|
|
+ allType += `"` + v + `"`
|
|
|
|
+ }
|
|
|
|
+ allType += `]}}`
|
|
|
|
+ if typeInt == len(strings.Split(subtype, ",")) {
|
|
|
|
+ allType = ``
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //信息类型 一级分类
|
|
|
|
+ if len(topType) > 0 {
|
|
|
|
+ if allType != "" {
|
|
|
|
+ allType += ","
|
|
|
|
+ }
|
|
|
|
+ allType += `{"terms":{"toptype":[`
|
|
|
|
+ for k, v := range topType {
|
|
|
|
+ if k > 0 {
|
|
|
|
+ allType += `,`
|
|
|
|
+ }
|
|
|
|
+ allType += `"` + v + `"`
|
|
|
|
+ }
|
|
|
|
+ allType += `]}}`
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if allType != "" {
|
|
|
|
+ if query != "" {
|
|
|
|
+ query += ","
|
|
|
|
+ }
|
|
|
|
+ query += fmt.Sprintf(QueryBoolShould, allType)
|
|
|
|
+ }
|
|
|
|
+ //采购单位类型
|
|
|
|
+ buyerClass := b.BuyerClass
|
|
|
|
+ if buyerClass != "" {
|
|
|
|
+ if len(query) > 0 {
|
|
|
|
+ query += ","
|
|
|
|
+ }
|
|
|
|
+ query += `{"terms":{"buyerclass":[`
|
|
|
|
+ for k, v := range strings.Split(buyerClass, ",") {
|
|
|
|
+ if k > 0 {
|
|
|
|
+ query += `,`
|
|
|
|
+ }
|
|
|
|
+ query += `"` + v + `"`
|
|
|
|
+ }
|
|
|
|
+ query += `]}`
|
|
|
|
+ }
|
|
|
|
+ return query
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// DetailFileORTitle 包含正文或 附件 不包含标题
|
|
|
|
+func (b *BidSearch) DetailFileORTitle(findFields string) bool {
|
|
|
|
+ return (strings.Contains(findFields, `"detail"`) || strings.Contains(findFields, `"filetext"`)) && !strings.Contains(findFields, `"title"`)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 采购单位、中标企业、代理机构
|
|
|
|
+func (b *BidSearch) GetMatchArrSql(field string, val ...string) (sql string) {
|
|
|
|
+ if len(val) == 0 {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ var (
|
|
|
|
+ arr []string
|
|
|
|
+ i int
|
|
|
|
+ )
|
|
|
|
+ for _, s := range val {
|
|
|
|
+ if s == "" {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ if len([]rune(s)) > 30 {
|
|
|
|
+ s = string([]rune(s)[:30])
|
|
|
|
+ }
|
|
|
|
+ i++
|
|
|
|
+ arr = append(arr, fmt.Sprintf(`{"match_phrase": {"%s": "%s"}}`, field, s))
|
|
|
|
+ if i > 4 {
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if len(arr) == 0 {
|
|
|
|
+ return ""
|
|
|
|
+ }
|
|
|
|
+ return fmt.Sprintf(`{"bool": {"should": [%s],"minimum_should_match": 1}}`, strings.Join(arr, ","))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// IndustryFormat 行业处理
|
|
|
|
+func (b *BidSearch) IndustryFormat(industry, subScopeClass string) (newIndustry string) {
|
|
|
|
+ commonSubstring := func(v string) (value string) {
|
|
|
|
+ bcs := strings.Split(v, "_")
|
|
|
|
+ if len(bcs) == 1 {
|
|
|
|
+ value = bcs[0]
|
|
|
|
+ } else if len(bcs) == 2 {
|
|
|
|
+ value = bcs[0]
|
|
|
|
+ if strings.TrimSpace(value) == "" {
|
|
|
|
+ value = bcs[0]
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ bct := strings.Split(subScopeClass, ",")
|
|
|
|
+ if bct == nil || len(bct) == 0 {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ //搜索条件中没有行业的话,取查询结果中第一个行业
|
|
|
|
+ if industry == "" {
|
|
|
|
+ newIndustry = commonSubstring(bct[0])
|
|
|
|
+ } else { //搜索条件中有行业的话,取行业中和搜索条件相对应的第一个
|
|
|
|
+ industryArr := strings.Split(industry, ",")
|
|
|
|
+ L:
|
|
|
|
+ for _, bc := range bct {
|
|
|
|
+ for _, is := range industryArr {
|
|
|
|
+ if bc == is {
|
|
|
|
+ newIndustry = strings.TrimSpace(commonSubstring(bc))
|
|
|
|
+ break L
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+}
|