datamap.go 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. qutil "qfw/util"
  6. "qfw/util/mongodb"
  7. "strings"
  8. "sync"
  9. "time"
  10. )
  11. type Info struct {
  12. id string //id
  13. title string //标题
  14. area string //省份
  15. city string //城市
  16. subtype string //信息类型
  17. buyer string //采购单位
  18. agency string //代理机构
  19. winner string //中标单位
  20. budget float64 //预算金额
  21. bidamount float64 //中标金额
  22. projectname string //项目名称
  23. projectcode string //项目编号
  24. contractnumber string //合同编号
  25. publishtime int64 //发布时间
  26. bidopentime int64 //开标时间
  27. agencyaddr string //开标地点
  28. site string //站点
  29. href string //正文的url
  30. repeatid string //重复id
  31. titleSpecialWord bool //标题特殊词
  32. specialWord bool //再次判断的特殊词
  33. mergemap map[string]interface{} //合并记录
  34. }
  35. var datelimit = float64(432000) //五天
  36. var sitelock sync.Mutex //锁
  37. //一般数据判重
  38. type datamap struct {
  39. lock sync.Mutex //锁
  40. days int //保留几天数据
  41. data map[string][]*Info
  42. keymap []string
  43. keys map[string]bool
  44. }
  45. //历史更新数据
  46. type historymap struct {
  47. lock sync.Mutex //锁
  48. days int //保留几天数据
  49. data map[string][]*Info
  50. keymap []string
  51. keys map[string]bool
  52. }
  53. func NewDatamap(days int, lastid string) *datamap {
  54. datelimit = qutil.Float64All(days * 86400)
  55. dm := &datamap{sync.Mutex{}, days, map[string][]*Info{}, []string{}, map[string]bool{}}
  56. if lastid == "" {
  57. return dm
  58. }
  59. //初始化加载数据
  60. sess := mgo.GetMgoConn()
  61. defer mgo.DestoryMongoConn(sess)
  62. it := sess.DB(mgo.DbName).C(extract).Find(mongodb.ObjToMQ(`{"_id":{"$lte":"`+lastid+`"}}`, true)).Sort("-_id").Iter()
  63. now1 := int64(0)
  64. n, continuSum := 0, 0
  65. for tmp := make(map[string]interface{}); it.Next(&tmp); n++ {
  66. if qutil.IntAll(tmp["repeat"]) == 1 || qutil.IntAll(tmp["repeat"]) == -1 {
  67. continuSum++
  68. } else {
  69. pt:=tmp["publishtime"]
  70. pt_time:=qutil.Int64All(pt)
  71. if pt_time<=0 {
  72. continue
  73. }
  74. if now1 == 0 {
  75. now1 = pt_time
  76. }
  77. if qutil.Float64All(now1-pt_time) < datelimit {
  78. info := NewInfo(tmp)
  79. dkey := qutil.FormatDateWithObj(&pt, qutil.Date_yyyyMMdd)
  80. k := fmt.Sprintf("%s_%s_%s", dkey, info.subtype, info.area)
  81. data := dm.data[k]
  82. if data == nil {
  83. data = []*Info{}
  84. }
  85. data = append(data, info)
  86. dm.data[k] = data
  87. dm.keys[dkey] = true
  88. } else {
  89. break
  90. }
  91. }
  92. if n%5000 == 0 {
  93. log.Println("current n:", n, continuSum)
  94. }
  95. tmp = make(map[string]interface{})
  96. }
  97. log.Println("load data:", n)
  98. return dm
  99. }
  100. //构建新历史数据池
  101. func NewHistorymap(startid string, lastid string, startTime int64, lastTime int64) *historymap {
  102. datelimit = qutil.Float64All(5 * 86400)
  103. hm := &historymap{sync.Mutex{}, 5, map[string][]*Info{}, []string{}, map[string]bool{}}
  104. if lastid == "" || startid == "" {
  105. return hm
  106. }
  107. //取startid之前5天
  108. sess_start := mgo.GetMgoConn()
  109. defer mgo.DestoryMongoConn(sess_start) //lte gte
  110. it_start := sess_start.DB(mgo.DbName).C(extract).Find(mongodb.ObjToMQ(`{"_id":{"$lte":"`+startid+`"}}`,
  111. true)).Sort("-_id").Iter()
  112. m, n := 0, 0
  113. for tmp_start := make(map[string]interface{}); it_start.Next(&tmp_start); {
  114. pt_s:=tmp_start["publishtime"]
  115. pt_time:=qutil.Int64All(pt_s)
  116. if pt_time<=0 {
  117. continue
  118. }
  119. if qutil.Float64All(startTime-pt_time) <= datelimit {
  120. n++
  121. info := NewInfo(tmp_start)
  122. dkey := qutil.FormatDateWithObj(&pt_s, qutil.Date_yyyyMMdd)
  123. k := fmt.Sprintf("%s_%s_%s", dkey, info.subtype, info.area)
  124. data := hm.data[k]
  125. if data == nil {
  126. data = []*Info{}
  127. }
  128. data = append(data, info)
  129. hm.data[k] = data
  130. hm.keys[dkey] = true
  131. } else {
  132. break
  133. }
  134. tmp_start = make(map[string]interface{})
  135. }
  136. log.Println("load history 前:", n)
  137. //取lastid之后5天
  138. sess_last := mgo.GetMgoConn()
  139. defer mgo.DestoryMongoConn(sess_last) //lte gte
  140. it_last := sess_last.DB(mgo.DbName).C(extract).Find(mongodb.ObjToMQ(`{"_id":{"$gte":"`+lastid+`"}}`,
  141. true)).Sort("_id").Iter()
  142. for tmp_last := make(map[string]interface{}); it_last.Next(&tmp_last); {
  143. pt_l:=tmp_last["publishtime"]
  144. pt_time:=qutil.Int64All(pt_l)
  145. if pt_time<=0 {
  146. continue
  147. }
  148. if qutil.Float64All(pt_time-lastTime) <= datelimit {
  149. m++
  150. info := NewInfo(tmp_last)
  151. dkey := qutil.FormatDateWithObj(&pt_l, qutil.Date_yyyyMMdd)
  152. k := fmt.Sprintf("%s_%s_%s", dkey, info.subtype, info.area)
  153. data := hm.data[k]
  154. if data == nil {
  155. data = []*Info{}
  156. }
  157. data = append(data, info)
  158. hm.data[k] = data
  159. hm.keys[dkey] = true
  160. } else {
  161. break
  162. }
  163. tmp_last = make(map[string]interface{})
  164. }
  165. log.Println("load history 后:", m)
  166. return hm
  167. }
  168. func NewInfo(tmp map[string]interface{}) *Info {
  169. subtype := qutil.ObjToString(tmp["subtype"])
  170. area := qutil.ObjToString(tmp["area"])
  171. if area == "A" {
  172. area = "全国"
  173. }
  174. info := &Info{}
  175. info.id = qutil.BsonIdToSId(tmp["_id"])
  176. info.title = qutil.ObjToString(tmp["title"])
  177. info.area = area
  178. info.subtype = subtype
  179. info.buyer = qutil.ObjToString(tmp["buyer"])
  180. info.projectname = qutil.ObjToString(tmp["projectname"])
  181. info.contractnumber = qutil.ObjToString(tmp["contractnumber"])
  182. info.projectcode = qutil.ObjToString(tmp["projectcode"])
  183. info.city = qutil.ObjToString(tmp["city"])
  184. info.agency = qutil.ObjToString(tmp["agency"])
  185. info.winner = qutil.ObjToString(tmp["winner"])
  186. info.budget = qutil.Float64All(tmp["budget"])
  187. info.bidamount = qutil.Float64All(tmp["bidamount"])
  188. info.publishtime = qutil.Int64All(tmp["publishtime"])
  189. info.bidopentime = qutil.Int64All(tmp["bidopentime"])
  190. info.agencyaddr = qutil.ObjToString(tmp["agencyaddr"])
  191. info.site = qutil.ObjToString(tmp["site"])
  192. info.href = qutil.ObjToString(tmp["href"])
  193. info.repeatid = qutil.ObjToString(tmp["repeatid"])
  194. info.specialWord = FilterRegTitle.MatchString(info.title)
  195. info.titleSpecialWord = FilterRegTitle_1.MatchString(info.title) || FilterRegTitle_2.MatchString(info.title)
  196. info.mergemap = *qutil.ObjToMap(tmp["merge_map"])
  197. if info.mergemap == nil {
  198. info.mergemap = make(map[string]interface{}, 0)
  199. }
  200. return info
  201. }
  202. //判重方法
  203. func (d *datamap) check(info *Info) (b bool, source *Info, reasons string) {
  204. reason:=""
  205. keys := []string{}
  206. d.lock.Lock()
  207. for k, _ := range d.keys { //不同时间段
  208. keys = append(keys, fmt.Sprintf("%s_%s_%s", k, info.subtype, info.area))
  209. if info.area != "全国" { //这个后续可以不要
  210. keys = append(keys, fmt.Sprintf("%s_%s_%s", k, info.subtype, "全国"))
  211. }
  212. }
  213. d.lock.Unlock()
  214. L:
  215. for _, k := range keys {
  216. d.lock.Lock()
  217. data := d.data[k]
  218. d.lock.Unlock()
  219. if len(data) > 0 { //对比v 找到同类型,同省或全国的数据作对比
  220. for _, v := range data {
  221. reason = ""
  222. if v.id == info.id { //正常重复
  223. return false, v, ""
  224. }
  225. if info.subtype == v.subtype {
  226. if info.site != "" {
  227. sitelock.Lock()
  228. dict := SiteMap[info.site]
  229. sitelock.Unlock()
  230. if dict != nil {
  231. if info.area == "全国" && dict["area"] != "" {
  232. info.area = qutil.ObjToString(dict["area"])
  233. info.city = qutil.ObjToString(dict["city"])
  234. } else {
  235. if info.city == "" && dict["city"] != "" {
  236. info.area = qutil.ObjToString(dict["area"])
  237. info.city = qutil.ObjToString(dict["city"])
  238. }
  239. }
  240. }
  241. }
  242. //前置条件1 - 站点相关
  243. if info.site != "" && info.site == v.site {
  244. if info.href != "" && info.href == v.href {
  245. reason = "href相同"
  246. b = true
  247. source = v
  248. reasons = reason
  249. break L
  250. }
  251. if info.href != "" && info.href != v.href {
  252. reason = "href不同-"
  253. }
  254. }
  255. //前置条件2 - 标题相关,有且一个关键词
  256. if ((info.titleSpecialWord && !v.titleSpecialWord) || (info.specialWord && !v.specialWord)) &&
  257. info.title != v.title && v.title != "" && info.title != "" {
  258. continue
  259. }
  260. //前置条件3 - 标题相关,均含有关键词
  261. if ((info.titleSpecialWord && v.titleSpecialWord) || (info.specialWord && v.specialWord)) &&
  262. len([]rune(v.title)) > 10 && len([]rune(info.title)) > 10 && v.title != "" && info.title != "" {
  263. if !(strings.Contains(v.title, info.title) || strings.Contains(info.title, v.title)) {
  264. continue //无包含关系
  265. }
  266. if strings.Contains(v.title, info.title) || strings.Contains(info.title, v.title) {
  267. reason = reason+"标题关键词且包含关系"
  268. //继续二级金额判断
  269. if !againRepeat(v,info){
  270. b = true
  271. source = v
  272. reasons = reason
  273. break
  274. }
  275. }
  276. }
  277. //代理机构相同-非空相等
  278. if v.agency != "" && info.agency != "" && v.agency == info.agency {
  279. reason = reason + "同机构-"
  280. repeat := false
  281. if repeat, reason = quickHeavyMethodTwo(v, info, reason); repeat {
  282. b = true
  283. source = v
  284. reasons = reason
  285. break
  286. }
  287. } else {
  288. reason = reason + "非同机构-"
  289. if info.city != "" && info.city == v.city {
  290. reason = reason + "同城-"
  291. repeat := false
  292. if repeat, reason = quickHeavyMethodTwo(v, info, reason); repeat {
  293. b = true
  294. source = v
  295. reasons = reason
  296. break
  297. }
  298. } else {
  299. reason = reason + "不同城-"
  300. repeat := false
  301. if repeat, reason = quickHeavyMethodOne(v, info, reason); repeat {
  302. b = true
  303. source = v
  304. reasons = reason
  305. break
  306. }
  307. }
  308. }
  309. }
  310. }
  311. }
  312. }
  313. //往预存数据 d 添加
  314. if !b {
  315. ct := info.publishtime
  316. dkey := qutil.FormatDateByInt64(&ct, qutil.Date_yyyyMMdd)
  317. k := fmt.Sprintf("%s_%s_%s", dkey, info.subtype, info.area)
  318. d.lock.Lock()
  319. data := d.data[k]
  320. if data == nil {
  321. data = []*Info{info}
  322. d.data[k] = data
  323. if !d.keys[dkey] {
  324. d.keys[dkey] = true
  325. d.update(ct)
  326. }
  327. } else {
  328. data = append(data, info)
  329. d.data[k] = data
  330. }
  331. d.lock.Unlock()
  332. }
  333. return
  334. }
  335. func (h *historymap) checkHistory(info *Info) (b bool, source *Info, reasons string) {
  336. reason:=""
  337. keys := []string{}
  338. h.lock.Lock()
  339. for k, _ := range h.keys { //不同时间段
  340. keys = append(keys, fmt.Sprintf("%s_%s_%s", k, info.subtype, info.area))
  341. if info.area != "全国" { //这个后续可以不要
  342. keys = append(keys, fmt.Sprintf("%s_%s_%s", k, info.subtype, "全国"))
  343. }
  344. }
  345. h.lock.Unlock()
  346. L:
  347. for _, k := range keys {
  348. h.lock.Lock()
  349. data := h.data[k]
  350. h.lock.Unlock()
  351. if len(data) > 0 { //对比v 找到同类型,同省或全国的数据作对比
  352. for _, v := range data {
  353. reason = ""
  354. if v.id == info.id { //正常重复
  355. return false, v, ""
  356. }
  357. if info.subtype == v.subtype {
  358. if info.site != "" {
  359. sitelock.Lock()
  360. dict := SiteMap[info.site]
  361. sitelock.Unlock()
  362. if dict != nil {
  363. if info.area == "全国" && dict["area"] != "" {
  364. info.area = qutil.ObjToString(dict["area"])
  365. info.city = qutil.ObjToString(dict["city"])
  366. } else {
  367. if info.city == "" && dict["city"] != "" {
  368. info.area = qutil.ObjToString(dict["area"])
  369. info.city = qutil.ObjToString(dict["city"])
  370. }
  371. }
  372. }
  373. }
  374. //前置条件1 - 站点相关
  375. if info.site != "" && info.site == v.site {
  376. if info.href != "" && info.href == v.href {
  377. reason = "href相同"
  378. b = true
  379. source = v
  380. reasons = reason
  381. break L
  382. }
  383. if info.href != "" && info.href != v.href {
  384. reason = "href不同-"
  385. }
  386. }
  387. //前置条件2 - 标题相关,有且一个关键词
  388. if ((info.titleSpecialWord && !v.titleSpecialWord) || (info.specialWord && !v.specialWord)) &&
  389. info.title != v.title && v.title != "" && info.title != "" {
  390. continue
  391. }
  392. //前置条件3 - 标题相关,均含有关键词
  393. if ((info.titleSpecialWord && v.titleSpecialWord) || (info.specialWord && v.specialWord)) &&
  394. len([]rune(v.title)) > 10 && len([]rune(info.title)) > 10 && v.title != "" && info.title != "" {
  395. if !(strings.Contains(v.title, info.title) || strings.Contains(info.title, v.title)) {
  396. continue //无包含关系
  397. }
  398. if strings.Contains(v.title, info.title) || strings.Contains(info.title, v.title) {
  399. reason = reason+"标题关键词且包含关系"
  400. //继续二级金额判断
  401. if !againRepeat(v,info){
  402. b = true
  403. source = v
  404. reasons = reason
  405. break
  406. }
  407. }
  408. }
  409. //代理机构相同-非空相等
  410. if v.agency != "" && info.agency != "" && v.agency == info.agency {
  411. reason = reason + "同机构-"
  412. repeat := false
  413. if repeat, reason = quickHeavyMethodTwo(v, info, reason); repeat {
  414. b = true
  415. source = v
  416. reasons = reason
  417. break
  418. }
  419. } else {
  420. reason = reason + "非同机构-"
  421. if info.city != "" && info.city == v.city {
  422. reason = reason + "同城-"
  423. repeat := false
  424. if repeat, reason = quickHeavyMethodTwo(v, info, reason); repeat {
  425. b = true
  426. source = v
  427. reasons = reason
  428. break
  429. }
  430. } else {
  431. reason = reason + "不同城-"
  432. repeat := false
  433. if repeat, reason = quickHeavyMethodOne(v, info, reason); repeat {
  434. b = true
  435. source = v
  436. reasons = reason
  437. break
  438. }
  439. }
  440. }
  441. }
  442. }
  443. }
  444. }
  445. //
  446. if b {
  447. if info.repeatid == source.id {
  448. b = false//重复-无变化-不处理
  449. }
  450. } else {
  451. if source != nil {
  452. if source.repeatid != "" {//未判重-有变化--记录
  453. b = true
  454. reason = "未判重记录"
  455. reasons = reason
  456. }
  457. }
  458. }
  459. //往预存数据 d 添加
  460. if !b {
  461. ct := info.publishtime
  462. dkey := qutil.FormatDateByInt64(&ct, qutil.Date_yyyyMMdd)
  463. k := fmt.Sprintf("%s_%s_%s", dkey, info.subtype, info.area)
  464. data := h.data[k]
  465. if data == nil {
  466. data = []*Info{info}
  467. h.data[k] = data
  468. if !h.keys[dkey] {
  469. h.keys[dkey] = true
  470. //h.update(ct)
  471. }
  472. } else {
  473. data = append(data, info)
  474. h.data[k] = data
  475. }
  476. }
  477. return
  478. }
  479. //替换原始数据池
  480. func (d *datamap) replaceSourceData(replaceData *Info, replaceId string) {
  481. ct := replaceData.publishtime
  482. dkey := qutil.FormatDateByInt64(&ct, qutil.Date_yyyyMMdd)
  483. k := fmt.Sprintf("%s_%s_%s", dkey, replaceData.subtype, replaceData.area)
  484. d.lock.Lock()
  485. data := d.data[k]
  486. if data == nil {
  487. data = []*Info{replaceData}
  488. d.data[k] = data
  489. if !d.keys[dkey] {
  490. d.keys[dkey] = true
  491. }
  492. } else {
  493. //遍历替换
  494. for k, v := range data {
  495. if v.id == replaceId {
  496. data[k] = replaceData
  497. break
  498. }
  499. }
  500. d.data[k] = data
  501. }
  502. d.lock.Unlock()
  503. }
  504. func (h *historymap) replaceSourceData(replaceData *Info, replaceId string) {
  505. ct := replaceData.publishtime
  506. dkey := qutil.FormatDateByInt64(&ct, qutil.Date_yyyyMMdd)
  507. k := fmt.Sprintf("%s_%s_%s", dkey, replaceData.subtype, replaceData.area)
  508. h.lock.Lock()
  509. data := h.data[k]
  510. if data == nil {
  511. data = []*Info{replaceData}
  512. h.data[k] = data
  513. if !h.keys[dkey] {
  514. h.keys[dkey] = true
  515. }
  516. } else {
  517. //遍历替换
  518. for k, v := range data {
  519. if v.id == replaceId {
  520. data[k] = replaceData
  521. break
  522. }
  523. }
  524. h.data[k] = data
  525. }
  526. h.lock.Unlock()
  527. }
  528. func (d *datamap) update(t int64) {
  529. //每天0点清除历史数据
  530. d.keymap = d.GetLatelyFiveDay(t)
  531. m := map[string]bool{}
  532. for _, v := range d.keymap {
  533. m[v] = true
  534. }
  535. all, all1 := 0, 0
  536. for k, v := range d.data {
  537. all += len(v)
  538. if !m[k[:8]] {
  539. delete(d.data, k)
  540. }
  541. }
  542. for k, _ := range d.keys {
  543. if !m[k] {
  544. delete(d.keys, k)
  545. }
  546. }
  547. for _, v := range d.data {
  548. all1 += len(v)
  549. }
  550. //log.Println("更新前后数据:", all, all1)
  551. }
  552. func (d *datamap) GetLatelyFiveDay(t int64) []string {
  553. array := make([]string, d.days)
  554. now := time.Unix(t, 0)
  555. for i := 0; i < d.days; i++ {
  556. array[i] = now.Format(qutil.Date_yyyyMMdd)
  557. now = now.AddDate(0, 0, -1)
  558. }
  559. return array
  560. }
  561. /*
  562. **************************
  563. ******* 以下为判重 ********
  564. **************************
  565. */
  566. //判重方法1
  567. func quickHeavyMethodOne(v *Info, info *Info, reason string) (bool, string) {
  568. isMeet:=false
  569. if info.subtype == "招标" || info.subtype == "邀标" || info.subtype == "询价" ||
  570. info.subtype == "竞谈" || info.subtype == "单一" || info.subtype == "竞价" ||
  571. info.subtype == "变更" || info.subtype == "其他" {
  572. //招标结果
  573. if isMeet, reason = tenderRepeat_A(v, info, reason); isMeet {
  574. if tenderRepeat_C(v, info) {
  575. return false, reason
  576. } else {
  577. reason = reason + "---招标类"
  578. return true, reason
  579. }
  580. } else {
  581. return false, reason
  582. }
  583. } else if info.subtype == "中标" || info.subtype == "成交" || info.subtype == "废标" || info.subtype == "流标" {
  584. //中标结果
  585. if isMeet, reason = winningRepeat_A(v, info, reason);isMeet {
  586. if winningRepeat_C(v, info) {
  587. return false, reason
  588. } else {
  589. reason = reason + "---中标类"
  590. return true, reason
  591. }
  592. } else {
  593. return false, reason
  594. }
  595. } else if info.subtype == "合同" || info.subtype == "验收" || info.subtype == "违规" {
  596. //合同
  597. if isMeet, reason = contractRepeat_A(v, info, reason);isMeet {
  598. if contractRepeat_C(v, info) {
  599. return false, reason
  600. } else {
  601. reason = reason + "---合同类"
  602. return true, reason
  603. }
  604. } else {
  605. return false, reason
  606. }
  607. } else {
  608. //招标结果
  609. if isMeet, reason = tenderRepeat_A(v, info, reason);isMeet {
  610. if tenderRepeat_C(v, info) {
  611. return false, reason
  612. } else {
  613. reason = reason + "---类别空-招标类"
  614. return true, reason
  615. }
  616. } else {
  617. return false, reason
  618. }
  619. }
  620. return false, reason
  621. }
  622. //判重方法2
  623. func quickHeavyMethodTwo(v *Info, info *Info, reason string) (bool, string) {
  624. isMeet:=false
  625. if v.agency == info.agency && v.agency != "" && info.agency != "" {
  626. if info.subtype == "招标" || info.subtype == "邀标" || info.subtype == "询价" ||
  627. info.subtype == "竞谈" || info.subtype == "单一" || info.subtype == "竞价" ||
  628. info.subtype == "变更" || info.subtype == "其他" {
  629. //招标结果
  630. if isMeet, reason = tenderRepeat_B(v, info, reason);isMeet {
  631. if tenderRepeat_C(v, info) { //有不同
  632. return false, reason
  633. } else {
  634. reason = reason + "---招标类"
  635. return true, reason
  636. }
  637. } else {
  638. return false, reason
  639. }
  640. } else if info.subtype == "中标" || info.subtype == "成交" || info.subtype == "废标" || info.subtype == "流标" {
  641. //中标结果
  642. if isMeet, reason = winningRepeat_B(v, info, reason);isMeet {
  643. if winningRepeat_C(v, info) { //有不同
  644. return false, reason
  645. } else {
  646. reason = reason + "---中标类"
  647. return true, reason
  648. }
  649. } else {
  650. return false, reason
  651. }
  652. } else if info.subtype == "合同" || info.subtype == "验收" || info.subtype == "违规" {
  653. //合同
  654. if isMeet, reason = contractRepeat_B(v, info, reason);isMeet {
  655. if contractRepeat_C(v, info) { //有不同
  656. return false, reason
  657. } else {
  658. reason = reason + "---合同类"
  659. return true, reason
  660. }
  661. } else {
  662. return false, reason
  663. }
  664. } else {
  665. //招标结果
  666. if isMeet, reason = tenderRepeat_B(v, info, reason);isMeet {
  667. if tenderRepeat_C(v, info) { //有不同
  668. return false, reason
  669. } else {
  670. reason = reason + "---类别空-招标类"
  671. return true, reason
  672. }
  673. } else {
  674. return false, reason
  675. }
  676. }
  677. }
  678. //不同
  679. if v.agency != info.agency && v.agency != "" && info.agency != "" {
  680. return false, reason
  681. }
  682. //机构最少一个为空
  683. if v.agency == "" || info.agency == "" {
  684. var repeat = false
  685. if repeat, reason = quickHeavyMethodOne(v, info, reason); repeat {
  686. reason = reason + "---机构最少一个空"
  687. return true, reason
  688. } else {
  689. return false, reason
  690. }
  691. }
  692. return false, reason
  693. }
  694. //招标_A
  695. func tenderRepeat_A(v *Info, info *Info, reason string) (bool ,string) {
  696. var ss string
  697. p1, p2, p3, p4, p9, p10, p11 := false, false, false, false, false, false, false
  698. if v.projectname != "" && v.projectname == info.projectname {
  699. ss = ss + "p1(名称)-"
  700. p1 = true
  701. }
  702. if v.buyer != "" && v.buyer == info.buyer {
  703. ss = ss + "p2(单位)-"
  704. p2 = true
  705. }
  706. if (v.projectcode != "" && v.projectcode == info.projectcode && len(v.projectcode)>=5)||
  707. (v.contractnumber != "" && v.contractnumber == info.contractnumber && len(v.contractnumber)>=5){
  708. ss = ss + "p3(编号组)-"
  709. p3 = true
  710. }
  711. if v.budget != 0 && v.budget == info.budget {
  712. ss = ss + "p4(预算)-"
  713. p4 = true
  714. }
  715. if v.bidopentime != 0 && v.bidopentime == info.bidopentime {
  716. ss = ss + "p9(开标时间)-"
  717. p9 = true
  718. }
  719. if v.agencyaddr != "" && v.agencyaddr == info.agencyaddr {
  720. ss = ss + "p10(开标地点)-"
  721. p10 = true
  722. }
  723. if len([]rune(v.title)) > 10 && len([]rune(info.title)) > 10 &&
  724. (strings.Contains(v.title, info.title) || strings.Contains(info.title, v.title)) {
  725. ss = ss + "p11(标题)-"
  726. p11 = true
  727. }
  728. if (p1 && p2 && p3) || (p1 && p2 && p4) || (p1 && p2 && p9) ||
  729. (p1 && p2 && p10) || (p1 && p2 && p11) || (p1 && p3 && p9) || (p1 && p3 && p10) ||
  730. (p1 && p4 && p9) || (p1 && p4 && p10) || (p2 && p3 && p4) ||
  731. (p2 && p3 && p9) || (p2 && p3 && p10) || (p2 && p3 && p11) ||
  732. (p2 && p4 && p9) || (p2 && p4 && p10) || (p2 && p4 && p11) ||
  733. (p3 && p4 && p9) || (p3 && p4 && p10) || (p3 && p4 && p11) ||
  734. (p4 && p9 && p10) || (p4 && p9 && p11) || (p9 && p10 && p11) {
  735. reason = reason + "满足招标A,3要素组合-" + ss + ","
  736. return true,reason
  737. }
  738. return false,reason
  739. }
  740. //招标_B
  741. func tenderRepeat_B(v *Info, info *Info, reason string) (bool,string) {
  742. m, n := 0, 0
  743. if v.projectname != "" && v.projectname == info.projectname {
  744. m++
  745. n++
  746. }
  747. if v.buyer != "" && v.buyer == info.buyer {
  748. m++
  749. }
  750. if (v.projectcode != "" && v.projectcode == info.projectcode && len(v.projectcode)>=5)||
  751. (v.contractnumber != "" && v.contractnumber == info.contractnumber && len(v.contractnumber)>=5){
  752. m++
  753. }
  754. if v.budget != 0 && v.budget == info.budget {
  755. m++
  756. }
  757. if v.bidopentime != 0 && v.bidopentime == info.bidopentime {
  758. m++
  759. }
  760. if v.agencyaddr != "" && v.agencyaddr == info.agencyaddr {
  761. m++
  762. }
  763. if len([]rune(v.title)) > 10 && len([]rune(info.title)) > 10 &&
  764. (strings.Contains(v.title, info.title) || strings.Contains(info.title, v.title)) {
  765. m++
  766. n++
  767. }
  768. if m >= 2 {
  769. if n == 2 && m == 2 {
  770. return false,reason
  771. } else {
  772. reason = reason + "满足招标B,七选二,"
  773. return true,reason
  774. }
  775. }
  776. return false,reason
  777. }
  778. //招标_C
  779. func tenderRepeat_C(v *Info, info *Info) bool {
  780. if v.budget != 0 && info.budget != 0 && v.budget != info.budget {
  781. return true
  782. }
  783. //原始地址...
  784. if v.bidopentime != 0 && info.bidopentime != 0 && v.bidopentime != info.bidopentime {
  785. return true
  786. }
  787. if v.agencyaddr != "" && info.agencyaddr != "" && v.agencyaddr != info.agencyaddr {
  788. return true
  789. }
  790. return false
  791. }
  792. //中标_A
  793. func winningRepeat_A(v *Info, info *Info, reason string) (bool,string) {
  794. var ss string
  795. p1, p2, p3, p5, p6, p11 := false, false, false, false, false, false
  796. if v.projectname != "" && v.projectname == info.projectname {
  797. ss = ss + "p1(项目名称)-"
  798. p1 = true
  799. }
  800. if v.buyer != "" && v.buyer == info.buyer {
  801. ss = ss + "p2(单位)-"
  802. p2 = true
  803. }
  804. if (v.projectcode != "" && v.projectcode == info.projectcode && len(v.projectcode)>=5)||
  805. (v.contractnumber != "" && v.contractnumber == info.contractnumber && len(v.contractnumber)>=5){
  806. ss = ss + "p3(编号组)-"
  807. p3 = true
  808. }
  809. if v.bidamount != 0 && v.bidamount == info.bidamount {
  810. ss = ss + "p5(中标金)-"
  811. p5 = true
  812. }
  813. if v.winner != "" && v.winner == info.winner {
  814. ss = ss + "p6(中标人)-"
  815. p6 = true
  816. }
  817. if len([]rune(v.title)) > 10 && len([]rune(info.title)) > 10 &&
  818. (strings.Contains(v.title, info.title) || strings.Contains(info.title, v.title)) {
  819. ss = ss + "p11(标题)-"
  820. p11 = true
  821. }
  822. if (p1 && p2 && p3) || (p1 && p2 && p5) || (p1 && p2 && p6) ||
  823. (p1 && p3 && p5) || (p1 && p3 && p6) || (p1 && p5 && p6) ||
  824. (p2 && p3 && p5) || (p2 && p3 && p6) || (p2 && p3 && p11) ||
  825. (p2 && p5 && p6) || (p2 && p5 && p11) || (p2 && p6 && p11) ||
  826. (p3 && p5 && p6) || (p3 && p5 && p11) || (p3 && p6 && p11) ||
  827. (p5 && p6 && p11) {
  828. reason = reason + "满足中标A,3要素组合-" + ss + ","
  829. return true,reason
  830. }
  831. return false,reason
  832. }
  833. //中标_B
  834. func winningRepeat_B(v *Info, info *Info, reason string) (bool,string) {
  835. m, n := 0, 0
  836. if v.projectname != "" && v.projectname == info.projectname {
  837. m++
  838. n++
  839. }
  840. if v.buyer != "" && v.buyer == info.buyer {
  841. m++
  842. }
  843. if (v.projectcode != "" && v.projectcode == info.projectcode && len(v.projectcode)>=5)||
  844. (v.contractnumber != "" && v.contractnumber == info.contractnumber && len(v.contractnumber)>=5){
  845. m++
  846. }
  847. if v.bidamount != 0 && v.bidamount == info.bidamount {
  848. m++
  849. }
  850. if v.winner != "" && v.winner == info.winner {
  851. m++
  852. }
  853. if len([]rune(v.title)) > 10 && len([]rune(info.title)) > 10 &&
  854. (strings.Contains(v.title, info.title) || strings.Contains(info.title, v.title)) {
  855. m++
  856. n++
  857. }
  858. if m >= 2 {
  859. if n == 2 && m == 2 {
  860. return false,reason
  861. } else {
  862. reason = reason + "满足中标B.六选二,"
  863. return true,reason
  864. }
  865. }
  866. return false,reason
  867. }
  868. //中标_C
  869. func winningRepeat_C(v *Info, info *Info) bool {
  870. if v.bidamount != 0 && info.bidamount != 0 && v.bidamount != info.bidamount {
  871. return true
  872. }
  873. if v.winner != "" && info.winner != "" && v.winner != info.winner {
  874. return true
  875. }
  876. //原始地址...
  877. return false
  878. }
  879. //合同_A
  880. func contractRepeat_A(v *Info, info *Info, reason string) (bool,string) {
  881. isMeet_1 := false
  882. if isMeet_1, reason = tenderRepeat_A(v, info, reason);isMeet_1 {
  883. return true,reason
  884. }
  885. isMeet_2 := false
  886. if isMeet_2, reason = winningRepeat_A(v, info, reason);isMeet_2 {
  887. return true,reason
  888. }
  889. return false,reason
  890. }
  891. //合同_B
  892. func contractRepeat_B(v *Info, info *Info, reason string) (bool,string) {
  893. isMeet_1 := false
  894. if isMeet_1, reason = tenderRepeat_B(v, info, reason);isMeet_1 {
  895. return true,reason
  896. }
  897. isMeet_2 := false
  898. if isMeet_2, reason = winningRepeat_B(v, info, reason);isMeet_2 {
  899. return true,reason
  900. }
  901. return false,reason
  902. }
  903. //合同_C
  904. func contractRepeat_C(v *Info, info *Info) bool {
  905. if tenderRepeat_C(v, info) {
  906. return true
  907. }
  908. if winningRepeat_C(v, info) {
  909. return true
  910. }
  911. return false
  912. }
  913. func againRepeat(v *Info ,info *Info) bool {
  914. //相同采购单位下
  915. if info.buyer != "" &&v.buyer == info.buyer {
  916. if info.subtype=="招标"||info.subtype=="邀标"||info.subtype=="询价"||
  917. info.subtype=="竞谈"||info.subtype=="单一"||info.subtype=="竞价"||
  918. info.subtype=="其他"||info.subtype=="变更" {
  919. //预算金额满足条件
  920. if v.budget!=info.budget&&v.budget!=0&&info.budget!=0 {
  921. return true
  922. }
  923. }else if info.subtype=="中标"||info.subtype=="成交"||info.subtype=="废标"||
  924. info.subtype=="流标"||info.subtype=="合同"||info.subtype=="验收"||
  925. info.subtype=="违规"{
  926. //中标金额单位满足条件
  927. if (v.bidamount!=info.bidamount&&v.bidamount!=0&&info.bidamount!=0)||
  928. (v.winner!=info.winner&&v.winner!=""&&info.winner!=""){
  929. return true
  930. }
  931. }else {
  932. }
  933. }
  934. return false
  935. }