|
@@ -0,0 +1,784 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ du "jy/util"
|
|
|
+ "log"
|
|
|
+ "math"
|
|
|
+ "qfw/util"
|
|
|
+ "qfw/util/redis"
|
|
|
+ "regexp"
|
|
|
+ "sort"
|
|
|
+ "strings"
|
|
|
+ "sync"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "gopkg.in/mgo.v2/bson"
|
|
|
+)
|
|
|
+
|
|
|
+/**
|
|
|
+发布时间(结合信息类型-->)
|
|
|
+信息类型(拟建、招标(变更)、结果(成交、中标、流标、废标、变更)、其他(合同、验收、违规、变更))
|
|
|
+项目代码(长度)
|
|
|
+采购单位(结合省份)
|
|
|
+招标机构
|
|
|
+所属省份
|
|
|
+信息标题(含有二次、标段、包的情况,结合分包情况处理)
|
|
|
+是否分包:
|
|
|
+**/
|
|
|
+type ProjectInfo struct {
|
|
|
+ Id string `json:"id"`
|
|
|
+ Publistime []int64 `json:"publistime"` //多条信息的发布时间、跨度
|
|
|
+ InfoType [][]string `json:"infotype"` //多条信息内的 toptype、subtype
|
|
|
+ Ids []string `json:"ids"`
|
|
|
+ Topscopeclass []string `json:"topscopeclass"`
|
|
|
+ Subscopeclass []string `json:"subscopeclass"`
|
|
|
+ Winners []string `json:"winners"`
|
|
|
+ ProjectName string `json:"projectname"`
|
|
|
+ ProjectCode string `json:"projectcode"` //项目代码唯一(纯数字的权重低)
|
|
|
+ Buyer string `json:"buyer"` //采购单位唯一
|
|
|
+ Buyerperson string `json:"buyerperson"`
|
|
|
+ Buyertel string `json:"buyertel"`
|
|
|
+ Agency string `json:"agency"` //代理机构唯一
|
|
|
+ Area string `json:"area"` //地区唯一
|
|
|
+ HasPackage bool `json:"haspackage"` //是否有分包
|
|
|
+ Package map[string]interface{} `json:"package"` //分包的对比对象
|
|
|
+
|
|
|
+ Buyerclass string `json:"buyerclass"` //采购单位分类
|
|
|
+ Bidopentime int64 `json:"bidopentime"` //开标时间
|
|
|
+ District string `json:"district"` //区县
|
|
|
+ Winnerorder []string //中标候选人
|
|
|
+}
|
|
|
+
|
|
|
+//抽取信息映射实体类
|
|
|
+type Info struct {
|
|
|
+ Id string `json:"_id"`
|
|
|
+ Href string `json:"href"`
|
|
|
+ Publishtime int64 `json:"publishtime"`
|
|
|
+ Title string `json:"title"`
|
|
|
+ TopType string `json:"toptype"`
|
|
|
+ SubType string `json:"subtype"`
|
|
|
+ ProjectName string `json:"projectname"`
|
|
|
+ ProjectCode string `json:"projectcode"`
|
|
|
+ Buyer string `json:"buyer"`
|
|
|
+ Buyerperson string `json:"buyerperson"`
|
|
|
+ Buyertel string `json:"buyertel"`
|
|
|
+ Agency string `json:"agency"`
|
|
|
+ Area string `json:"area"`
|
|
|
+ HasPackage bool `json:"haspackage"`
|
|
|
+ Package map[string]interface{} `json:"package"`
|
|
|
+ PNum string `json:"pnum"`
|
|
|
+ Topscopeclass []string `json:"topscopeclass"`
|
|
|
+ Subscopeclass []string `json:"subscopeclass"`
|
|
|
+ Winners []string
|
|
|
+ dealtype int
|
|
|
+
|
|
|
+ Buyerclass string `json:"buyerclass"`
|
|
|
+ Bidopentime int64 `json:"bidopentime"`
|
|
|
+ District string `json:"district"`
|
|
|
+ Winnerorder []string
|
|
|
+}
|
|
|
+
|
|
|
+type CompareOne struct {
|
|
|
+ ProjectNameType int //项目名称对比结果分类 0未比较 1相等 2包含 3不相等
|
|
|
+ ProjectCodeType int //0未比较 1相等 2包含 3不相等
|
|
|
+ AreaType int //0未比较 1相等 2不相等
|
|
|
+ PublistimeType int //1在时间范围 2不在
|
|
|
+ BuyerType int //0未比较 1相等 2包含 3不相等
|
|
|
+ AgencyType int //0未比较 1相等 2包含 3不相等
|
|
|
+ PackageType int //1都是多包 2都不是多包 3招标 4新信息是结果
|
|
|
+ Score int
|
|
|
+ Parent *CompareInfo
|
|
|
+ Pinfo *ProjectInfo
|
|
|
+ Pos int
|
|
|
+}
|
|
|
+
|
|
|
+type CompareInfo struct {
|
|
|
+ Field string //对比属性 pn/pc/pb
|
|
|
+ Key string //存放rediskey
|
|
|
+ //Pinfo []ProjectInfo //存放redis对象
|
|
|
+ Scores []*CompareOne //对比分值 pinfo索引对应分值
|
|
|
+ Bfind bool //是否查找到
|
|
|
+ IdArr []string
|
|
|
+ K *Key
|
|
|
+ KeyMap *KeyMap
|
|
|
+}
|
|
|
+
|
|
|
+func NewCompareInfo(field, key string, KeyMap *KeyMap) *CompareInfo {
|
|
|
+ return &CompareInfo{
|
|
|
+ Field: field,
|
|
|
+ Key: key,
|
|
|
+ Scores: []*CompareOne{},
|
|
|
+ KeyMap: KeyMap,
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+var numreg2 = regexp.MustCompile("^[0-9]+$")
|
|
|
+var TitleReg = regexp.MustCompile("([一二三四五六七八九十0-9A-Za-zⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ、\\-~至]+(子|合同|分|施工|监理|标)?[包标段][号段]?[、]?)+|((子|合同|分|施工|监理|标)?[包标段][号段]?[一二三四五六七八九十0-9A-Za-zⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ、\\-~至]+[、]?)+|(子|合同|分|施工|监理|标)?[包标段][号段]?[a-zA-Z0-9]+[\\-~-至、](子|合同|分|施工|监理|标)?[包标段][号段]?[a-zA-Z0-9]+")
|
|
|
+
|
|
|
+//对比打分程序
|
|
|
+func Compare(tmp map[string]interface{} /*新信息*/, pici int64) (sflag string) {
|
|
|
+ defer util.Catch()
|
|
|
+ /***********信息预处理开始***********/
|
|
|
+ //信息由map转换成Info对象
|
|
|
+ bys, _ := json.Marshal(tmp)
|
|
|
+ var thisinfo *Info
|
|
|
+ json.Unmarshal(bys, &thisinfo)
|
|
|
+ if thisinfo == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if len(thisinfo.Topscopeclass) == 0 {
|
|
|
+ thisinfo.Topscopeclass = []string{}
|
|
|
+ }
|
|
|
+ if len(thisinfo.Subscopeclass) == 0 {
|
|
|
+ thisinfo.Subscopeclass = []string{}
|
|
|
+ }
|
|
|
+ //去重
|
|
|
+ thisinfo.Subscopeclass = RemoveDup(thisinfo.Subscopeclass)
|
|
|
+
|
|
|
+ if len(thisinfo.Package) > 0 { //信息是否分包
|
|
|
+ thisinfo.HasPackage = true
|
|
|
+ } else if thisinfo.TopType == "结果" && TitleReg.MatchString(thisinfo.Title) {
|
|
|
+ //当信息类型是结果时,并且标题中包含分包字样,找到包号,用以后面比较打分
|
|
|
+ res := TitleReg.FindAllStringSubmatch(thisinfo.Title, -1)
|
|
|
+ pnum := du.PackageNumberConvert(res[0][0])
|
|
|
+ du.Debug(pnum, res)
|
|
|
+ thisinfo.PNum = pnum
|
|
|
+ }
|
|
|
+ if thisinfo.SubType == "变更" || strings.Index(thisinfo.Title, "变更公告") > -1 || strings.Index(thisinfo.Title, "更正公告") > -1 {
|
|
|
+ //当信息类型是变更或标题中含变更时
|
|
|
+ if thisinfo.TopType == "招标" {
|
|
|
+ //招标的变更公告过,不作处理
|
|
|
+ du.Debug(thisinfo.Id, thisinfo.Href, thisinfo.ProjectName, thisinfo.ProjectCode)
|
|
|
+ return
|
|
|
+ } else if thisinfo.TopType == "结果" {
|
|
|
+ thisinfo.SubType = "变更"
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //计算中标人
|
|
|
+ winner, _ := tmp["winner"].(string)
|
|
|
+ m1 := map[string]bool{}
|
|
|
+ winners := []string{}
|
|
|
+ if winner != "" {
|
|
|
+ m1[winner] = true
|
|
|
+ winners = append(winners, winner)
|
|
|
+ }
|
|
|
+ if thisinfo.HasPackage {
|
|
|
+ packageM, _ := tmp["package"].(bson.M)
|
|
|
+ for _, p := range packageM {
|
|
|
+ pm, _ := p.(map[string]interface{})
|
|
|
+ pw, _ := pm["winner"].(string)
|
|
|
+ if pw != "" {
|
|
|
+ m1[pw] = true
|
|
|
+ winners = append(winners, pw)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ thisinfo.Winners = winners
|
|
|
+ m1 = nil
|
|
|
+ //中标候选人
|
|
|
+ winnerorder := []string{}
|
|
|
+ if winorders, ok := tmp["winnerorder"].([]interface{}); ok {
|
|
|
+ for _, wins := range winorders {
|
|
|
+ if win, ok := wins.(map[string]interface{}); ok {
|
|
|
+ entname := util.ObjToString(win["entname"])
|
|
|
+ if entname != "" && len([]rune(entname)) > 6 {
|
|
|
+ winnerorder = append(winnerorder, entname)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ thisinfo.Winnerorder = winnerorder
|
|
|
+ /***********信息预处理**结束***********/
|
|
|
+ updateid := ""
|
|
|
+
|
|
|
+ var PN, PC, PB *CompareInfo
|
|
|
+
|
|
|
+ new_pn, _ := handleprojectname(thisinfo.ProjectName, thisinfo.Buyer, thisinfo.TopType) //作为判断依据
|
|
|
+ /***********根据项目名称比对**开始***********/
|
|
|
+ if thisinfo.ProjectName != "" {
|
|
|
+ KEY := "pn_" + new_pn
|
|
|
+ PN = NewCompareInfo("pn", KEY, PNKey)
|
|
|
+ }
|
|
|
+ /***********根据项目名称比对**结束***********/
|
|
|
+
|
|
|
+ /***********根据项目编号比对**开始***********/
|
|
|
+ if len(thisinfo.ProjectCode) > 5 && !numreg.MatchString(thisinfo.ProjectCode) { //大于5且不是纯数字bfind
|
|
|
+ KEY := "pc_" + thisinfo.ProjectCode
|
|
|
+ PC = NewCompareInfo("pc", KEY, PCKey)
|
|
|
+ }
|
|
|
+ /***********根据项目编号比对**结束***********/
|
|
|
+
|
|
|
+ /***********根据采购单位比对**开始***********/
|
|
|
+ if len([]rune(thisinfo.Buyer)) > 4 {
|
|
|
+ KEY := "pb_" + thisinfo.Buyer
|
|
|
+ PB = NewCompareInfo("pb", KEY, PBKey)
|
|
|
+ }
|
|
|
+ //分值排序
|
|
|
+ tmpArr := []*CompareOne{}
|
|
|
+ repeatId := map[string]bool{}
|
|
|
+ IdLock.Lock()
|
|
|
+ //此处加id锁,会引进多线程的死锁,对比三个大map数组,找到key相同的项目id数组,并去重
|
|
|
+ for _, PNCB := range []*CompareInfo{PN, PC, PB} {
|
|
|
+ if PNCB != nil {
|
|
|
+ PNCB.KeyMap.Lock.Lock()
|
|
|
+ K := PNCB.KeyMap.Map[PNCB.Key]
|
|
|
+ if K == nil {
|
|
|
+ K = &Key{&[]string{}, &sync.Mutex{}}
|
|
|
+ PNCB.KeyMap.Map[PNCB.Key] = K
|
|
|
+ }
|
|
|
+ PNCB.K = K
|
|
|
+ PNCB.K.Lock.Lock()
|
|
|
+ PNCB.KeyMap.Lock.Unlock()
|
|
|
+ defer PNCB.K.Lock.Unlock()
|
|
|
+ newarr := []string{}
|
|
|
+ for _, id := range *K.Arr {
|
|
|
+ if !repeatId[id] {
|
|
|
+ newarr = append(newarr, id)
|
|
|
+ repeatId[id] = true
|
|
|
+ idlk := IdLockMap[id]
|
|
|
+ if idlk == nil {
|
|
|
+ idlk = &sync.Mutex{}
|
|
|
+ IdLockMap[id] = idlk
|
|
|
+ }
|
|
|
+ idlk.Lock()
|
|
|
+ defer idlk.Unlock()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ PNCB.IdArr = newarr
|
|
|
+ }
|
|
|
+ }
|
|
|
+ IdLock.Unlock()
|
|
|
+
|
|
|
+ //三个对比对象分别和thisinfo比较,打完分的对象放入scores,合并放入tempArr
|
|
|
+ for _, PNCB := range []*CompareInfo{PN, PC, PB} {
|
|
|
+ if PNCB != nil {
|
|
|
+ if len(PNCB.IdArr) > 0 {
|
|
|
+ PNCB.compute(thisinfo, PNCB.IdArr)
|
|
|
+ tmpArr = append(tmpArr, PNCB.Scores...)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //排序取出最大分值的对象,更新对象
|
|
|
+ if len(tmpArr) > 0 {
|
|
|
+ sort.Slice(tmpArr, func(i, j int) bool {
|
|
|
+ return tmpArr[i].Score > tmpArr[j].Score
|
|
|
+ })
|
|
|
+ max := tmpArr[0]
|
|
|
+ if max.Score > 0 {
|
|
|
+ //获取到对象
|
|
|
+ max.Parent.Bfind = true
|
|
|
+ updateid = updateinfo(thisinfo, tmp, max.Pinfo, pici)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /***********根据采购单位比对**结束***********/
|
|
|
+ if updateid == "" {
|
|
|
+ sflag = "normal"
|
|
|
+ updateid = InsertProject(new_pn, tmp, pici, thisinfo)
|
|
|
+ p1 := NewPinfo(updateid, thisinfo)
|
|
|
+ //PUT = append(PUT, []interface{}{updateid, p1})
|
|
|
+ redis.PutCKV(REDISIDS, updateid, p1)
|
|
|
+ //IdLock.Lock()
|
|
|
+ //IdLockMap[updateid] = &sync.Mutex{}
|
|
|
+ //IdLock.Unlock()
|
|
|
+ } else {
|
|
|
+ sflag = "repeat"
|
|
|
+ }
|
|
|
+ //更新redis中存入的三大map对象中的id
|
|
|
+ if updateid != "" {
|
|
|
+ PUT := []interface{}{}
|
|
|
+ for _, PNCB := range []*CompareInfo{PN, PC, PB} {
|
|
|
+ if PNCB != nil && !PNCB.Bfind {
|
|
|
+ if BinarySearch(*PNCB.K.Arr, updateid) == -1 {
|
|
|
+ *(PNCB.K.Arr) = append(*(PNCB.K.Arr), updateid)
|
|
|
+ PUT = append(PUT, []interface{}{PNCB.Key, *(PNCB.K.Arr)})
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if len(PUT) > 0 {
|
|
|
+ redis.BulkPut(REDISKEYS, 0, PUT...)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+//没有在redis中查找到,新增项目
|
|
|
+func InsertProject(new_pn string, tmp map[string]interface{}, pici int64, thisinfo *Info) string {
|
|
|
+ e := InitEL("")
|
|
|
+ set := map[string]interface{}{
|
|
|
+ "pici": pici,
|
|
|
+ }
|
|
|
+ set["s_projectname"] = new_pn
|
|
|
+ e.fieldpriority(&tmp, nil, &set)
|
|
|
+ set["extractpos"] = e.GetVal()
|
|
|
+ set["createtime"] = time.Now().Unix()
|
|
|
+ set["sourceinfoid"] = util.BsonIdToSId(tmp["_id"])
|
|
|
+ set["sourceinfourl"] = tmp["href"]
|
|
|
+ set["topscopeclass"] = thisinfo.Topscopeclass
|
|
|
+ set["subscopeclass"] = thisinfo.Subscopeclass
|
|
|
+ if thisinfo.Buyerperson != "" {
|
|
|
+ set["buyerperson"] = thisinfo.Buyerperson
|
|
|
+ }
|
|
|
+ if thisinfo.Buyertel != "" {
|
|
|
+ set["buyertel"] = thisinfo.Buyertel
|
|
|
+ }
|
|
|
+ if thisinfo.Buyerclass != "" {
|
|
|
+ set["buyertel"] = thisinfo.Buyerclass
|
|
|
+ }
|
|
|
+ if thisinfo.District != "" {
|
|
|
+ set["district"] = thisinfo.District
|
|
|
+ }
|
|
|
+ if thisinfo.Bidopentime > 0 {
|
|
|
+ set["bidopentime"] = thisinfo.Bidopentime
|
|
|
+ }
|
|
|
+ if len(thisinfo.Winnerorder) > 0 {
|
|
|
+ set["winnerorder"] = thisinfo.Winnerorder
|
|
|
+ }
|
|
|
+ s_subscopeclass := strings.Join(thisinfo.Subscopeclass, ",")
|
|
|
+ // if len(s_subscopeclass) > 0 {
|
|
|
+ // s_subscopeclass = "," + s_subscopeclass + ","
|
|
|
+ // }
|
|
|
+ set["s_subscopeclass"] = s_subscopeclass
|
|
|
+ s_winner := strings.Join(thisinfo.Winners, ",")
|
|
|
+ // if len(s_winner) > 0 {
|
|
|
+ // s_winner = "," + s_winner + ","
|
|
|
+ // }
|
|
|
+ set["s_winner"] = s_winner
|
|
|
+ if tmp["package"] != nil {
|
|
|
+ set["package"] = tmp["package"] //没定义优先级
|
|
|
+ }
|
|
|
+ push := NewPushInfo(tmp)
|
|
|
+ for tkey, _ := range extractpos {
|
|
|
+ if tmp[tkey] != nil {
|
|
|
+ push[tkey] = tmp[tkey]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ set["list"] = []bson.M{
|
|
|
+ push,
|
|
|
+ }
|
|
|
+ return MQFW.Save(projectColl, set)
|
|
|
+}
|
|
|
+
|
|
|
+//生成存放在redis数组中的对象
|
|
|
+func NewPinfo(id string, thisinfo *Info) ProjectInfo {
|
|
|
+ p1 := ProjectInfo{
|
|
|
+ Publistime: []int64{thisinfo.Publishtime},
|
|
|
+ InfoType: [][]string{[]string{thisinfo.TopType, thisinfo.SubType}},
|
|
|
+ Id: id,
|
|
|
+ Ids: []string{thisinfo.Id},
|
|
|
+ Topscopeclass: thisinfo.Topscopeclass,
|
|
|
+ Subscopeclass: thisinfo.Subscopeclass,
|
|
|
+ Winners: thisinfo.Winners,
|
|
|
+ ProjectName: thisinfo.ProjectName,
|
|
|
+ ProjectCode: thisinfo.ProjectCode,
|
|
|
+ Buyer: thisinfo.Buyer,
|
|
|
+ Agency: thisinfo.Agency,
|
|
|
+ Area: thisinfo.Area,
|
|
|
+ HasPackage: thisinfo.HasPackage,
|
|
|
+ Package: map[string]interface{}{},
|
|
|
+ // Buyerclass: thisinfo.Buyerclass,
|
|
|
+ // Bidopentime: thisinfo.Bidopentime,
|
|
|
+ // District: thisinfo.District,
|
|
|
+ Winnerorder: thisinfo.Winnerorder,
|
|
|
+ }
|
|
|
+ for k4, _ := range thisinfo.Package {
|
|
|
+ p1.Package[k4] = ""
|
|
|
+ }
|
|
|
+ return p1
|
|
|
+}
|
|
|
+
|
|
|
+//每一个字段的打分map,获取最高分
|
|
|
+func GetMaxScore(scoremap map[int]int) (find bool, index int) {
|
|
|
+ ks := []int{}
|
|
|
+ vs := []int{}
|
|
|
+ for k, v := range scoremap {
|
|
|
+ mk, mv := -1, -100
|
|
|
+ bf := false
|
|
|
+ for mk, mv = range vs {
|
|
|
+ if mv > v {
|
|
|
+ bf = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if mk == -1 || !bf {
|
|
|
+ vs = append(vs, v)
|
|
|
+ ks = append(ks, k)
|
|
|
+ } else {
|
|
|
+ vs = append(append(vs[:mk], v), vs[mk:]...)
|
|
|
+ ks = append(append(ks[:mk], k), ks[mk:]...)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if len(ks) > 0 {
|
|
|
+ index = ks[len(ks)-1]
|
|
|
+ find = true
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+//往对应redis中更新信息
|
|
|
+func updateinfo(thisinfo *Info, tmp map[string]interface{}, pInfo *ProjectInfo, pici int64) string {
|
|
|
+ updateid := pInfo.Id
|
|
|
+ if BinarySearch(pInfo.Ids, thisinfo.Id) > -1 {
|
|
|
+ return updateid
|
|
|
+ }
|
|
|
+ set := map[string]interface{}{
|
|
|
+ "pici": pici,
|
|
|
+ }
|
|
|
+ res, bres := MQFW.FindById(projectColl, pInfo.Id, `{"list":0}`)
|
|
|
+ EqInfoUpdate(thisinfo, pInfo)
|
|
|
+ if bres && res != nil && *res != nil {
|
|
|
+ set["topscopeclass"] = pInfo.Topscopeclass
|
|
|
+ set["subscopeclass"] = pInfo.Subscopeclass
|
|
|
+ s_subscopeclass := strings.Join(pInfo.Subscopeclass, ",")
|
|
|
+ if len(s_subscopeclass) > 0 {
|
|
|
+ s_subscopeclass = "," + s_subscopeclass + ","
|
|
|
+ }
|
|
|
+ set["s_subscopeclass"] = s_subscopeclass
|
|
|
+ s_winner := strings.Join(pInfo.Winners, ",")
|
|
|
+ if len(s_winner) > 0 {
|
|
|
+ s_winner = "," + s_winner + ","
|
|
|
+ }
|
|
|
+ set["s_winner"] = s_winner
|
|
|
+ if pInfo.Buyerperson != "" && pInfo.Buyertel != "" {
|
|
|
+ set["buyerperson"] = pInfo.Buyerperson
|
|
|
+ set["buyertel"] = pInfo.Buyertel
|
|
|
+ }
|
|
|
+ if pInfo.Buyerclass != "" {
|
|
|
+ set["buyerclass"] = pInfo.Buyerclass
|
|
|
+ }
|
|
|
+ if pInfo.District != "" {
|
|
|
+ set["district"] = pInfo.District
|
|
|
+ }
|
|
|
+ if pInfo.Bidopentime > 0 {
|
|
|
+ set["bidopentime"] = pInfo.Bidopentime
|
|
|
+ }
|
|
|
+ if len(pInfo.Winnerorder) > 0 {
|
|
|
+ set["winnerorder"] = pInfo.Winnerorder
|
|
|
+ }
|
|
|
+ if thisinfo.HasPackage {
|
|
|
+ set["multipackage"] = 1
|
|
|
+ } else {
|
|
|
+ set["multipackage"] = 0
|
|
|
+ }
|
|
|
+ e := InitEL(util.ObjToString((*res)["extractpos"]))
|
|
|
+ if thisinfo.dealtype == 1 {
|
|
|
+ var sonpackage map[string]interface{}
|
|
|
+ for _, obj := range tmp["package"].(map[string]interface{}) {
|
|
|
+ sonpackage, _ = obj.(map[string]interface{})
|
|
|
+ }
|
|
|
+ for _, v2 := range []string{"budget", "budget_w", "winner", "winner_w", "bidstatus", "bidstatus_w"} {
|
|
|
+ if sonpackage[v2] != nil {
|
|
|
+ tmp[v2] = sonpackage[v2]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ e.fieldpriority(&tmp, res, &set)
|
|
|
+ set["extractpos"] = e.GetVal()
|
|
|
+ if thisinfo.HasPackage { //多包处理
|
|
|
+ p1, _ := (*res)["package"].(map[string]interface{})
|
|
|
+ p2, _ := tmp["package"].(map[string]interface{})
|
|
|
+ if p2 != nil {
|
|
|
+ if p1 != nil {
|
|
|
+ for pk2, pv2 := range p2 {
|
|
|
+ if p1[pk2] != nil { //合并
|
|
|
+ item1, _ := p1[pk2].(map[string]interface{})
|
|
|
+ item2, _ := pv2.(map[string]interface{})
|
|
|
+ if item1 != nil && item2 != nil { //原始项
|
|
|
+ for ik1, iv1 := range item2 {
|
|
|
+ if item1[ik1] == nil {
|
|
|
+ item1[ik1] = iv1
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ p1[pk2] = pv2
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ p1 = p2
|
|
|
+ }
|
|
|
+ }
|
|
|
+ set["package"] = p1
|
|
|
+ }
|
|
|
+ //中标候选人合并
|
|
|
+
|
|
|
+ update := map[string]interface{}{}
|
|
|
+ if len(set) > 0 {
|
|
|
+ update["$set"] = set
|
|
|
+ }
|
|
|
+ //保留原数据吧
|
|
|
+ push := NewPushInfo(tmp)
|
|
|
+ for tkey, _ := range extractpos {
|
|
|
+ if tmp[tkey] != nil {
|
|
|
+ push[tkey] = tmp[tkey]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ update["$push"] = map[string]interface{}{
|
|
|
+ "list": push,
|
|
|
+ }
|
|
|
+ if len(update) > 0 {
|
|
|
+ MQFW.Update(projectColl, map[string]interface{}{
|
|
|
+ "_id": util.StringTOBsonId(pInfo.Id),
|
|
|
+ }, &update, false, false)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //再往redis中放 index
|
|
|
+ //往队列中增加时间 -------------->start
|
|
|
+ redis.Put(REDISIDS, updateid, pInfo, 0)
|
|
|
+ return updateid
|
|
|
+}
|
|
|
+
|
|
|
+func EqInfoUpdate(thisinfo *Info, pInfo *ProjectInfo) {
|
|
|
+ var tk int
|
|
|
+ bf1 := false
|
|
|
+ for _k, tv := range pInfo.Publistime {
|
|
|
+ tk = _k
|
|
|
+ if tv > thisinfo.Publishtime {
|
|
|
+ bf1 = true
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if bf1 {
|
|
|
+ pInfo.Publistime = append(append(pInfo.Publistime[:tk], thisinfo.Publishtime), pInfo.Publistime[tk:]...)
|
|
|
+ pInfo.InfoType = append(append(pInfo.InfoType[:tk], []string{thisinfo.TopType, thisinfo.SubType}), pInfo.InfoType[tk:]...)
|
|
|
+ pInfo.Ids = append(append(pInfo.Ids[:tk], thisinfo.Id), pInfo.Ids[tk:]...)
|
|
|
+ } else {
|
|
|
+ pInfo.Publistime = append(pInfo.Publistime, thisinfo.Publishtime)
|
|
|
+ pInfo.InfoType = append(pInfo.InfoType, []string{thisinfo.TopType, thisinfo.SubType})
|
|
|
+ pInfo.Ids = append(pInfo.Ids, thisinfo.Id)
|
|
|
+ }
|
|
|
+ //增加发布时间结束----------------->end
|
|
|
+
|
|
|
+ if (pInfo.Buyer == "" && thisinfo.Buyer != "") || (len([]rune(pInfo.Buyer)) < 5 && len([]rune(thisinfo.Buyer)) > 5) {
|
|
|
+ pInfo.Buyer = thisinfo.Buyer
|
|
|
+ }
|
|
|
+ if (pInfo.Agency == "" && thisinfo.Agency != "") || (len([]rune(pInfo.Agency)) < 5 && len([]rune(thisinfo.Agency)) > 5) {
|
|
|
+ pInfo.Agency = thisinfo.Agency
|
|
|
+ }
|
|
|
+ if (pInfo.ProjectCode == "" && thisinfo.ProjectCode != "") || (len([]rune(pInfo.ProjectCode)) < 6 && len([]rune(thisinfo.ProjectCode)) > 6) {
|
|
|
+ pInfo.ProjectCode = thisinfo.ProjectCode
|
|
|
+ }
|
|
|
+
|
|
|
+ if thisinfo.Buyerperson != "" && thisinfo.Buyertel != "" && len([]rune(thisinfo.Buyertel)) > 6 {
|
|
|
+ pInfo.Buyerperson = thisinfo.Buyerperson
|
|
|
+ pInfo.Buyertel = thisinfo.Buyertel
|
|
|
+ }
|
|
|
+ if thisinfo.Buyerclass != "" {
|
|
|
+ pInfo.Buyerclass = thisinfo.Buyerclass
|
|
|
+ }
|
|
|
+ if thisinfo.District != "" {
|
|
|
+ pInfo.District = thisinfo.District
|
|
|
+ }
|
|
|
+ if thisinfo.Bidopentime > 0 {
|
|
|
+ pInfo.Bidopentime = thisinfo.Bidopentime
|
|
|
+ }
|
|
|
+ if len(thisinfo.Topscopeclass) > 0 {
|
|
|
+ sort.Strings(pInfo.Topscopeclass)
|
|
|
+ for _, k := range thisinfo.Topscopeclass {
|
|
|
+ if BinarySearch(pInfo.Topscopeclass, k) == -1 {
|
|
|
+ pInfo.Topscopeclass = append(pInfo.Topscopeclass, k)
|
|
|
+ sort.Strings(pInfo.Topscopeclass)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(thisinfo.Subscopeclass) > 0 {
|
|
|
+ sort.Strings(pInfo.Subscopeclass)
|
|
|
+ for _, k := range thisinfo.Subscopeclass {
|
|
|
+ if BinarySearch(pInfo.Subscopeclass, k) == -1 {
|
|
|
+ pInfo.Subscopeclass = append(pInfo.Subscopeclass, k)
|
|
|
+ sort.Strings(pInfo.Subscopeclass)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //winner
|
|
|
+ if len(thisinfo.Winners) > 0 {
|
|
|
+ sort.Strings(pInfo.Winners)
|
|
|
+ for _, k := range thisinfo.Winners {
|
|
|
+ if BinarySearch(pInfo.Winners, k) == -1 {
|
|
|
+ pInfo.Winners = append(pInfo.Winners, k)
|
|
|
+ sort.Strings(pInfo.Winners)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //winnerorder
|
|
|
+ if len(thisinfo.Winnerorder) > 0 {
|
|
|
+ sort.Strings(pInfo.Winnerorder)
|
|
|
+ for _, k := range thisinfo.Winnerorder {
|
|
|
+ if BinarySearch(pInfo.Winnerorder, k) == -1 {
|
|
|
+ pInfo.Winnerorder = append(pInfo.Winnerorder, k)
|
|
|
+ sort.Strings(pInfo.Winnerorder)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //return pInfo
|
|
|
+}
|
|
|
+
|
|
|
+func (com *CompareInfo /*对比对象,分别含有项目名称、项目编号、采购单位*/) compute(thisinfo *Info /*新信息*/, ids []string) {
|
|
|
+ //根据 com的key到redis中查找对应的值(如:项目名称的key为"pn_某某项目",值为一维对象数组 即:[]ProjectInfo)
|
|
|
+ //这些信息id上面已经加过锁
|
|
|
+ defer util.Catch()
|
|
|
+ res := redis.Mget(REDISIDS, ids)
|
|
|
+ //redis.GetInterface("other", com.Key, &com.Pinfo)
|
|
|
+ //redispush := false
|
|
|
+ if len(res) > 0 { //找到项目名称、项目编号或采购单位相同时
|
|
|
+ for _, b1 := range res { //遍历对象数组
|
|
|
+ if b1 != nil {
|
|
|
+ var info ProjectInfo
|
|
|
+ err := json.Unmarshal(b1.([]byte), &info)
|
|
|
+ if err != nil {
|
|
|
+ log.Println(err)
|
|
|
+ }
|
|
|
+ cone := &CompareOne{
|
|
|
+ Parent: com,
|
|
|
+ Pinfo: &info,
|
|
|
+ }
|
|
|
+ if com.Field != "pn" { //比较字段不是项目名称时,对项目名称要素的打分逻辑
|
|
|
+ //新信息和对比信息的项目名称长度都大于5时
|
|
|
+ if len([]rune(thisinfo.ProjectName)) > 5 && len([]rune(info.ProjectName)) > 5 {
|
|
|
+ if thisinfo.ProjectName == info.ProjectName { //绝对相等加5分
|
|
|
+ cone.ProjectNameType = 1
|
|
|
+ cone.Score += 5
|
|
|
+ } else if strings.Index(info.ProjectName, thisinfo.ProjectName) > -1 || strings.Index(thisinfo.ProjectName, info.ProjectName) > -1 { //包含或被包含关系不加分不减分
|
|
|
+ cone.ProjectNameType = 2
|
|
|
+ //cone.Score += 3
|
|
|
+ } else { //不相等且不包含减5分
|
|
|
+ cone.ProjectNameType = 3
|
|
|
+ cone.Score -= 10
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if com.Field != "pc" { //比较字段不是项目编号时,对项目编号要素的打分逻辑
|
|
|
+ //新信息和对比信息和项目编号长度大于5
|
|
|
+ if len(thisinfo.ProjectCode) > 5 && len(info.ProjectCode) > 5 {
|
|
|
+ if thisinfo.ProjectCode == info.ProjectCode { //项目编号相等加5分
|
|
|
+ cone.ProjectCodeType = 1
|
|
|
+ cone.Score += 5
|
|
|
+ } else if strings.Index(info.ProjectCode, thisinfo.ProjectCode) > -1 || strings.Index(thisinfo.ProjectCode, info.ProjectCode) > -1 { //包含或被包含关系加3分
|
|
|
+ cone.ProjectCodeType = 2
|
|
|
+ cone.Score += 3
|
|
|
+ } else {
|
|
|
+ //不相等减5分
|
|
|
+ cone.ProjectCodeType = 3
|
|
|
+ cone.Score -= 5
|
|
|
+ if len(thisinfo.ProjectCode) == len(info.ProjectCode) { //值不相等但长度相等减20分
|
|
|
+ cone.Score -= 20
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if com.Field != "pb" { //比较字段不是采购单位时,对采购单位要素的打分逻辑
|
|
|
+ //采购单位大于4个字时做比较
|
|
|
+ if len(thisinfo.Buyer) > 12 && len(info.Buyer) > 12 {
|
|
|
+ if thisinfo.Buyer == info.Buyer { //相等加5分
|
|
|
+ cone.BuyerType = 1
|
|
|
+ cone.Score += 5
|
|
|
+ } else if strings.Index(thisinfo.Buyer, info.Buyer) > -1 || strings.Index(info.Buyer, thisinfo.Buyer) > -1 { //包含与被包含加3分
|
|
|
+ cone.BuyerType = 2
|
|
|
+ cone.Score += 3
|
|
|
+ } else { //不相等减5分
|
|
|
+ cone.BuyerType = 3
|
|
|
+ cone.Score -= 5
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //对发布时间打分,两者信息发布时间在120天以内加2分
|
|
|
+ if math.Abs(float64(thisinfo.Publishtime-info.Publistime[0])) < 120*86400 && math.Abs(float64(thisinfo.Publishtime-info.Publistime[len(info.Publistime)-1])) < 120*86400 {
|
|
|
+ cone.PublistimeType = 1
|
|
|
+ //cone.Score += 2
|
|
|
+ } else { //发布时间相差超过120天减5分
|
|
|
+ cone.PublistimeType = 2
|
|
|
+ cone.Score -= 5
|
|
|
+ }
|
|
|
+
|
|
|
+ //对招标机构进行打分
|
|
|
+ //招标机构长度大于4分字时做比较
|
|
|
+ if len(thisinfo.Agency) > 12 && len(info.Agency) > 12 {
|
|
|
+ if thisinfo.Agency == info.Agency { //相等加3分
|
|
|
+ cone.AgencyType = 1
|
|
|
+ cone.Score += 3
|
|
|
+ } else if strings.Index(thisinfo.Agency, info.Agency) > -1 || strings.Index(info.Agency, thisinfo.Agency) > -1 { //包含关系不加分
|
|
|
+ cone.AgencyType = 2
|
|
|
+ } else { //不相等减5分
|
|
|
+ cone.AgencyType = 3
|
|
|
+ cone.Score -= 5
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //对地区进行打分,地区都不为空,且范围都不是全国时做比较
|
|
|
+ if thisinfo.Area != "" && info.Area != "" && thisinfo.Area != "A" && thisinfo.Area != "全国" && info.Area != "A" && info.Area != "全国" {
|
|
|
+ if thisinfo.Area == info.Area { //地区相同不加分
|
|
|
+ cone.AreaType = 1
|
|
|
+ } else { //地区不同减5分
|
|
|
+ cone.AreaType = 2
|
|
|
+ cone.Score -= 5
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //分包类型相同时
|
|
|
+ if thisinfo.HasPackage == info.HasPackage {
|
|
|
+ if thisinfo.HasPackage {
|
|
|
+ cone.PackageType = 1
|
|
|
+ } else { //都不是多包
|
|
|
+ cone.PackageType = 2
|
|
|
+ }
|
|
|
+ //都是分包或都不是分包加4分
|
|
|
+ cone.Score += 4
|
|
|
+ } else { //分包不一致时
|
|
|
+ if thisinfo.TopType == "招标" { //新信息类型为招标时
|
|
|
+ if thisinfo.HasPackage && len(thisinfo.Package) == 1 { //当前信息是招标类,且是一个包,对比信息不是分包,认为它们都不是分包,加2分
|
|
|
+ cone.PackageType = 3
|
|
|
+ cone.Score += 2
|
|
|
+ } else if !thisinfo.HasPackage { //当前信息不是分包,合并信息是分包(要从标题中查找),不加分不减分
|
|
|
+ cone.PackageType = 31
|
|
|
+ } else { //当前信息是分包,合并信息不是分包,不加减分
|
|
|
+ cone.PackageType = 32
|
|
|
+ }
|
|
|
+ } else if thisinfo.TopType == "结果" { //新信息类型为结果时
|
|
|
+ if thisinfo.HasPackage && len(thisinfo.Package) == 1 { //从标题中查找有没有分包 ,当前信息结果类是一个分包,合并信息不是分包,加2分
|
|
|
+ cone.PackageType = 4
|
|
|
+ cone.Score += 2
|
|
|
+ } else if !thisinfo.HasPackage { //当前信息是结果,不是分包,而合并信息是分包,不加分
|
|
|
+ cone.PackageType = 41
|
|
|
+ } else {
|
|
|
+ cone.PackageType = 42 //当前信息是分包,而合并信息不是分包,不加减分
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //cone.Pos = k
|
|
|
+ //放入打分数组中
|
|
|
+ com.Scores = append(com.Scores, cone)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//二分字符串查找
|
|
|
+func BinarySearch(s []string, k string) int {
|
|
|
+ sort.Strings(s)
|
|
|
+ lo, hi := 0, len(s)-1
|
|
|
+ for lo <= hi {
|
|
|
+ m := (lo + hi) >> 1
|
|
|
+ if s[m] < k {
|
|
|
+ lo = m + 1
|
|
|
+ } else if s[m] > k {
|
|
|
+ hi = m - 1
|
|
|
+ } else {
|
|
|
+ return m
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1
|
|
|
+}
|
|
|
+
|
|
|
+//移除数组中重复的元素
|
|
|
+func RemoveDup(arr []string) (newarr []string) {
|
|
|
+ m1 := map[string]bool{}
|
|
|
+ newarr = []string{}
|
|
|
+ for _, k := range arr {
|
|
|
+ if !m1[k] {
|
|
|
+ m1[k] = true
|
|
|
+ newarr = append(newarr, k)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|