search.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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. "log"
  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. musts = append(musts, fmt.Sprintf(queryExists, "buyertel"))
  175. } else {
  176. mustNot = append(mustNot, fmt.Sprintf(queryExists, "buyertel"))
  177. }
  178. }
  179. //中标企业联系方式
  180. hasWinnerTel := in.WinnerTel
  181. if hasWinnerTel != "" {
  182. if hasWinnerTel == "y" {
  183. musts = append(musts, fmt.Sprintf(queryExists, "winnertel"))
  184. } else {
  185. mustNot = append(mustNot, fmt.Sprintf(queryExists, "winnertel"))
  186. }
  187. }
  188. //附件
  189. fileExists := in.FileExists
  190. if !isFileSearch && fileExists != "" {
  191. if fileExists == "1" { //有附件
  192. musts = append(musts, fmt.Sprintf(queryBoolMustTerm, true))
  193. } else if fileExists == "-1" { //无附件
  194. mustNot = append(mustNot, fmt.Sprintf(queryBoolMustTerm, true))
  195. }
  196. }
  197. // 如果是领域化数据则需要加标签
  198. if in.BidField != "" {
  199. musts = append(musts, fmt.Sprintf(queryBoolMustTermDomain, in.BidField))
  200. }
  201. qstr = fmt.Sprintf(query, strings.Join(musts, ","), strings.Join(mustNot, ","))
  202. log.Println("qstr:", qstr)
  203. return
  204. }
  205. // GetBidSearchQuery 整理地区、城市、发布时间、信息类型、采购单位类型 查询条件
  206. func GetBidSearchQuery(in *bxcore.SearchReq) string {
  207. query := ``
  208. //省份
  209. area := in.Province
  210. if area != "" {
  211. query += `{"terms":{"area":[`
  212. for k, v := range strings.Split(area, ",") {
  213. if k > 0 {
  214. query += `,`
  215. }
  216. query += `"` + v + `"`
  217. }
  218. query += `]}}`
  219. }
  220. //市
  221. city := in.City
  222. if city != "" {
  223. if len(query) > 0 {
  224. query += ","
  225. }
  226. query += `{"terms":{"city":[`
  227. for k, v := range strings.Split(city, ",") {
  228. if k > 0 {
  229. query += `,`
  230. }
  231. query += `"` + v + `"`
  232. }
  233. query += `]}}`
  234. }
  235. district := in.District
  236. if district != "" {
  237. if len(query) > 0 {
  238. query += ","
  239. }
  240. for k, v := range strings.Split(district, ",") {
  241. if k > 0 {
  242. query += `,`
  243. }
  244. cityName := strings.Split(v, "_")[0]
  245. districtName := strings.Split(v, "_")[1]
  246. query_bool_must_and_district := `{"bool":{"must":[{"terms":{"city":["%s"]}},{"terms":{"district":["%s"]}}]}}`
  247. query += fmt.Sprintf(query_bool_must_and_district, cityName, districtName)
  248. }
  249. }
  250. /*if district != "" {
  251. for _, v := range strings.Split(district, ",") {
  252. if len(v) > 0 {
  253. query += ","
  254. }
  255. cityName := strings.Split(v, "_")[0]
  256. districtName := strings.Split(v, "_")[1]
  257. query_bool_must_and_district := `{"bool":{"must":[{"terms":{"area":["%s"]}},{"terms":{"district":["%s"]}}]}}`
  258. query += fmt.Sprintf(query_bool_must_and_district, cityName, districtName)
  259. query += `{"terms":{"city":[`
  260. for k, v := range strings.Split(city, ",") {
  261. if k > 0 {
  262. query += `,`
  263. }
  264. query += `"` + v + `"`
  265. }
  266. query += `]}}`
  267. }
  268. }*/
  269. if query != "" {
  270. query = fmt.Sprintf(queryBoolShould, query)
  271. }
  272. //发布时间
  273. publishTime := in.PublishTime
  274. if publishTime != "" && len(strings.Split(publishTime, "-")) > 1 {
  275. if len(query) > 0 {
  276. query += ","
  277. }
  278. startTime := strings.Split(publishTime, "-")[0]
  279. endTime := strings.Split(publishTime, "-")[1]
  280. query += `{"range":{"publishtime":{`
  281. if startTime != "" {
  282. query += `"gte":` + startTime
  283. }
  284. if startTime != "" && endTime != "" {
  285. query += `,`
  286. }
  287. if endTime != "" {
  288. //电脑端 时间选择 开始时间当天和结束时间当天相同
  289. if startTime == endTime {
  290. et, _ := strconv.ParseInt(endTime, 0, 64)
  291. etTime := time.Unix(et, 0)
  292. endTime = fmt.Sprint(time.Date(etTime.Year(), etTime.Month(), etTime.Day()+1, 0, 0, 0, 0, time.Local).Unix())
  293. }
  294. query += `"lt":` + endTime
  295. }
  296. query += `}}}`
  297. }
  298. //信息类型-二级
  299. subtype := in.Subtype
  300. topType := MC.If(in.TopType != "", strings.Split(in.TopType, ","), []string{}).([]string)
  301. allType := ``
  302. //二级分类
  303. if subtype != "" {
  304. var typeInt = 0
  305. allType += `{"terms":{"subtype":[`
  306. for k, v := range strings.Split(subtype, ",") {
  307. if tType := MC.If(topTypeMap[v] != "" && in.TopType == "", topTypeMap[v], "").(string); tType != "" {
  308. topType = append(topType, tType)
  309. typeInt += 1
  310. continue
  311. }
  312. if k > typeInt {
  313. allType += `,`
  314. }
  315. allType += `"` + v + `"`
  316. }
  317. allType += `]}}`
  318. if typeInt == len(strings.Split(subtype, ",")) {
  319. allType = ``
  320. }
  321. }
  322. //信息类型 一级分类
  323. log.Println("topType:", topType)
  324. if len(topType) > 0 {
  325. if allType != "" {
  326. allType += ","
  327. }
  328. allType += `{"terms":{"toptype":[`
  329. for k, v := range topType {
  330. if k > 0 {
  331. allType += `,`
  332. }
  333. allType += `"` + v + `"`
  334. }
  335. allType += `]}}`
  336. }
  337. if allType != "" {
  338. if query != "" {
  339. query += ","
  340. }
  341. query += fmt.Sprintf(queryBoolShould, allType)
  342. }
  343. //采购单位类型
  344. buyerClass := in.BuyerClass
  345. if buyerClass != "" {
  346. if len(query) > 0 {
  347. query += ","
  348. }
  349. query += `{"terms":{"buyerclass":[`
  350. for k, v := range strings.Split(buyerClass, ",") {
  351. if k > 0 {
  352. query += `,`
  353. }
  354. query += `"` + v + `"`
  355. }
  356. query += `]}}`
  357. }
  358. return query
  359. }
  360. // DetailFileORTitle 包含正文或 附件 不包含标题
  361. func DetailFileORTitle(findFields string) bool {
  362. return (strings.Contains(findFields, `"detail"`) || strings.Contains(findFields, `"filetext"`)) && !strings.Contains(findFields, `"title"`)
  363. }