search.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. package es
  2. import (
  3. "fmt"
  4. "jyBXCore/rpc/bxcore"
  5. "jyBXCore/rpc/entity"
  6. IC "jyBXCore/rpc/init"
  7. "jyBXCore/rpc/util"
  8. "strconv"
  9. "strings"
  10. "time"
  11. MC "app.yhyue.com/moapp/jybase/common"
  12. elastic "app.yhyue.com/moapp/jybase/es"
  13. "log"
  14. )
  15. // GetSearchQuery 整理关键词等查询条件
  16. func GetSearchQuery(in *bxcore.SearchReq, mustQuery string) (qstr string) {
  17. var (
  18. //搜索范围是否只有附件
  19. //搜索范围只选择附件,是否有附件条件无效;
  20. isFileSearch = in.SelectType == "filetext"
  21. wordsMusts, wordsShould, musts, mustNot []string
  22. findFields string
  23. selectTypeArr = strings.Split(in.SelectType, ",")
  24. isLogin = in.UserId != ""
  25. )
  26. if selectTypeArr == nil || len(selectTypeArr) == 0 {
  27. findFields = `"title"`
  28. } else {
  29. findFields = fmt.Sprintf(`"%s"`, strings.Join(selectTypeArr, "\",\""))
  30. }
  31. switchBool := strings.Contains(findFields, "detail") && strings.Contains(findFields, "title") && IC.C.SearchTypeSwitch
  32. if mustQuery != "" {
  33. musts = append(musts, mustQuery)
  34. }
  35. //采购单位
  36. if in.Buyer != "" {
  37. musts = append(musts, util.GetMatchArrSql("buyer.mbuyer", strings.Split(in.Buyer, ",")...))
  38. }
  39. //中标单位
  40. if in.Winner != "" {
  41. musts = append(musts, util.GetMatchArrSql("s_winner.mwinner", strings.Split(in.Winner, ",")...))
  42. }
  43. //代理机构
  44. if in.Agency != "" {
  45. musts = append(musts, util.GetMatchArrSql("agency.magency", strings.Split(in.Agency, ",")...))
  46. }
  47. //此时关键词中间有IC.C.JYKeyMark进行隔离
  48. if in.KeyWords != "" {
  49. var (
  50. keyWordsMusts []string
  51. )
  52. for _, v := range strings.Split(in.KeyWords, IC.C.JYKeyMark) {
  53. if elastic.ReplaceYH(v) == "" {
  54. continue
  55. }
  56. //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
  57. //detail 正文不支持单字查询
  58. if len([]rune(elastic.ReplaceYH(v))) == 1 && DetailFileORTitle(findFields) {
  59. findFields += `,"title"`
  60. } else if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
  61. //标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
  62. if strings.Contains(findFields, `"title",`) {
  63. findFields = strings.Replace(findFields, `"title",`, ``, -1)
  64. } else if strings.Contains(findFields, `,"title"`) {
  65. findFields = strings.Replace(findFields, `,"title"`, ``, -1)
  66. }
  67. }
  68. keyWordsMusts = append(keyWordsMusts, fmt.Sprintf(fmt.Sprintf(multiMatch, "%s", findFields), elastic.ReplaceYH(v)))
  69. }
  70. //搜索关键词模式;默认0:包含所有,1:包含任意
  71. if in.WordsMode == 1 {
  72. wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(keyWordsMusts, ",")))
  73. } else {
  74. wordsMusts = append(wordsMusts, keyWordsMusts...)
  75. }
  76. }
  77. //附加词
  78. if in.AdditionalWords != "" {
  79. //多组附加词,每组间,号隔开。每组内如果关键词中间有空格,自动分词
  80. var (
  81. addWordsMusts []string
  82. )
  83. for _, aws := range strings.Split(in.AdditionalWords, ",") {
  84. var (
  85. addWordsMust []string
  86. )
  87. for _, v := range strings.Split(aws, IC.C.JYKeyMark) {
  88. if elastic.ReplaceYH(v) == "" {
  89. continue
  90. }
  91. //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
  92. //detail 正文不支持单字查询
  93. if len([]rune(elastic.ReplaceYH(v))) == 1 && DetailFileORTitle(findFields) {
  94. findFields += `,"title"`
  95. } else if switchBool && len([]rune(elastic.ReplaceYH(v))) > 1 {
  96. //标题 全文搜索 搜索类型开关打开 默认搜索全文;(全文包含标题)(单字排除)
  97. if strings.Contains(findFields, `"title",`) {
  98. findFields = strings.Replace(findFields, `"title",`, ``, -1)
  99. } else if strings.Contains(findFields, `,"title"`) {
  100. findFields = strings.Replace(findFields, `,"title"`, ``, -1)
  101. }
  102. }
  103. addWordsMust = append(addWordsMust, fmt.Sprintf(fmt.Sprintf(multiMatch, "%s", findFields), elastic.ReplaceYH(v)))
  104. addWordsMusts = append(addWordsMusts, addWordsMust...)
  105. if in.WordsMode == 0 {
  106. wordsMusts = append(wordsMusts, addWordsMust...)
  107. }
  108. addWordsMust = []string{}
  109. }
  110. //搜索关键词模式;默认0:包含所有,1:包含任意
  111. if in.WordsMode == 1 {
  112. wordsShould = append(wordsShould, fmt.Sprintf(elastic.NgramMust, strings.Join(addWordsMusts, ",")))
  113. addWordsMusts = []string{}
  114. }
  115. }
  116. }
  117. //搜索关键词模式;默认0:包含所有,1:包含任意
  118. //包含任意一组
  119. if len(wordsShould) > 0 {
  120. musts = append(musts, fmt.Sprintf(queryBoolShould, strings.Join(wordsShould, ",")))
  121. } else if len(wordsMusts) > 0 {
  122. musts = append(musts, fmt.Sprintf(elastic.NgramMust, strings.Join(wordsMusts, ",")))
  123. }
  124. //排除词
  125. if notKey := strings.TrimSpace(in.ExclusionWords); notKey != "" {
  126. notKeyMultiMatch := fmt.Sprintf(multiMatch, "%s", findFields)
  127. var notKeyMustNot []string
  128. //多组排除词
  129. for _, nks := range strings.Split(notKey, ",") {
  130. //单组排除词 空格分割
  131. for _, v := range strings.Split(nks, IC.C.JYKeyMark) {
  132. v = strings.TrimSpace(v)
  133. if v == "" {
  134. continue
  135. }
  136. if len([]rune(elastic.ReplaceYH(v))) == 1 {
  137. //单个字 搜索范围 有全文或者附件 无标题 例如:学 虚拟机 detail 搜索的时候加上标题
  138. if DetailFileORTitle(findFields) {
  139. notKeyMultiMatch = fmt.Sprintf(multiMatch, "%s", findFields+`,"title"`)
  140. }
  141. }
  142. notKeyMustNot = append(notKeyMustNot, fmt.Sprintf(notKeyMultiMatch, elastic.ReplaceYH(v)))
  143. }
  144. }
  145. mustNot = append(mustNot, fmt.Sprintf(queryBoolShould, strings.Join(notKeyMustNot, ",")))
  146. }
  147. //行业
  148. if in.Industry != "" && isLogin {
  149. musts = append(musts, fmt.Sprintf(queryBoolMust, `"`+strings.ReplaceAll(in.Industry, ",", `","`)+`"`))
  150. }
  151. //价格
  152. if in.Price != "" && len(strings.Split(in.Price, "-")) > 1 {
  153. minPrice, maxPrice := strings.Split(in.Price, "-")[0], strings.Split(in.Price, "-")[1]
  154. if minPrice != "" || maxPrice != "" {
  155. sq := ``
  156. if minPrice != "" {
  157. min, _ := strconv.ParseFloat(minPrice, 64)
  158. minPrice = fmt.Sprintf("%.0f", min*10000)
  159. if minPrice == "0" {
  160. minPrice = ""
  161. }
  162. }
  163. if maxPrice != "" {
  164. max, _ := strconv.ParseFloat(maxPrice, 64)
  165. maxPrice = fmt.Sprintf("%.0f", max*10000)
  166. if maxPrice == "0" {
  167. maxPrice = ""
  168. }
  169. }
  170. if minPrice != "" {
  171. sq += fmt.Sprintf(gte, minPrice)
  172. }
  173. if minPrice != "" && maxPrice != "" {
  174. sq += `,`
  175. }
  176. if maxPrice != "" {
  177. sq += fmt.Sprintf(lte, maxPrice)
  178. }
  179. if minPrice != "" || maxPrice != "" {
  180. query_price := fmt.Sprintf(queryBoolShould, fmt.Sprintf(queryBoolMustBoolShould, sq, sq))
  181. musts = append(musts, query_price)
  182. }
  183. }
  184. }
  185. //采购单位联系方式
  186. hasBuyerTel := in.BuyerTel
  187. if hasBuyerTel != "" {
  188. if hasBuyerTel == "y" {
  189. musts = append(musts, fmt.Sprintf(queryExists, "buyertel"))
  190. } else {
  191. mustNot = append(mustNot, fmt.Sprintf(queryExists, "buyertel"))
  192. }
  193. }
  194. //中标企业联系方式
  195. hasWinnerTel := in.WinnerTel
  196. if hasWinnerTel != "" {
  197. if hasWinnerTel == "y" {
  198. musts = append(musts, fmt.Sprintf(queryExists, "winnertel"))
  199. } else {
  200. mustNot = append(mustNot, fmt.Sprintf(queryExists, "winnertel"))
  201. }
  202. }
  203. //移动融创
  204. if in.MobileTag != nil && len(in.MobileTag) > 0 && in.IsPay { //仅付费bidding表有此字段
  205. musts = append(musts, fmt.Sprintf(queryBoolMustA, "mobile_tag", `"`+strings.Join(in.MobileTag, `","`)+`"`))
  206. }
  207. if isLogin { //需要登录
  208. //电脑端 物业专版BI
  209. if in.BidField == "BIProperty" {
  210. if !entity.MobileReg.MatchString(in.UserAgent) {
  211. musts = append(musts, fmt.Sprintf(queryBoolMustA, "tag_topinformation", `"情报_物业"`))
  212. //物业业态
  213. if in.PropertyForm != "" {
  214. arr := []string{}
  215. for _, v := range strings.Split(in.PropertyForm, ",") {
  216. arr = append(arr, fmt.Sprintf(`"%s"`, v))
  217. }
  218. musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(`{"terms":{"tag_set.wuye.property_form":[%s]}}`, strings.Join(arr, ","))))
  219. }
  220. //业务类型
  221. if in.SubInformation != "" {
  222. arr := []string{}
  223. for _, v := range strings.Split(in.SubInformation, ",") {
  224. arr = append(arr, fmt.Sprintf(`"%s"`, v))
  225. }
  226. musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(`{"terms":{"tag_subinformation":[%s]}}`, strings.Join(arr, ","))))
  227. }
  228. //价格区间
  229. if in.Scale != "" {
  230. arr := []string{}
  231. for _, v := range strings.Split(in.Scale, ",") {
  232. arr = append(arr, fmt.Sprintf(`"%s"`, v))
  233. }
  234. musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(`{"terms":{"tag_set.wuye.scale":[%s]}}`, strings.Join(arr, ","))))
  235. }
  236. //合同周期
  237. if in.Period != "" {
  238. arr := []string{}
  239. for _, v := range strings.Split(in.Period, ",") {
  240. arr = append(arr, fmt.Sprintf(`"%s"`, v))
  241. }
  242. musts = append(musts, fmt.Sprintf(queryBoolShould, fmt.Sprintf(`{"terms":{"tag_set.wuye.period":[%s]}}`, strings.Join(arr, ","))))
  243. }
  244. //换手率
  245. if in.ChangeHand != 0 {
  246. if in.ChangeHand > 0 {
  247. //存在
  248. musts = append(musts, `{"range":{"tag_set.wuye.changehand":{"gt":0.3}}}`)
  249. }
  250. }
  251. if in.FileExists != "" {
  252. if in.FileExists == "1" {
  253. //存在
  254. musts = append(musts, fmt.Sprintf(queryBoolMustA, "tag_set.wuye.isfile", `"63"`))
  255. } else {
  256. //不存在
  257. mustNot = append(mustNot, fmt.Sprintf(queryExists, "tag_set.wuye.isfile"))
  258. }
  259. }
  260. }
  261. } else {
  262. //附件--非BI
  263. fileExists := in.FileExists
  264. if !isFileSearch && fileExists != "" {
  265. if fileExists == "1" { //有附件
  266. musts = append(musts, fmt.Sprintf(queryBoolMustTerm, true))
  267. } else if fileExists == "-1" { //无附件
  268. mustNot = append(mustNot, fmt.Sprintf(queryBoolMustTerm, true))
  269. }
  270. }
  271. if in.BidField != "" { // 如果是领域化数据则需要加标签
  272. musts = append(musts, fmt.Sprintf(queryBoolMustTermDomain, in.BidField))
  273. }
  274. }
  275. }
  276. //in.BidField 剑鱼默认招标信息搜索 此参数为空**
  277. qstr = fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(mustNot, ","))
  278. log.Println("qstr:", qstr)
  279. return
  280. }
  281. // GetBidSearchQuery 整理地区、城市、发布时间、信息类型、采购单位类型 查询条件
  282. func GetBidSearchQuery(in *bxcore.SearchReq) string {
  283. query := ``
  284. //省份
  285. area := in.Province
  286. isLogin := in.UserId != ""
  287. if area != "" {
  288. query += `{"terms":{"area":[`
  289. for k, v := range strings.Split(area, ",") {
  290. if k > 0 {
  291. query += `,`
  292. }
  293. query += `"` + v + `"`
  294. }
  295. query += `]}}`
  296. }
  297. //市--未登录用户不能根据市和地区筛选
  298. city := in.City
  299. if city != "" && isLogin {
  300. if len(query) > 0 {
  301. query += ","
  302. }
  303. query += `{"terms":{"city":[`
  304. for k, v := range strings.Split(city, ",") {
  305. if k > 0 {
  306. query += `,`
  307. }
  308. query += `"` + v + `"`
  309. }
  310. query += `]}}`
  311. }
  312. district := in.District
  313. if district != "" && isLogin {
  314. if len(query) > 0 {
  315. query += ","
  316. }
  317. for k, v := range strings.Split(district, ",") {
  318. if k > 0 {
  319. query += `,`
  320. }
  321. cityName := strings.Split(v, "_")[0]
  322. districtName := strings.Split(v, "_")[1]
  323. queryBoolMustAndDistrict := `{"bool":{"must":[{"terms":{"city":["%s"]}},{"terms":{"district":["%s"]}}]}}`
  324. query += fmt.Sprintf(queryBoolMustAndDistrict, cityName, districtName)
  325. }
  326. }
  327. if query != "" {
  328. query = fmt.Sprintf(queryBoolShould, query)
  329. }
  330. //发布时间
  331. publishTime := in.PublishTime
  332. if publishTime != "" {
  333. startTime, endTime := "", ""
  334. now := time.Now()
  335. switch publishTime {
  336. case "lately-7":
  337. startTime = fmt.Sprint(time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, time.Local).Unix())
  338. case "lately-30":
  339. startTime = fmt.Sprint(time.Date(now.Year(), now.Month(), now.Day()-30, 0, 0, 0, 0, time.Local).Unix())
  340. case "thisyear":
  341. startTime = fmt.Sprint(time.Date(now.Year()-1, now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Unix())
  342. endTime = fmt.Sprint(now.Unix())
  343. case "threeyear":
  344. startTime = fmt.Sprint(time.Date(now.Year()-3, now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Unix())
  345. endTime = fmt.Sprint(now.Unix())
  346. case "fiveyear":
  347. startTime = fmt.Sprint(time.Date(now.Year()-5, now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.Local).Unix())
  348. endTime = fmt.Sprint(now.Unix())
  349. default:
  350. if len(strings.Split(publishTime, "-")) > 1 {
  351. startTime = strings.Split(publishTime, "-")[0]
  352. endTime = strings.Split(publishTime, "-")[1]
  353. //电脑端 时间选择 开始时间当天和结束时间当天相同
  354. if startTime == endTime {
  355. et, _ := strconv.ParseInt(endTime, 0, 64)
  356. etTime := time.Unix(et, 0)
  357. endTime = fmt.Sprint(time.Date(etTime.Year(), etTime.Month(), etTime.Day()+1, 0, 0, 0, 0, time.Local).Unix())
  358. }
  359. }
  360. }
  361. if startTime != "" || endTime != "" {
  362. if len(query) > 0 {
  363. query += ","
  364. }
  365. query += `{"range":{"publishtime":{`
  366. if startTime != "" {
  367. query += `"gte":` + startTime
  368. }
  369. if startTime != "" && endTime != "" {
  370. query += `,`
  371. }
  372. if endTime != "" {
  373. query += `"lt":` + endTime
  374. }
  375. query += `}}}`
  376. }
  377. }
  378. //信息类型-二级
  379. subtype := in.Subtype
  380. topType := MC.If(in.TopType != "", strings.Split(in.TopType, ","), []string{}).([]string)
  381. allType := ``
  382. //二级分类
  383. if subtype != "" {
  384. var typeInt = 0
  385. allType += `{"terms":{"subtype":[`
  386. for k, v := range strings.Split(subtype, ",") {
  387. if tType := MC.If(topTypeMap[v] != "" && in.TopType == "", topTypeMap[v], "").(string); tType != "" {
  388. topType = append(topType, tType)
  389. typeInt += 1
  390. continue
  391. }
  392. if k > typeInt {
  393. allType += `,`
  394. }
  395. allType += `"` + v + `"`
  396. }
  397. allType += `]}}`
  398. if typeInt == len(strings.Split(subtype, ",")) {
  399. allType = ``
  400. }
  401. }
  402. //信息类型 一级分类
  403. log.Println("topType:", topType)
  404. if len(topType) > 0 {
  405. if allType != "" {
  406. allType += ","
  407. }
  408. allType += `{"terms":{"toptype":[`
  409. for k, v := range topType {
  410. if k > 0 {
  411. allType += `,`
  412. }
  413. allType += `"` + v + `"`
  414. }
  415. allType += `]}}`
  416. }
  417. if allType != "" {
  418. if query != "" {
  419. query += ","
  420. }
  421. query += fmt.Sprintf(queryBoolShould, allType)
  422. }
  423. //采购单位类型
  424. buyerClass := in.BuyerClass
  425. if buyerClass != "" {
  426. if len(query) > 0 {
  427. query += ","
  428. }
  429. query += `{"terms":{"buyerclass":[`
  430. for k, v := range strings.Split(buyerClass, ",") {
  431. if k > 0 {
  432. query += `,`
  433. }
  434. query += `"` + v + `"`
  435. }
  436. query += `]}}`
  437. }
  438. //电脑端 物业专版BI
  439. if !entity.MobileReg.MatchString(in.UserAgent) {
  440. if in.ExpireTime != "" {
  441. if len(query) > 0 {
  442. query += ","
  443. }
  444. startTime, endTime := "", ""
  445. now := time.Now()
  446. if in.ExpireTime == "1" { //本月到期
  447. startTime = fmt.Sprint(now.Unix())
  448. first := time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, time.Local)
  449. endTime = fmt.Sprint(first.AddDate(0, 0, 0).Unix())
  450. /* endTime = fmt.Sprint(time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, time.Local).Unix())*/
  451. } else if in.ExpireTime == "1-3" { //1-3个月到期
  452. startTime = fmt.Sprint(time.Date(now.Year(), now.Month()+1, now.Day(), 0, 0, 0, 0, time.Local).Unix())
  453. endTime = fmt.Sprint(time.Date(now.Year(), now.Month()+3, now.Day(), 0, 0, 0, 0, time.Local).Unix())
  454. } else if in.ExpireTime == "3-6" { //3-6个月到期
  455. startTime = fmt.Sprint(time.Date(now.Year(), now.Month()+3, now.Day(), 0, 0, 0, 0, time.Local).Unix())
  456. endTime = fmt.Sprint(time.Date(now.Year(), now.Month()+6, now.Day(), 0, 0, 0, 0, time.Local).Unix())
  457. } else if in.ExpireTime == "6-12" { //6-12个月到期
  458. startTime = fmt.Sprint(time.Date(now.Year(), now.Month()+6, now.Day(), 0, 0, 0, 0, time.Local).Unix())
  459. endTime = fmt.Sprint(time.Date(now.Year(), now.Month()+12, now.Day(), 0, 0, 0, 0, time.Local).Unix())
  460. } else if in.ExpireTime == "12" { //12个月以后
  461. startTime = fmt.Sprint(time.Date(now.Year(), now.Month()+12, now.Day(), 0, 0, 0, 0, time.Local).Unix())
  462. } else if len(strings.Split(in.ExpireTime, "_")) > 1 {
  463. startTime = strings.Split(in.ExpireTime, "_")[0]
  464. endTime = strings.Split(in.ExpireTime, "_")[1]
  465. etTime := time.Now()
  466. if endTime != "" {
  467. et, _ := strconv.ParseInt(endTime, 0, 64)
  468. etTime = time.Unix(et, 0)
  469. }
  470. endTime = fmt.Sprint(time.Date(etTime.Year(), etTime.Month(), etTime.Day()+1, 0, 0, 0, 0, time.Local).Unix())
  471. }
  472. query += `{"range":{"expiredate":{`
  473. if startTime != "" {
  474. query += `"gte":` + startTime
  475. }
  476. if startTime != "" && endTime != "" {
  477. query += `,`
  478. }
  479. if endTime != "" {
  480. query += `"lt":` + endTime
  481. }
  482. query += `}}}`
  483. }
  484. }
  485. return query
  486. }
  487. // DetailFileORTitle 包含正文或 附件 不包含标题
  488. func DetailFileORTitle(findFields string) bool {
  489. return (strings.Contains(findFields, `"detail"`) || strings.Contains(findFields, `"filetext"`)) && !strings.Contains(findFields, `"title"`)
  490. }