compare.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. package main
  2. import (
  3. "qfw/util"
  4. "qfw/util/redis"
  5. "regexp"
  6. "sort"
  7. "strings"
  8. "time"
  9. "gopkg.in/mgo.v2/bson"
  10. )
  11. /**
  12. 发布时间(结合信息类型-->)
  13. 信息类型(拟建、招标(变更)、结果(成交、中标、流标、废标、变更)、其他(合同、验收、违规、变更))
  14. 项目代码(长度)
  15. 采购单位(结合省份)
  16. 招标机构
  17. 所属省份
  18. 信息标题(含有二次、标段、包的情况,结合分包情况处理)
  19. 是否分包:
  20. **/
  21. type ProjectInfo struct {
  22. Id string `json:"id"`
  23. IdInc string `json:"_id"` //补漏使用
  24. Publistime []int64 `json:"publistime"` //多条信息的发布时间、跨度
  25. InfoType [][]string `json:"infotype"` //多条信息内的 toptype、subtype
  26. Ids []string `json:"ids"`
  27. Topscopeclass []string `json:"topscopeclass"`
  28. Subscopeclass []string `json:"subscopeclass"`
  29. Winners []string `json:"winners"`
  30. ProjectName string `json:"projectname"`
  31. ProjectCode string `json:"projectcode"` //项目代码唯一(纯数字的权重低)
  32. Buyer string `json:"buyer"` //采购单位唯一
  33. Buyerperson string `json:"buyerperson"`
  34. Buyertel string `json:"buyertel"`
  35. Agency string `json:"agency"` //代理机构唯一
  36. Area string `json:"area"` //地区唯一
  37. City string `json:"city"` //地市
  38. HasPackage bool `json:"haspackage"` //是否有分包
  39. Package map[string]interface{} `json:"package"` //分包的对比对象
  40. Buyerclass string `json:"buyerclass"` //采购单位分类
  41. Bidopentime int64 `json:"bidopentime"` //开标时间
  42. District string `json:"district"` //区县
  43. Winnerorder []string //中标候选人
  44. }
  45. type CompareOne struct {
  46. ProjectNameType string //项目名称对比结果分类 A相等 B包含 C不相等 Dthis存在对比不存在 Ethis不存在
  47. ProjectCodeType string //同上
  48. BuyerType string //同上
  49. AreaType string //同上
  50. AgencyType string //同上
  51. PublistimeType int //1在时间范围 2不在
  52. PackageType int //1都是多包 2都不是多包 3招标 4新信息是结果
  53. Score int
  54. Parent *CompareInfo
  55. Pinfo *ProjectInfo
  56. Pos int
  57. Cresult string //对比结果
  58. }
  59. type CompareInfo struct {
  60. Field string //对比属性 pn/pc/pb
  61. Key string //存放rediskey
  62. Scores []*CompareOne //对比分值 pinfo索引对应分值
  63. Bfind bool //是否查找到
  64. IdArr []string
  65. K *Key
  66. KeyMap *KeyMap
  67. }
  68. func NewCompareInfo(field, key string, KeyMap *KeyMap) *CompareInfo {
  69. return &CompareInfo{
  70. Field: field,
  71. Key: key,
  72. Scores: []*CompareOne{},
  73. KeyMap: KeyMap,
  74. }
  75. }
  76. var numreg2 = regexp.MustCompile("^[0-9]+$")
  77. var TitleReg = regexp.MustCompile("([一二三四五六七八九十0-9A-Za-zⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ、\\-~至]+(子|合同|分|施工|监理|标)?[包标段][号段]?[、]?)+|((子|合同|分|施工|监理|标)?[包标段][号段]?[一二三四五六七八九十0-9A-Za-zⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ、\\-~至]+[、]?)+|(子|合同|分|施工|监理|标)?[包标段][号段]?[a-zA-Z0-9]+[\\-~-至、](子|合同|分|施工|监理|标)?[包标段][号段]?[a-zA-Z0-9]+")
  78. //没有在redis中查找到,新增项目
  79. func InsertProject(new_pn string, tmp, mess map[string]interface{}, pici int64, thisinfo *Info) string {
  80. e := InitEL("")
  81. set := map[string]interface{}{
  82. "pici": pici,
  83. }
  84. set["s_projectname"] = new_pn
  85. e.fieldpriority(&tmp, nil, &set)
  86. set["extractpos"] = e.GetVal()
  87. set["createtime"] = time.Now().Unix()
  88. set["sourceinfoid"] = util.BsonIdToSId(tmp["_id"])
  89. set["sourceinfourl"] = tmp["href"]
  90. set["topscopeclass"] = thisinfo.Topscopeclass
  91. set["subscopeclass"] = thisinfo.Subscopeclass
  92. if thisinfo.Buyerperson != "" {
  93. set["buyerperson"] = thisinfo.Buyerperson
  94. }
  95. if thisinfo.Buyertel != "" {
  96. set["buyertel"] = thisinfo.Buyertel
  97. }
  98. if thisinfo.Buyerclass != "" {
  99. set["buyertel"] = thisinfo.Buyerclass
  100. }
  101. if thisinfo.District != "" {
  102. set["district"] = thisinfo.District
  103. }
  104. if thisinfo.Bidopentime > 0 {
  105. set["bidopentime"] = thisinfo.Bidopentime
  106. }
  107. if len(thisinfo.Winnerorder) > 0 {
  108. set["winnerorder"] = thisinfo.Winnerorder
  109. }
  110. s_subscopeclass := strings.Join(thisinfo.Subscopeclass, ",")
  111. set["s_subscopeclass"] = s_subscopeclass
  112. s_winner := strings.Join(thisinfo.Winners, ",")
  113. set["s_winner"] = s_winner
  114. if tmp["package"] != nil {
  115. set["package"] = tmp["package"] //没定义优先级
  116. }
  117. push := NewPushInfo(tmp)
  118. for tkey, _ := range extractpos {
  119. if tmp[tkey] != nil {
  120. push[tkey] = tmp[tkey]
  121. }
  122. }
  123. set["list"] = []bson.M{
  124. push,
  125. }
  126. if mess != nil { //项目标识
  127. for k, v := range mess {
  128. set[k] = v
  129. }
  130. }
  131. return MQFW.Save(projectColl, set)
  132. }
  133. //生成存放在redis数组中的对象
  134. func NewPinfo(id string, thisinfo *Info) ProjectInfo {
  135. p1 := ProjectInfo{
  136. Publistime: []int64{thisinfo.Publishtime},
  137. InfoType: [][]string{[]string{thisinfo.TopType, thisinfo.SubType}},
  138. Id: id,
  139. Ids: []string{thisinfo.Id},
  140. Topscopeclass: thisinfo.Topscopeclass,
  141. Subscopeclass: thisinfo.Subscopeclass,
  142. Winners: thisinfo.Winners,
  143. ProjectName: thisinfo.ProjectName,
  144. ProjectCode: thisinfo.ProjectCode,
  145. Buyer: thisinfo.Buyer,
  146. Agency: thisinfo.Agency,
  147. Area: thisinfo.Area,
  148. HasPackage: thisinfo.HasPackage,
  149. Package: map[string]interface{}{},
  150. Buyerclass: thisinfo.Buyerclass,
  151. Bidopentime: thisinfo.Bidopentime,
  152. District: thisinfo.District,
  153. Winnerorder: thisinfo.Winnerorder,
  154. }
  155. for k4, _ := range thisinfo.Package {
  156. p1.Package[k4] = ""
  157. }
  158. return p1
  159. }
  160. //每一个字段的打分map,获取最高分
  161. func GetMaxScore(scoremap map[int]int) (find bool, index int) {
  162. ks := []int{}
  163. vs := []int{}
  164. for k, v := range scoremap {
  165. mk, mv := -1, -100
  166. bf := false
  167. for mk, mv = range vs {
  168. if mv > v {
  169. bf = true
  170. break
  171. }
  172. }
  173. if mk == -1 || !bf {
  174. vs = append(vs, v)
  175. ks = append(ks, k)
  176. } else {
  177. vs = append(append(vs[:mk], v), vs[mk:]...)
  178. ks = append(append(ks[:mk], k), ks[mk:]...)
  179. }
  180. }
  181. if len(ks) > 0 {
  182. index = ks[len(ks)-1]
  183. find = true
  184. }
  185. return
  186. }
  187. //往对应redis中更新信息
  188. func updateinfo(thisinfo *Info, tmp map[string]interface{}, pInfo *ProjectInfo, pici int64) string {
  189. updateid := pInfo.Id
  190. if BinarySearch(pInfo.Ids, thisinfo.Id) > -1 {
  191. return updateid
  192. }
  193. set := map[string]interface{}{
  194. "pici": pici,
  195. }
  196. res, bres := MQFW.FindById(projectColl, pInfo.Id, `{"list":0}`)
  197. EqInfoUpdate(thisinfo, pInfo)
  198. if bres && res != nil && *res != nil {
  199. set["topscopeclass"] = pInfo.Topscopeclass
  200. set["subscopeclass"] = pInfo.Subscopeclass
  201. s_subscopeclass := strings.Join(pInfo.Subscopeclass, ",")
  202. if len(s_subscopeclass) > 0 {
  203. s_subscopeclass = "," + s_subscopeclass + ","
  204. }
  205. set["s_subscopeclass"] = s_subscopeclass
  206. s_winner := strings.Join(pInfo.Winners, ",")
  207. if len(s_winner) > 0 {
  208. s_winner = "," + s_winner + ","
  209. }
  210. set["s_winner"] = s_winner
  211. if pInfo.Buyerperson != "" && pInfo.Buyertel != "" {
  212. set["buyerperson"] = pInfo.Buyerperson
  213. set["buyertel"] = pInfo.Buyertel
  214. }
  215. if pInfo.Buyerclass != "" {
  216. set["buyerclass"] = pInfo.Buyerclass
  217. }
  218. if pInfo.District != "" {
  219. set["district"] = pInfo.District
  220. }
  221. if pInfo.Bidopentime > 0 {
  222. set["bidopentime"] = pInfo.Bidopentime
  223. }
  224. if len(pInfo.Winnerorder) > 0 {
  225. set["winnerorder"] = pInfo.Winnerorder
  226. }
  227. if thisinfo.HasPackage {
  228. set["multipackage"] = 1
  229. } else {
  230. set["multipackage"] = 0
  231. }
  232. e := InitEL(util.ObjToString((*res)["extractpos"]))
  233. if thisinfo.dealtype == 1 {
  234. var sonpackage map[string]interface{}
  235. for _, obj := range tmp["package"].(map[string]interface{}) {
  236. sonpackage, _ = obj.(map[string]interface{})
  237. }
  238. for _, v2 := range []string{"budget", "budget_w", "winner", "winner_w", "bidstatus", "bidstatus_w"} {
  239. if sonpackage[v2] != nil {
  240. tmp[v2] = sonpackage[v2]
  241. }
  242. }
  243. }
  244. e.fieldpriority(&tmp, res, &set)
  245. set["extractpos"] = e.GetVal()
  246. if thisinfo.HasPackage { //多包处理
  247. p1, _ := (*res)["package"].(map[string]interface{})
  248. p2, _ := tmp["package"].(map[string]interface{})
  249. if p2 != nil {
  250. if p1 != nil {
  251. for pk2, pv2 := range p2 {
  252. if p1[pk2] != nil { //合并
  253. item1, _ := p1[pk2].(map[string]interface{})
  254. item2, _ := pv2.(map[string]interface{})
  255. if item1 != nil && item2 != nil { //原始项
  256. for ik1, iv1 := range item2 {
  257. if item1[ik1] == nil {
  258. item1[ik1] = iv1
  259. }
  260. }
  261. }
  262. } else {
  263. p1[pk2] = pv2
  264. }
  265. }
  266. } else {
  267. p1 = p2
  268. }
  269. }
  270. set["package"] = p1
  271. }
  272. //中标候选人合并
  273. update := map[string]interface{}{}
  274. if len(set) > 0 {
  275. update["$set"] = set
  276. }
  277. //保留原数据吧
  278. push := NewPushInfo(tmp)
  279. for tkey, _ := range extractpos {
  280. if tmp[tkey] != nil {
  281. push[tkey] = tmp[tkey]
  282. }
  283. }
  284. update["$push"] = map[string]interface{}{
  285. "list": push,
  286. }
  287. if len(update) > 0 {
  288. MQFW.Update(projectColl, map[string]interface{}{
  289. "_id": util.StringTOBsonId(pInfo.Id),
  290. }, &update, false, false)
  291. }
  292. }
  293. //再往redis中放 index
  294. //往队列中增加时间 -------------->start
  295. redis.Put(REDISIDS, updateid, pInfo, 0)
  296. return updateid
  297. }
  298. func EqInfoUpdate(thisinfo *Info, pInfo *ProjectInfo) {
  299. var tk int
  300. bf1 := false
  301. for _k, tv := range pInfo.Publistime {
  302. tk = _k
  303. if tv > thisinfo.Publishtime {
  304. bf1 = true
  305. break
  306. }
  307. }
  308. if bf1 {
  309. pInfo.Publistime = append(append(pInfo.Publistime[:tk], thisinfo.Publishtime), pInfo.Publistime[tk:]...)
  310. pInfo.InfoType = append(append(pInfo.InfoType[:tk], []string{thisinfo.TopType, thisinfo.SubType}), pInfo.InfoType[tk:]...)
  311. pInfo.Ids = append(append(pInfo.Ids[:tk], thisinfo.Id), pInfo.Ids[tk:]...)
  312. } else {
  313. pInfo.Publistime = append(pInfo.Publistime, thisinfo.Publishtime)
  314. pInfo.InfoType = append(pInfo.InfoType, []string{thisinfo.TopType, thisinfo.SubType})
  315. pInfo.Ids = append(pInfo.Ids, thisinfo.Id)
  316. }
  317. //增加发布时间结束----------------->end
  318. if (pInfo.Buyer == "" && thisinfo.Buyer != "") || (len([]rune(pInfo.Buyer)) < 5 && len([]rune(thisinfo.Buyer)) > 5) {
  319. pInfo.Buyer = thisinfo.Buyer
  320. }
  321. if (pInfo.Agency == "" && thisinfo.Agency != "") || (len([]rune(pInfo.Agency)) < 5 && len([]rune(thisinfo.Agency)) > 5) {
  322. pInfo.Agency = thisinfo.Agency
  323. }
  324. if (pInfo.ProjectCode == "" && thisinfo.ProjectCode != "") || (len([]rune(pInfo.ProjectCode)) < 6 && len([]rune(thisinfo.ProjectCode)) > 6) {
  325. pInfo.ProjectCode = thisinfo.ProjectCode
  326. }
  327. if thisinfo.Buyerperson != "" && thisinfo.Buyertel != "" && len([]rune(thisinfo.Buyertel)) > 6 {
  328. pInfo.Buyerperson = thisinfo.Buyerperson
  329. pInfo.Buyertel = thisinfo.Buyertel
  330. }
  331. if thisinfo.Buyerclass != "" {
  332. pInfo.Buyerclass = thisinfo.Buyerclass
  333. }
  334. if thisinfo.District != "" {
  335. pInfo.District = thisinfo.District
  336. }
  337. if thisinfo.Bidopentime > 0 {
  338. pInfo.Bidopentime = thisinfo.Bidopentime
  339. }
  340. if len(thisinfo.Topscopeclass) > 0 {
  341. sort.Strings(pInfo.Topscopeclass)
  342. for _, k := range thisinfo.Topscopeclass {
  343. if BinarySearch(pInfo.Topscopeclass, k) == -1 {
  344. pInfo.Topscopeclass = append(pInfo.Topscopeclass, k)
  345. sort.Strings(pInfo.Topscopeclass)
  346. }
  347. }
  348. }
  349. if len(thisinfo.Subscopeclass) > 0 {
  350. sort.Strings(pInfo.Subscopeclass)
  351. for _, k := range thisinfo.Subscopeclass {
  352. if BinarySearch(pInfo.Subscopeclass, k) == -1 {
  353. pInfo.Subscopeclass = append(pInfo.Subscopeclass, k)
  354. sort.Strings(pInfo.Subscopeclass)
  355. }
  356. }
  357. }
  358. //winner
  359. if len(thisinfo.Winners) > 0 {
  360. sort.Strings(pInfo.Winners)
  361. for _, k := range thisinfo.Winners {
  362. if BinarySearch(pInfo.Winners, k) == -1 {
  363. pInfo.Winners = append(pInfo.Winners, k)
  364. sort.Strings(pInfo.Winners)
  365. }
  366. }
  367. }
  368. //winnerorder
  369. if len(thisinfo.Winnerorder) > 0 {
  370. sort.Strings(pInfo.Winnerorder)
  371. for _, k := range thisinfo.Winnerorder {
  372. if BinarySearch(pInfo.Winnerorder, k) == -1 {
  373. pInfo.Winnerorder = append(pInfo.Winnerorder, k)
  374. sort.Strings(pInfo.Winnerorder)
  375. }
  376. }
  377. }
  378. //return pInfo
  379. }
  380. //二分字符串查找
  381. func BinarySearch(s []string, k string) int {
  382. sort.Strings(s)
  383. lo, hi := 0, len(s)-1
  384. for lo <= hi {
  385. m := (lo + hi) >> 1
  386. if s[m] < k {
  387. lo = m + 1
  388. } else if s[m] > k {
  389. hi = m - 1
  390. } else {
  391. return m
  392. }
  393. }
  394. return -1
  395. }
  396. //移除数组中重复的元素
  397. func RemoveDup(arr []string) (newarr []string) {
  398. m1 := map[string]bool{}
  399. newarr = []string{}
  400. for _, k := range arr {
  401. if !m1[k] {
  402. m1[k] = true
  403. newarr = append(newarr, k)
  404. }
  405. }
  406. return
  407. }