compare.go 13 KB

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