merge.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. package main
  2. import (
  3. "encoding/json"
  4. "log"
  5. "math"
  6. qu "qfw/util"
  7. "qfw/util/redis"
  8. "sort"
  9. //"strconv"
  10. "strings"
  11. "sync"
  12. )
  13. //单线程控制查找
  14. var findLock = sync.Mutex{}
  15. //从对应map中获取对比的项目id
  16. func getCompareIds(pn, pc, ptc, pb string) (bpn, bpc, bptc, bpb int, res []*Key, idArr []string, IDArr []*ID) {
  17. findLock.Lock()
  18. defer findLock.Unlock()
  19. res = []*Key{}
  20. //是否查找到,并标识位置。-1代表未查找到。
  21. bpn, bpc, bptc, bpb = -1, -1, -1, -1
  22. if pn != "" {
  23. ids := mapPn[pn]
  24. if ids == nil {
  25. ids = &Key{Arr: []string{}}
  26. mapPn[pn] = ids
  27. bpn = 0
  28. }
  29. ids.Lock.Lock()
  30. res = append(res, ids)
  31. }
  32. if pc != "" {
  33. ids := mapPc[pc]
  34. if ids == nil {
  35. ids = &Key{Arr: []string{}}
  36. mapPc[pc] = ids
  37. bpc = len(res)
  38. }
  39. ids.Lock.Lock()
  40. res = append(res, ids)
  41. }
  42. if ptc != "" {
  43. ids := mapPc[ptc]
  44. if ids == nil {
  45. ids = &Key{Arr: []string{}}
  46. mapPc[ptc] = ids
  47. bptc = len(res)
  48. }
  49. ids.Lock.Lock()
  50. res = append(res, ids)
  51. }
  52. if pb != "" {
  53. ids := mapPb[pb]
  54. if ids == nil {
  55. ids = &Key{Arr: []string{}}
  56. mapPb[pb] = ids
  57. bpb = len(res)
  58. }
  59. ids.Lock.Lock()
  60. res = append(res, ids)
  61. }
  62. repeatId := map[string]bool{}
  63. idArr = []string{} //项目id
  64. IDArr = []*ID{} //项目信息
  65. for _, m := range res {
  66. for _, id := range m.Arr {
  67. if !repeatId[id] {
  68. repeatId[id] = true
  69. //_, _ = strconv.ParseInt(id[0:8], 16, 64)
  70. AllIdsMapLock.Lock()
  71. Id := AllIdsMap2[id]
  72. AllIdsMapLock.Unlock()
  73. Id.Lock.Lock()
  74. idArr = append(idArr, id)
  75. IDArr = append(IDArr, Id)
  76. }
  77. }
  78. }
  79. return
  80. }
  81. //项目合并入口
  82. func startProjectMerge(info *Info, tmp map[string]interface{}) {
  83. //只有或没有采购单位的无法合并
  84. //bpn, bpc, bptc, bpb 是否查找到,并标识位置。-1代表未查找到。
  85. //pids 是项目id数组集合
  86. //IDArr,是单个项目ID对象集合
  87. bpn, bpc, bptc, bpb, pids, idArr, IDArr := getCompareIds(info.ProjectName, info.ProjectCode, info.PTC, info.Buyer)
  88. //map--k为pn,ptn,pc,ptc,buyer值 v为Id数组和lock
  89. for _, m := range pids {
  90. defer m.Lock.Unlock()
  91. }
  92. for _, id := range IDArr {
  93. defer id.Lock.Unlock()
  94. }
  95. bFindProject := false
  96. findPid := ""
  97. //获取完id,进行计算
  98. if len(idArr) > 0 && len(idArr) == len(IDArr) {
  99. res := redis.Mget(ProjectCache, idArr)
  100. //定义两组
  101. comRes1 := []*ProjectInfo{} //优先级最高的对比结果数组
  102. comRes2 := []*ProjectInfo{} //优化级其次
  103. comRes3 := []*ProjectInfo{}
  104. if len(res) == len(idArr) {
  105. for _, v := range res {
  106. var cp ProjectInfo
  107. comStr := ""
  108. var compareProject *ProjectInfo
  109. err := json.Unmarshal(v.([]byte), &cp)
  110. compareProject = &cp
  111. //问题出地LastTime!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  112. diffTime := math.Abs(float64(info.Publishtime - compareProject.LastTime))
  113. if err != nil {
  114. log.Println("从redis取id信息出错!!!", err)
  115. } else if diffTime < 360*86400 {
  116. //"A 相等 B 被包含 C 不相等 D不存在 E被包含
  117. compareStr, score := comparePNCB(info, compareProject)
  118. //if info.ProjectCode == "ZWJLZXQ-2016-0508" {
  119. //log.Println(compareStr)
  120. //}
  121. resVal := Select(compareStr, info, compareProject)
  122. //---------------------------------------
  123. if resVal > 0 {
  124. compareBuyer := "D"
  125. if info.Buyer != "" {
  126. if info.Buyer == compareProject.Buyer {
  127. compareBuyer = "A"
  128. score += 3
  129. } else if compareProject.Buyer != "" {
  130. if strings.Contains(info.Buyer, compareProject.Buyer) || strings.Contains(compareProject.Buyer, info.Buyer) {
  131. compareBuyer = "B"
  132. score += 1
  133. } else {
  134. compareBuyer = "C"
  135. }
  136. }
  137. }
  138. //---------------------------------------
  139. compareCity := ""
  140. if info.Area != "全国" && info.Area != "" && info.Area == compareProject.Area {
  141. compareCity += "A"
  142. score += 2
  143. } else if info.Area == "全国" || compareProject.Area == "全国" {
  144. compareCity += "B"
  145. score += 1
  146. } else {
  147. compareCity += "C"
  148. }
  149. if compareCity != "C" {
  150. if info.City != "" && info.City == compareProject.City {
  151. compareCity += "A"
  152. score += 2
  153. } else {
  154. if info.Area == "全国" || compareProject.Area == "全国" {
  155. compareCity += "B"
  156. } else if info.City == compareCity {
  157. compareCity += "B"
  158. } else {
  159. compareCity += "C"
  160. }
  161. }
  162. } else {
  163. compareCity += "C"
  164. }
  165. compareTime := "D"
  166. //diffTime := math.Abs(float64(info.Publishtime - compareProject.Publistime[len(compareProject.Publistime)-1]))
  167. if diffTime < 45*86400 {
  168. compareTime = "A"
  169. score += 2
  170. } else if diffTime < 90*86400 {
  171. compareTime = "B"
  172. score += 1
  173. }
  174. score2 := 0
  175. compareAgency := "D"
  176. if info.Agency != "" {
  177. if info.Agency == compareProject.Agency {
  178. compareAgency = "A"
  179. score += 2
  180. score2 += 1
  181. } else if compareProject.Agency != "" {
  182. if strings.Contains(info.Agency, compareProject.Agency) || strings.Contains(compareProject.Agency, info.Agency) {
  183. compareAgency = "B"
  184. score += 1
  185. score2 += 1
  186. } else {
  187. compareAgency = "C"
  188. }
  189. }
  190. }
  191. compareBudget := "C"
  192. if info.budget > 0 && (info.budget == compareProject.Budget || (compareProject.Bidamount > 0 && info.budget > compareProject.Bidamount && (info.budget-compareProject.Bidamount) < (0.1*info.budget))) {
  193. compareBudget = "A"
  194. score += 1
  195. score2 += 1
  196. }
  197. compareBidmount := "C"
  198. if info.bidamount > 0 && (info.bidamount == compareProject.Bidamount || (compareProject.Budget > 0 && compareProject.Budget > info.bidamount && (compareProject.Budget-info.bidamount) < 0.1*compareProject.Budget)) {
  199. compareBidmount = "A"
  200. score += 1
  201. score2 += 1
  202. }
  203. //项目名称、项目编号、标题项目编号、采购单位、省、市、发布时间、代理机构
  204. comStr = compareStr + compareBuyer + compareCity + compareTime + compareAgency + compareBudget + compareBidmount
  205. compareProject.comStr = comStr
  206. eqV := 0
  207. switch resVal {
  208. case 3:
  209. if compareBuyer < "C" {
  210. eqV = 1
  211. } else if compareBuyer == "D" {
  212. if "AA" == compareCity && compareAgency != "C" && compareTime != "D" && score2 > 0 {
  213. eqV = 2
  214. } else if compareCity[1:1] != "C" && score2 > 0 && compareTime == "A" {
  215. eqV = 3
  216. } else if compareTime != "D" && compareAgency != "C" && score2 > 1 {
  217. eqV = 3
  218. }
  219. } else {
  220. if "AA" == compareCity && compareAgency != "C" && compareTime != "D" {
  221. eqV = 2
  222. } else if compareCity[1:1] != "C" && compareTime == "A" && score2 > 1 {
  223. eqV = 3
  224. }
  225. }
  226. case 2:
  227. if compareBuyer < "C" {
  228. if compareTime != "D" && "AA" == compareCity && score2 > 0 {
  229. eqV = 2
  230. } else if compareCity[1:1] != "C" && compareTime == "A" && score2 > 0 {
  231. eqV = 3
  232. }
  233. } else if compareBuyer == "D" {
  234. if "AA" == compareCity && compareTime != "D" && score2 > 1 {
  235. eqV = 3
  236. } else if score2 > 2 && compareTime == "A" {
  237. eqV = 3
  238. }
  239. } else {
  240. if "AA" == compareCity && (compareAgency == "A" || score2 > 1) && compareTime == "A" {
  241. eqV = 3
  242. }
  243. }
  244. case 1:
  245. if compareBuyer < "C" {
  246. if compareTime != "D" && "AA" == compareCity && score2 > 1 {
  247. eqV = 2
  248. } else if compareCity[1:1] != "C" && compareTime == "A" && score2 > 1 {
  249. eqV = 3
  250. }
  251. } else if compareBuyer == "D" {
  252. if "AA" == compareCity && compareTime != "D" && score2 > 2 {
  253. eqV = 3
  254. } else if compareCity[1:1] != "C" && score2 > 2 && compareTime == "A" {
  255. eqV = 3
  256. }
  257. } else {
  258. if "AA" == compareCity && score2 > 2 && compareTime == "A" {
  259. eqV = 3
  260. }
  261. }
  262. }
  263. if eqV == 1 {
  264. comRes1 = append(comRes1, compareProject)
  265. } else if eqV == 2 {
  266. comRes2 = append(comRes2, compareProject)
  267. } else if eqV == 3 {
  268. comRes3 = append(comRes3, compareProject)
  269. } else {
  270. log.Println("+++++++++++", resVal, comStr, info, compareProject)
  271. }
  272. }
  273. }
  274. }
  275. //--------------------------------对比完成-----------------------
  276. //更新数组、更新项目
  277. for kv, resN := range [][]*ProjectInfo{comRes1, comRes2, comRes3} {
  278. if len(resN) > 0 {
  279. if len(resN) > 1 {
  280. sort.Slice(resN, func(i, j int) bool {
  281. return resN[i].score > resN[j].score
  282. })
  283. }
  284. bFindProject = true
  285. findPid = resN[0].Id.Hex()
  286. for k2, bv := range []int{bpn, bpc, bptc, bpb} {
  287. if bv > -1 {
  288. pids[bv].Arr = append(pids[bv].Arr, findPid)
  289. if k2 == 0 {
  290. if resN[0].ProjectName == "" {
  291. resN[0].ProjectName = info.ProjectName
  292. } else {
  293. if resN[0].MPN == nil {
  294. resN[0].MPN = []string{info.ProjectName}
  295. } else {
  296. resN[0].MPN = append(resN[0].MPN, info.ProjectName)
  297. }
  298. }
  299. } else if k2 < 3 {
  300. if resN[0].ProjectCode == "" {
  301. resN[0].ProjectCode = qu.If(k2 == 1, info.ProjectCode, info.PTC).(string)
  302. } else {
  303. if resN[0].MPC == nil {
  304. resN[0].MPC = []string{qu.If(k2 == 1, info.ProjectCode, info.PTC).(string)}
  305. } else {
  306. resN[0].MPC = append(resN[0].MPC, qu.If(k2 == 1, info.ProjectCode, info.PTC).(string))
  307. }
  308. }
  309. } else {
  310. if resN[0].Buyer == "" {
  311. resN[0].Buyer = info.Buyer
  312. }
  313. }
  314. }
  315. }
  316. UpdateProject(tmp, info, resN[0], kv+1, resN[0].comStr)
  317. //更新AllIdsMao中的时间
  318. redis.Put(ProjectCache, findPid, resN[0], 0)
  319. break
  320. }
  321. }
  322. } else {
  323. log.Println("redis记录缺失!!!")
  324. }
  325. }
  326. if !bFindProject {
  327. //没有找到
  328. id := NewProject(tmp, info)
  329. //_, _ = strconv.ParseInt(id[0:8], 16, 64)
  330. AllIdsMapLock.Lock()
  331. //AllIdsMap[int(t)%idsMapSize][id] = &ID{Id: id, lastTime: info.Publishtime}
  332. AllIdsMap2[id] = &ID{Id: id, lastTime: info.Publishtime}
  333. AllIdsMapLock.Unlock()
  334. for _, m := range pids {
  335. m.Arr = append(m.Arr, id)
  336. }
  337. }
  338. }
  339. //二分字符串查找
  340. func BinarySearch(s []string, k string) int {
  341. sort.Strings(s)
  342. lo, hi := 0, len(s)-1
  343. for lo <= hi {
  344. m := (lo + hi) >> 1
  345. if s[m] < k {
  346. lo = m + 1
  347. } else if s[m] > k {
  348. hi = m - 1
  349. } else {
  350. return m
  351. }
  352. }
  353. return -1
  354. }
  355. var FIELDS = []string{"area", "city", "district", "projectname", "projectcode", "buyer", "winner", "budget", "bidamount", "bidstatus", "agency", "projectscope"}