search.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. package es
  2. import (
  3. "fmt"
  4. "jyBXCore/rpc/bxcore"
  5. IC "jyBXCore/rpc/init"
  6. "strconv"
  7. "strings"
  8. "time"
  9. MC "app.yhyue.com/moapp/jybase/common"
  10. elastic "app.yhyue.com/moapp/jybase/es"
  11. "github.com/zeromicro/go-zero/core/logx"
  12. )
  13. // GetSearchQuery 整理关键词等查询条件
  14. func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
  15. var (
  16. //搜索范围是否只有附件
  17. //搜索范围只选择附件,是否有附件条件无效;
  18. isFileSearch = in.SelectType == "filetext"
  19. wordsMusts, wordsShould, musts, mustNot []string
  20. findFields string
  21. selectTypeArr = strings.Split(in.SelectType, ",")
  22. )
  23. if selectTypeArr == nil || len(selectTypeArr) == 0 {
  24. findFields = `"title"`
  25. } else {
  26. findFields = fmt.Sprintf(`"%s"`, strings.Join(selectTypeArr, "\",\""))
  27. }
  28. switchBool := strings.Contains(findFields, "detail") && strings.Contains(findFields, "title") && IC.C.SearchTypeSwitch
  29. if mustQuery != "" {
  30. musts = append(musts, mustQuery)
  31. }
  32. //此时关键词中间有IC.C.JYKeyMark进行隔离
  33. if in.KeyWords != "" {
  34. var (
  35. keyWordsMusts []string
  36. )
  37. for _, v := range strings.Split(in.KeyWords, IC.C.JYKeyMark) {
  38. if elastic.ReplaceYH(v) == "" {
  39. continue
  40. }
  41. //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
  42. //detail 正文不支持单字查询
  43. if len([]rune(elastic.ReplaceYH(v))) == 1 && DetailFileORTitle(findFields) {
  44. findFields += `,"title"`
  45. } else if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
  46. //标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
  47. if strings.Contains(findFields, `"title",`) {
  48. findFields = strings.Replace(findFields, `"title",`, ``, -1)
  49. } else if strings.Contains(findFields, `,"title"`) {
  50. findFields = strings.Replace(findFields, `,"title"`, ``, -1)
  51. }
  52. }
  53. keyWordsMusts = append(keyWordsMusts, fmt.Sprintf(fmt.Sprintf(multiMatch, "%s", findFields), elastic.ReplaceYH(v)))
  54. }
  55. //搜索关键词模式;默认0:包含所有,1:包含任意
  56. if in.WordsMode == 1 {
  57. wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(keyWordsMusts, ",")))
  58. } else {
  59. wordsMusts = append(wordsMusts, keyWordsMusts...)
  60. }
  61. }
  62. //附加词
  63. if in.AdditionalWords != "" {
  64. //多组附加词,每组间,号隔开。每组内如果关键词中间有空格,自动分词
  65. var (
  66. addWordsMusts []string
  67. )
  68. for _, aws := range strings.Split(in.AdditionalWords, ",") {
  69. var (
  70. addWordsMust []string
  71. )
  72. for _, v := range strings.Split(aws, IC.C.JYKeyMark) {
  73. if elastic.ReplaceYH(v) == "" {
  74. continue
  75. }
  76. //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
  77. //detail 正文不支持单字查询
  78. if len([]rune(elastic.ReplaceYH(v))) == 1 && DetailFileORTitle(findFields) {
  79. findFields += `,"title"`
  80. } else if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
  81. //标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
  82. if strings.Contains(findFields, `"title",`) {
  83. findFields = strings.Replace(findFields, `"title",`, ``, -1)
  84. } else if strings.Contains(findFields, `,"title"`) {
  85. findFields = strings.Replace(findFields, `,"title"`, ``, -1)
  86. }
  87. }
  88. addWordsMust = append(addWordsMust, fmt.Sprintf(fmt.Sprintf(multiMatch, "%s", findFields), elastic.ReplaceYH(v)))
  89. addWordsMusts = append(addWordsMusts, addWordsMust...)
  90. if in.WordsMode == 0 {
  91. wordsMusts = append(wordsMusts, addWordsMust...)
  92. }
  93. addWordsMust = []string{}
  94. }
  95. //搜索关键词模式;默认0:包含所有,1:包含任意
  96. if in.WordsMode == 1 {
  97. wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(addWordsMusts, ",")))
  98. addWordsMusts = []string{}
  99. }
  100. }
  101. }
  102. //搜索关键词模式;默认0:包含所有,1:包含任意
  103. //包含任意一组
  104. if len(wordsShould) > 0 {
  105. musts = append(musts, fmt.Sprintf(queryBoolShould, strings.Join(wordsShould, ",")))
  106. } else if len(wordsMusts) > 0 {
  107. musts = append(musts, fmt.Sprintf(elastic.NgramMust, strings.Join(wordsMusts, ",")))
  108. }
  109. //排除词
  110. if notKey := strings.TrimSpace(in.ExclusionWords); notKey != "" {
  111. notKeyMultiMatch := fmt.Sprintf(multiMatch, "%s", findFields)
  112. var notKeyMustNot []string
  113. //多组排除词
  114. for _, nks := range strings.Split(notKey, ",") {
  115. //单组排除词 空格分割
  116. for _, v := range strings.Split(nks, IC.C.JYKeyMark) {
  117. v = strings.TrimSpace(v)
  118. if v == "" {
  119. continue
  120. }
  121. if len([]rune(elastic.ReplaceYH(v))) == 1 {
  122. //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
  123. if DetailFileORTitle(findFields) {
  124. notKeyMultiMatch = fmt.Sprintf(multiMatch, "%s", findFields+`,"title"`)
  125. }
  126. }
  127. notKeyMustNot = append(notKeyMustNot, fmt.Sprintf(notKeyMultiMatch, elastic.ReplaceYH(v)))
  128. }
  129. }
  130. mustNot = append(mustNot, fmt.Sprintf(queryBoolShould, strings.Join(notKeyMustNot, ",")))
  131. }
  132. //行业
  133. if in.Industry != "" {
  134. musts = append(musts, fmt.Sprintf(queryBoolMust, `"`+strings.ReplaceAll(in.Industry, ",", `","`)+`"`))
  135. }
  136. //价格
  137. if in.Price != "" && len(strings.Split(in.Price, "-")) > 1 {
  138. minPrice, maxPrice := strings.Split(in.Price, "-")[0], strings.Split(in.Price, "-")[1]
  139. if minPrice != "" || maxPrice != "" {
  140. sq := ``
  141. if minPrice != "" {
  142. min, _ := strconv.ParseFloat(minPrice, 64)
  143. minPrice = fmt.Sprintf("%.0f", min*10000)
  144. if minPrice == "0" {
  145. minPrice = ""
  146. }
  147. }
  148. if maxPrice != "" {
  149. max, _ := strconv.ParseFloat(maxPrice, 64)
  150. maxPrice = fmt.Sprintf("%.0f", max*10000)
  151. if maxPrice == "0" {
  152. maxPrice = ""
  153. }
  154. }
  155. if minPrice != "" {
  156. sq += fmt.Sprintf(gte, minPrice)
  157. }
  158. if minPrice != "" && maxPrice != "" {
  159. sq += `,`
  160. }
  161. if maxPrice != "" {
  162. sq += fmt.Sprintf(lte, maxPrice)
  163. }
  164. if minPrice != "" || maxPrice != "" {
  165. query_price := fmt.Sprintf(queryBoolShould, fmt.Sprintf(queryBoolMustBoolShould, sq, sq))
  166. musts = append(musts, query_price)
  167. }
  168. }
  169. }
  170. //采购单位联系方式
  171. hasBuyerTel := in.BuyerTel
  172. if hasBuyerTel != "" {
  173. if hasBuyerTel == "y" {
  174. mustNot = append(mustNot, fmt.Sprintf(queryMissing, "buyertel"))
  175. } else {
  176. musts = append(musts, fmt.Sprintf(queryMissing, "buyertel"))
  177. }
  178. }
  179. //中标企业联系方式
  180. hasWinnerTel := in.WinnerTel
  181. if hasWinnerTel != "" {
  182. if hasWinnerTel == "y" {
  183. mustNot = append(mustNot, fmt.Sprintf(queryMissing, "winnertel"))
  184. } else {
  185. musts = append(musts, fmt.Sprintf(queryMissing, "winnertel"))
  186. }
  187. }
  188. //附件
  189. fileExists := in.FileExists
  190. if !isFileSearch && fileExists != "" {
  191. if fileExists == "1" { //有附件
  192. mustNot = append(mustNot, fmt.Sprintf(queryMissing, "isValidFile"))
  193. musts = append(musts, fmt.Sprintf(queryBoolMustTerm, 1))
  194. } else if fileExists == "-1" { //无附件
  195. musts = append(musts, fmt.Sprintf(queryMissing, "isValidFile"))
  196. }
  197. }
  198. // 如果是领域化数据则需要加标签
  199. if in.BidField != "" {
  200. musts = append(musts, fmt.Sprintf(queryBoolMustTermDomain, in.BidField))
  201. }
  202. qstr = fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(mustNot, ","))
  203. logx.Info("qstr:", qstr)
  204. return
  205. }
  206. // GetBidSearchQuery 整理地区、城市、发布时间、信息类型、采购单位类型 查询条件
  207. func GetBidSearchQuery(in *bxcore.SearchReq) string {
  208. query := ``
  209. //省份
  210. area := in.Province
  211. if area != "" {
  212. query += `{"terms":{"area":[`
  213. for k, v := range strings.Split(area, ",") {
  214. if k > 0 {
  215. query += `,`
  216. }
  217. query += `"` + v + `"`
  218. }
  219. query += `]}}`
  220. }
  221. //
  222. city := in.City
  223. if city != "" {
  224. if len(query) > 0 {
  225. query += ","
  226. }
  227. query += `{"terms":{"city":[`
  228. for k, v := range strings.Split(city, ",") {
  229. if k > 0 {
  230. query += `,`
  231. }
  232. query += `"` + v + `"`
  233. }
  234. query += `]}}`
  235. }
  236. if query != "" {
  237. query = fmt.Sprintf(queryBoolShould, query)
  238. }
  239. //发布时间
  240. publishTime := in.PublishTime
  241. if publishTime != "" && len(strings.Split(publishTime, "-")) > 1 {
  242. if len(query) > 0 {
  243. query += ","
  244. }
  245. startTime := strings.Split(publishTime, "-")[0]
  246. endTime := strings.Split(publishTime, "-")[1]
  247. query += `{"range":{"publishtime":{`
  248. if startTime != "" {
  249. query += `"gte":` + startTime
  250. }
  251. if startTime != "" && endTime != "" {
  252. query += `,`
  253. }
  254. if endTime != "" {
  255. //电脑端 时间选择 开始时间当天和结束时间当天相同
  256. if startTime == endTime {
  257. et, _ := strconv.ParseInt(endTime, 0, 64)
  258. etTime := time.Unix(et, 0)
  259. endTime = fmt.Sprint(time.Date(etTime.Year(), etTime.Month(), etTime.Day()+1, 0, 0, 0, 0, time.Local).Unix())
  260. }
  261. query += `"lt":` + endTime
  262. }
  263. query += `}}}`
  264. }
  265. //信息类型-二级
  266. subtype := in.Subtype
  267. topType := MC.If(in.TopType != "", strings.Split(in.TopType, ","), []string{}).([]string)
  268. allType := ``
  269. //二级分类
  270. if subtype != "" {
  271. var typeInt = 0
  272. allType += `{"terms":{"subtype":[`
  273. for k, v := range strings.Split(subtype, ",") {
  274. if tType := MC.If(topTypeMap[v] != "" && in.TopType == "", topTypeMap[v], "").(string); tType != "" {
  275. topType = append(topType, tType)
  276. typeInt += 1
  277. continue
  278. }
  279. if k > typeInt {
  280. allType += `,`
  281. }
  282. allType += `"` + v + `"`
  283. }
  284. allType += `]}}`
  285. }
  286. //信息类型 一级分类
  287. logx.Info("topType:", topType)
  288. if len(topType) > 0 {
  289. if allType != "" {
  290. allType += ","
  291. }
  292. allType += `{"terms":{"toptype":[`
  293. for k, v := range topType {
  294. if k > 0 {
  295. allType += `,`
  296. }
  297. allType += `"` + v + `"`
  298. }
  299. allType += `]}}`
  300. }
  301. if allType != "" {
  302. if query != "" {
  303. query += ","
  304. }
  305. query += fmt.Sprintf(queryBoolShould, allType)
  306. }
  307. //采购单位类型
  308. buyerClass := in.BuyerClass
  309. if buyerClass != "" {
  310. if len(query) > 0 {
  311. query += ","
  312. }
  313. query += `{"terms":{"buyerclass":[`
  314. for k, v := range strings.Split(buyerClass, ",") {
  315. if k > 0 {
  316. query += `,`
  317. }
  318. query += `"` + v + `"`
  319. }
  320. query += `]}}`
  321. }
  322. return query
  323. }
  324. // DetailFileORTitle 包含正文或 附件 不包含标题
  325. func DetailFileORTitle(findFields string) bool {
  326. return (strings.Contains(findFields, `"detail"`) || strings.Contains(findFields, `"filetext"`)) && !strings.Contains(findFields, `"title"`)
  327. }