infotool.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. package main
  2. import (
  3. "encoding/json"
  4. // "fmt"
  5. du "jy/util"
  6. qu "qfw/util"
  7. "regexp"
  8. "strings"
  9. "sync"
  10. "time"
  11. "gopkg.in/mgo.v2/bson"
  12. )
  13. //抽取信息映射实体类
  14. type Info struct {
  15. Id string `json:"_id"`
  16. Href string `json:"href"`
  17. Publishtime int64 `json:"publishtime"`
  18. Title string `json:"title"`
  19. TopType string `json:"toptype"`
  20. SubType string `json:"subtype"`
  21. ProjectName string `json:"projectname"`
  22. ProjectCode string `json:"projectcode"`
  23. Buyer string `json:"buyer"`
  24. Buyerperson string `json:"buyerperson"`
  25. Buyertel string `json:"buyertel"`
  26. Agency string `json:"agency"`
  27. Area string `json:"area"`
  28. City string `json:"city"`
  29. HasPackage bool `json:"haspackage"`
  30. Package map[string]interface{} `json:"package"`
  31. PNum string `json:"pnum"`
  32. Topscopeclass []string `json:"topscopeclass"`
  33. Subscopeclass []string `json:"subscopeclass"`
  34. Winners []string
  35. dealtype int
  36. Buyerclass string `json:"buyerclass"`
  37. Bidopentime int64 `json:"bidopentime"`
  38. District string `json:"district"`
  39. Winnerorder []string
  40. PTC string
  41. pnbval int
  42. LenPC int
  43. LenPN int
  44. LenPTC int
  45. }
  46. var (
  47. PNKeyMap, PCKeyMap, PBKeyMap = sync.Map{}, sync.Map{}, sync.Map{}
  48. pnreg = regexp.MustCompile("^(及编号[::])|(项目|采购|招标|中标|成交|结果|[_]|公告)$")
  49. titleGetPn = regexp.MustCompile("^([\\[【((]?.?(资格预审|中标|招标|延期|成交|结果|合同|失败|询价|关于对?)(公告)?[\\]】))]?([::]|关于对?)?)?(.{4,70}?(采购|工程)?(项目)?)([((【]?(第?[一二三四五六七八九1-9再]次|重新|重招|公开|[预拟]).{0,3}?[))】]?)?(招标|采购|采购计划|发包|结果|变更|更正|成交|网上(竞价)?|电子化|电子反拍|询比?价|比价|竞争性(谈判|磋商)|流标|废标|邀请|合同|验收|违规|资格|预审|中标(结果)?|延期|澄清|暂停|补遗|终止|文件|标前|征求|报建|征集|论证|谈判|拟实施|中止|需求|比选|评标(过程)?及?|磋商|未入围|进口|投标|答疑|抽签|异常|质疑|答复|回复|应答|遴选|最高|拦标|推迟|开标|取消|延迟|撤销|控制价|场外|作废|候选人|采用|实施|预|不良记录|竞买|反拍|修正|调整|简称|小型)?(公告|记录|公示|预告|通知[函书]?|意见[函书]?|[函书])?([((【].*?[))】])?$")
  50. titleGetPc = regexp.MustCompile("^([-0-9a-zA-Z第号采招政询电审竞#]{8,}[-0-9a-zA-Z#]+)")
  51. titleGetPc1 = regexp.MustCompile("[\\[【((](.{0,6}(编号|编码|项号|包号|代码|标段?号)[::为])?([-0-9a-zA-Z第号采招政询电审竞#]{5,}([\\[\\]()()][-0-9a-zA-Z第号采招审竞#]+[\\[\\]()()][-0-9a-zA-Z第号采招审竞#]+)?)[\\]】))]")
  52. titleGetPc2 = regexp.MustCompile("([-0-9a-zA-Z第号采政招询电审竞#]{8,}[-0-9a-zA-Z#]+)(.{0,5}公告)?$")
  53. numreg = regexp.MustCompile("^[0-9]$")
  54. numreg2 = regexp.MustCompile("^[0-9]+$")
  55. numCheckPc = regexp.MustCompile("^[0-9-]{1,10}$")
  56. TitleReg = regexp.MustCompile("([一二三四五六七八九十0-9A-Za-zⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ、\\-~至]+(子|合同|分|施工|监理|标)?[包标段][号段]?[、]?)+|((子|合同|分|施工|监理|标)?[包标段][号段]?[一二三四五六七八九十0-9A-Za-zⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ、\\-~至]+[、]?)+|(子|合同|分|施工|监理|标)?[包标段][号段]?[a-zA-Z0-9]+[\\-~-至、](子|合同|分|施工|监理|标)?[包标段][号段]?[a-zA-Z0-9]+")
  57. )
  58. type ProjectInfo struct {
  59. Id string `json:"id"`
  60. Publistime []int64 `json:"publistime"` //多条信息的发布时间、跨度
  61. InfoType [][]string `json:"infotype"` //多条信息内的 toptype、subtype
  62. Ids []string `json:"ids"`
  63. Topscopeclass []string `json:"topscopeclass"`
  64. Subscopeclass []string `json:"subscopeclass"`
  65. Winners []string `json:"winners"`
  66. ProjectName string `json:"projectname"`
  67. ProjectCode string `json:"projectcode"` //项目代码唯一(纯数字的权重低)
  68. Buyer string `json:"buyer"` //采购单位唯一
  69. MPN []string `json:"mpn"` //合并后多余的项目名称
  70. MPC []string `json:"mpc"` //合并后多余的项目编号
  71. Buyerperson string `json:"buyerperson"`
  72. Buyertel string `json:"buyertel"`
  73. Agency string `json:"agency"` //代理机构唯一
  74. Area string `json:"area"` //地区唯一
  75. City string `json:"city"` //地市
  76. District string `json:"district"` //区县
  77. HasPackage bool `json:"haspackage"` //是否有分包
  78. Package map[string]interface{} `json:"package"` //分包的对比对象
  79. Buyerclass string `json:"buyerclass"` //采购单位分类
  80. Bidopentime int64 `json:"bidopentime"` //开标时间
  81. Winnerorder []string //中标候选人
  82. score int
  83. comStr string
  84. }
  85. type KeyMap struct {
  86. Lock sync.Mutex
  87. Map map[string]*Key
  88. }
  89. type Key struct {
  90. Arr []string
  91. Lock sync.Mutex
  92. }
  93. type IdAndLock struct {
  94. Id string
  95. Lock sync.Mutex
  96. }
  97. func NewKeyMap() *KeyMap {
  98. return &KeyMap{
  99. Map: map[string]*Key{},
  100. Lock: sync.Mutex{},
  101. }
  102. }
  103. var size, idsMapSize = 30, 100
  104. var AllPNMap = make([]*KeyMap, size) //存储 项目名称,值为id数组
  105. var AllPCMap = make([]*KeyMap, size) //存储 项目编号,值为id数组
  106. var AllPTCMap = make([]*KeyMap, size) //存储 项目编号,值为id数组
  107. var AllPBMap = make([]*KeyMap, size) //存储 采购单位,值为id数组
  108. type ID struct {
  109. Id string
  110. Lock sync.Mutex
  111. lastTime int64
  112. pos int
  113. }
  114. //所有项目id对象,加锁,删除等用
  115. var AllIdsMap = make([]map[string]*ID, idsMapSize)
  116. var AllIdsMap2 = map[string]*ID{}
  117. var AllIdsMapLock = sync.Mutex{}
  118. //预定义字符串 [ABCD][ABCD][ABCD] 项目名称/编号/标题编号
  119. var compareNoPass = map[string]bool{}
  120. var compareAB = map[string]bool{}
  121. var compareAB2D = map[string]bool{}
  122. var compareABD = map[string]bool{}
  123. var compareAB2CD = map[string]bool{}
  124. var compareABCD = map[string]bool{}
  125. func init() {
  126. for i := 0; i < size; i++ {
  127. AllPNMap[i] = NewKeyMap()
  128. AllPCMap[i] = NewKeyMap()
  129. AllPTCMap[i] = NewKeyMap()
  130. AllPBMap[i] = NewKeyMap()
  131. }
  132. for i := 0; i < idsMapSize; i++ {
  133. AllIdsMap[i] = map[string]*ID{}
  134. }
  135. //---不能通过
  136. vm := []string{"C", "D"}
  137. for i := 0; i < 2; i++ {
  138. for j := 0; j < 2; j++ {
  139. for k := 0; k < 2; k++ {
  140. key := vm[i] + vm[j] + vm[k]
  141. compareNoPass[key] = true
  142. //fmt.Println(key)
  143. }
  144. }
  145. }
  146. //fmt.Println("-------------------")
  147. //三个元素一致 [AB][AB][AB],分值最高
  148. vm = []string{"A", "B"}
  149. for i := 0; i < 2; i++ {
  150. for j := 0; j < 2; j++ {
  151. for k := 0; k < 2; k++ {
  152. key := vm[i] + vm[j] + vm[k]
  153. compareAB[key] = true
  154. //fmt.Println(key)
  155. }
  156. }
  157. }
  158. //fmt.Println("-------------------", len(compareAB))
  159. //---至少两个一致,其他可能不存在
  160. //[AB][AB][ABD]
  161. //[AB][ABD][AB]
  162. vm = []string{"A", "B"}
  163. vm2 := []string{"A", "B", "D"}
  164. for i := 0; i < 2; i++ {
  165. for j := 0; j < 2; j++ {
  166. for k := 0; k < 3; k++ {
  167. key := vm[i] + vm[j] + vm2[k]
  168. if !compareAB[key] {
  169. compareAB2D[key] = true
  170. //fmt.Println(key)
  171. }
  172. }
  173. }
  174. }
  175. for i := 0; i < 2; i++ {
  176. for j := 0; j < 3; j++ {
  177. for k := 0; k < 2; k++ {
  178. key := vm[i] + vm2[j] + vm[k]
  179. if !compareAB[key] {
  180. compareAB2D[key] = true
  181. //fmt.Println(key)
  182. }
  183. }
  184. }
  185. }
  186. //fmt.Println("-------------------", len(compareAB2D))
  187. //---至少一个一致,其他可能不存在
  188. //[ABD][ABD][ABD] //已经删除DDD
  189. vm = []string{"A", "B", "D"}
  190. for i := 0; i < 3; i++ {
  191. for j := 0; j < 3; j++ {
  192. for k := 0; k < 3; k++ {
  193. key := vm[i] + vm[j] + vm[k]
  194. if !compareAB[key] && !compareAB2D[key] && !compareNoPass[key] {
  195. compareABD[key] = true
  196. //fmt.Println(key)
  197. }
  198. }
  199. }
  200. }
  201. //fmt.Println("-------------------", len(compareABD))
  202. //[AB][ABCD][AB]
  203. //[AB][AB][ABCD]
  204. vm = []string{"A", "B"}
  205. vm2 = []string{"A", "B", "C", "D"}
  206. for i := 0; i < 2; i++ {
  207. for j := 0; j < 4; j++ {
  208. for k := 0; k < 2; k++ {
  209. key := vm[i] + vm2[j] + vm[k]
  210. if !compareAB[key] && !compareAB2D[key] && !compareNoPass[key] && !compareABD[key] {
  211. compareAB2CD[key] = true
  212. //fmt.Println(key)
  213. }
  214. }
  215. }
  216. }
  217. for i := 0; i < 2; i++ {
  218. for j := 0; j < 2; j++ {
  219. for k := 0; k < 4; k++ {
  220. key := vm[i] + vm[j] + vm2[k]
  221. if !compareAB[key] && !compareAB2D[key] && !compareNoPass[key] && !compareABD[key] {
  222. compareAB2CD[key] = true
  223. //fmt.Println(key)
  224. }
  225. }
  226. }
  227. }
  228. //fmt.Println("-------------------", len(compareAB2CD))
  229. //[ABECD][ABECD][ABECD] //已经删除[CD][CD][CD] //这个要重点讨论
  230. vm = []string{"A", "B", "C", "D"}
  231. for i := 0; i < 4; i++ {
  232. for j := 0; j < 4; j++ {
  233. for k := 0; k < 4; k++ {
  234. key := vm[i] + vm[j] + vm[k]
  235. if !compareAB[key] && !compareAB2D[key] && !compareABD[key] && !compareNoPass[key] && !compareAB2CD[key] {
  236. compareABCD[key] = true
  237. //fmt.Println(key)
  238. }
  239. }
  240. }
  241. }
  242. //fmt.Println("-------------------", len(compareABCD))
  243. }
  244. //预处理信息
  245. func PreThisInfo(tmp map[string]interface{}) *Info {
  246. bys, _ := json.Marshal(tmp)
  247. var thisinfo *Info
  248. json.Unmarshal(bys, &thisinfo)
  249. if thisinfo == nil {
  250. return nil
  251. }
  252. if len(thisinfo.Topscopeclass) == 0 {
  253. thisinfo.Topscopeclass = []string{}
  254. }
  255. if len(thisinfo.Subscopeclass) == 0 {
  256. thisinfo.Subscopeclass = []string{}
  257. }
  258. //去重
  259. thisinfo.Subscopeclass = RemoveDup(thisinfo.Subscopeclass)
  260. if len(thisinfo.Package) > 0 { //信息是否分包
  261. thisinfo.HasPackage = true
  262. } else if thisinfo.TopType == "结果" && TitleReg.MatchString(thisinfo.Title) {
  263. //当信息类型是结果时,并且标题中包含分包字样,找到包号,用以后面比较打分
  264. res := TitleReg.FindAllStringSubmatch(thisinfo.Title, -1)
  265. pnum := du.PackageNumberConvert(res[0][0])
  266. //du.Debug(pnum, res)
  267. thisinfo.PNum = pnum
  268. }
  269. // if checkInfoAlter(tmp) {
  270. // thisinfo.SubType = "变更"
  271. // }
  272. //计算中标人
  273. winner, _ := tmp["winner"].(string)
  274. m1 := map[string]bool{}
  275. winners := []string{}
  276. if winner != "" {
  277. m1[winner] = true
  278. winners = append(winners, winner)
  279. }
  280. if thisinfo.HasPackage {
  281. packageM, _ := tmp["package"].(bson.M)
  282. for _, p := range packageM {
  283. pm, _ := p.(map[string]interface{})
  284. pw, _ := pm["winner"].(string)
  285. if pw != "" {
  286. m1[pw] = true
  287. winners = append(winners, pw)
  288. }
  289. }
  290. }
  291. thisinfo.Winners = winners
  292. m1 = nil
  293. //中标候选人
  294. winnerorder := []string{}
  295. if winorders, ok := tmp["winnerorder"].([]interface{}); ok {
  296. for _, wins := range winorders {
  297. if win, ok := wins.(map[string]interface{}); ok {
  298. entname := qu.ObjToString(win["entname"])
  299. if entname != "" && len([]rune(entname)) > 6 {
  300. winnerorder = append(winnerorder, entname)
  301. }
  302. }
  303. }
  304. }
  305. thisinfo.Winnerorder = winnerorder
  306. res := titleGetPc.FindStringSubmatch(thisinfo.Title)
  307. if len(res) > 1 && len(res[1]) > 8 && thisinfo.ProjectCode != res[1] && !numCheckPc.MatchString(res[1]) && !_zimureg1.MatchString(res[1]) {
  308. thisinfo.PTC = res[1]
  309. thisinfo.pnbval++
  310. } else {
  311. res = titleGetPc1.FindStringSubmatch(thisinfo.Title)
  312. if len(res) > 3 && len(res[3]) > 8 && thisinfo.ProjectCode != res[3] && !numCheckPc.MatchString(res[3]) && !_zimureg1.MatchString(res[3]) {
  313. thisinfo.PTC = res[3]
  314. thisinfo.pnbval++
  315. } else {
  316. res = titleGetPc2.FindStringSubmatch(thisinfo.Title)
  317. if len(res) > 1 && len(res[1]) > 8 && thisinfo.ProjectCode != res[1] && !numCheckPc.MatchString(res[1]) && !_zimureg1.MatchString(res[1]) {
  318. thisinfo.PTC = res[1]
  319. thisinfo.pnbval++
  320. }
  321. }
  322. }
  323. if thisinfo.ProjectName != "" {
  324. thisinfo.pnbval++
  325. }
  326. if thisinfo.ProjectCode != "" && !_zimureg1.MatchString(thisinfo.ProjectCode) {
  327. thisinfo.pnbval++
  328. } else {
  329. thisinfo.ProjectCode = ""
  330. }
  331. if thisinfo.Buyer != "" {
  332. thisinfo.pnbval++
  333. }
  334. thisinfo.LenPC = len([]rune(thisinfo.ProjectCode))
  335. thisinfo.LenPTC = len([]rune(thisinfo.PTC))
  336. thisinfo.LenPN = len([]rune(thisinfo.ProjectName))
  337. return thisinfo
  338. }
  339. //移除数组中重复的元素
  340. func RemoveDup(arr []string) (newarr []string) {
  341. m1 := map[string]bool{}
  342. newarr = []string{}
  343. for _, k := range arr {
  344. if !m1[k] {
  345. m1[k] = true
  346. newarr = append(newarr, k)
  347. }
  348. }
  349. return
  350. }
  351. //阻塞同名的pb、pc、pv并发
  352. func lockPNCBMap(thisinfo *Info) {
  353. for { //等待其他任务完成
  354. ok := true
  355. if thisinfo.LenPN > 0 {
  356. if _, b := PNKeyMap.Load(thisinfo.ProjectName); b {
  357. ok = false
  358. }
  359. }
  360. if thisinfo.LenPC > 0 {
  361. if _, b := PCKeyMap.Load(thisinfo.ProjectCode); b {
  362. ok = false
  363. }
  364. }
  365. if thisinfo.LenPTC > 0 {
  366. if _, b := PCKeyMap.Load(thisinfo.PTC); b {
  367. ok = false
  368. }
  369. }
  370. if len(thisinfo.Buyer) > 0 {
  371. if _, b := PBKeyMap.Load(thisinfo.Buyer); b {
  372. ok = false
  373. }
  374. }
  375. if ok {
  376. break
  377. } else {
  378. time.Sleep(30 * time.Millisecond)
  379. }
  380. }
  381. }
  382. //放行
  383. func unlockPNCBMap(thisinfo *Info) {
  384. PNKeyMap.Delete(thisinfo.ProjectName)
  385. PCKeyMap.Delete(thisinfo.ProjectCode)
  386. PCKeyMap.Delete(thisinfo.PTC)
  387. PBKeyMap.Delete(thisinfo.Buyer)
  388. }
  389. //判断信息是否是变更
  390. func checkInfoAlter(tmp map[string]interface{} /*新信息*/) bool {
  391. toptype := qu.ObjToString(tmp["toptype"])
  392. subtype := qu.ObjToString(tmp["subtype"])
  393. title := qu.ObjToString(tmp["title"])
  394. if subtype == "变更" || strings.Index(title, "变更公告") > -1 || strings.Index(title, "更正公告") > -1 {
  395. //当信息类型是变更或标题中含变更时
  396. if toptype == "招标" {
  397. //招标的变更公告,不作处理
  398. } else if toptype == "结果" {
  399. subtype = "变更"
  400. }
  401. }
  402. return subtype == "变更"
  403. }