datamap.go 28 KB

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