datamap.go 35 KB

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