wcj 6 年 前
コミット
8cbe9adb5a

+ 16 - 2
src/jy/admin/rulecheck.go

@@ -248,7 +248,17 @@ func checkBackReg(content, ruleText string) string {
 func checkCoreReg(field, content, ruleText string) map[string]string {
 	rep := map[string]string{}
 	qu.Try(func() {
-		tmp := strings.Split(ruleText, "__")
+		//处理正负数修正
+		ptmp := strings.Split(ruleText, "#")
+		sign := 0
+		if len(ptmp) == 2 {
+			if ptmp[1] == "正" {
+				sign = 1
+			} else if ptmp[1] == "负" {
+				sign = -1
+			}
+		}
+		tmp := strings.Split(ptmp[0], "__")
 		if len(tmp) == 2 {
 			epos := strings.Split(tmp[1], ",")
 			posm := map[string]int{}
@@ -279,7 +289,11 @@ func checkCoreReg(field, content, ruleText string) map[string]string {
 							continue
 						}
 						val := content[pos[p]:pos[p+1]]
-						rep[k] = val
+						if sign == -1 {
+							rep[k] = "-" + val
+						} else {
+							rep[k] = val
+						}
 					}
 				}
 			}

+ 9 - 1
src/jy/clear/tonumber.go

@@ -55,7 +55,15 @@ func ObjToInt(data []interface{}) []interface{} {
 
 //转float,精度小数点4位
 func ObjToFloat(data []interface{}) []interface{} {
-	tmp, err := strconv.ParseFloat(fmt.Sprint(data[0]), 64)
+	con := fmt.Sprint(data[0])
+	percent := strings.Contains(con, "%")
+	if percent {
+		con = strings.Replace(con, "%", "", -1)
+	}
+	tmp, err := strconv.ParseFloat(con, 64)
+	if percent {
+		tmp = tmp / 100
+	}
 	if err != nil {
 		return []interface{}{float64(0), data[1]}
 	} else {

+ 72 - 18
src/jy/extract/extract.go

@@ -23,13 +23,13 @@ import (
 )
 
 var (
-	lock          sync.RWMutex
-	cut           = ju.NewCut()                          //获取正文并清理
-	ExtLogs       map[*TaskInfo][]map[string]interface{} //抽取日志
-	TaskList      map[string]*ExtractTask                //任务列表
-	ClearTaskList map[string]*ClearTask                  //清理任务列表
-	saveLimit     = 200                                  //抽取日志批量保存
-	PageSize      = 5000                                 //查询分页
+	lock    sync.RWMutex
+	cut     = ju.NewCut()                          //获取正文并清理
+	ExtLogs map[*TaskInfo][]map[string]interface{} //抽取日志
+	TaskList      map[string]*ExtractTask          //任务列表
+	ClearTaskList map[string]*ClearTask            //清理任务列表
+	saveLimit     = 200                            //抽取日志批量保存
+	PageSize      = 5000                           //查询分页
 	Fields        = `{"title":1,"detail":1,"contenthtml":1,"site":1,"spidercode":1,"toptype":1,"subtype":1,"area":1,"city":1,"comeintime":1,"publishtime":1,"sensitive":1,"projectinfo":1,"jsondata":1}`
 	Fields2       = `{"budget":1,"bidamount":1,"title":1,"projectname":1,"winner":1}`
 )
@@ -345,6 +345,9 @@ func (e *ExtractTask) ExtractDetail(j *ju.Job) {
 			//抽取规则
 			tmprules := map[string][]*RuleCore{}
 			lock.Lock()
+			if e.RuleCores[j.Category] == nil {
+				j.Category = "*_其他"
+			}
 			for k, vc1 := range e.RuleCores[j.Category] {
 				tmprules[k] = vc1
 			}
@@ -390,7 +393,13 @@ func (e *ExtractTask) ExtractDetail(j *ju.Job) {
 				}
 			}
 		} else {
-			for _, vc1 := range e.RuleCores[j.Category+"_"+j.CategorySecond] {
+			var cores map[string][]*RuleCore
+			if e.RuleCores[j.Category+"_"+j.CategorySecond] == nil {
+				cores = e.RuleCores["*_其他"]
+			} else {
+				cores = e.RuleCores[j.Category+"_"+j.CategorySecond]
+			}
+			for _, vc1 := range cores {
 				for _, vc := range vc1 {
 					tmp := ju.DeepCopy(doc).(map[string]interface{})
 					//是否进入逻辑
@@ -474,7 +483,9 @@ func (e *ExtractTask) ExtractDetail(j *ju.Job) {
 					clear.MesField[key] != nil {
 					text := qu.ObjToString(v.Value)
 					text = clear.OtherClean(key, text)
-					v.Value = text
+					if text != "" {
+						v.Value = text
+					}
 				}
 				lock.Unlock()
 			}
@@ -672,11 +683,17 @@ func ExtRegCore(extfrom string, doc map[string]interface{}, j *ju.Job, in *RegLu
 				}
 				if tmps, ok := v.([]map[string]interface{}); ok {
 					for _, tmp := range tmps {
-						field := &ju.ExtField{Field: k, Code: qu.ObjToString(tmp["code"]), RuleText: qu.ObjToString(tmp["ruletext"]), Type: qu.ObjToString(tmp["type"]), MatchType: qu.ObjToString(tmp["matchtype"]), ExtFrom: extfrom, Value: tmp["value"], Score: 0}
+						field := &ju.ExtField{Field: k, Code: qu.ObjToString(tmp["code"]), RuleText: qu.ObjToString(tmp["ruletext"]), Type: qu.ObjToString(tmp["type"]), MatchType: qu.ObjToString(tmp["matchtype"]), ExtFrom: extfrom, Value: tmp["value"],}
+						if extfrom == "title" {
+							field.Score = 4
+						}
 						if tmp["blocktag"] != nil {
 							field.BlockTag = tmp["blocktag"].(map[string]bool)
 						}
-						item := &ju.ScoreItem{Des: "初始化", Code: qu.ObjToString(tmp["code"]), RuleText: qu.ObjToString(tmp["ruletext"]), Type: qu.ObjToString(tmp["type"]), MatchType: qu.ObjToString(tmp["matchtype"]), ExtFrom: extfrom, Value: tmp["value"], Score: 0}
+						item := &ju.ScoreItem{Des: "初始化", Code: qu.ObjToString(tmp["code"]), RuleText: qu.ObjToString(tmp["ruletext"]), Type: qu.ObjToString(tmp["type"]), MatchType: qu.ObjToString(tmp["matchtype"]), ExtFrom: extfrom, Value: tmp["value"]}
+						if extfrom == "title" {
+							item.Score = 4
+						}
 						if tmp["scoreitem"] == nil {
 							scoreItems := make([]*ju.ScoreItem, 0)
 							scoreItems = append(scoreItems, item)
@@ -907,6 +924,12 @@ func extRegCoreToResult(extfrom, text string, tag *map[string]bool, j *ju.Job, v
 						continue
 					}
 					val := text[pos[p]:pos[p+1]]
+					if val == "招标公告" {
+						return extinfo
+					}
+					if utf8.RuneCountInString(val) < 2 && extfrom == "title" {
+						val = text
+					}
 					tmps := []map[string]interface{}{}
 					tmp := map[string]interface{}{
 						"field":     v.Field,
@@ -921,11 +944,20 @@ func extRegCoreToResult(extfrom, text string, tag *map[string]bool, j *ju.Job, v
 					tmps = append(tmps, tmp)
 					extinfo[k] = tmps
 					if strings.TrimSpace(val) != "" {
-						exfield := ju.ExtField{Field: k, Code: v.Code, RuleText: v.RuleText, Type: "regexp", MatchType: "regcontent", ExtFrom: extfrom, Value: val, Score: 0}
+						if v.RegCore.NumSign == -1 { //正负值修正
+							val = "-" + val
+						}
+						exfield := ju.ExtField{Field: k, Code: v.Code, RuleText: v.RuleText, Type: "regexp", MatchType: "regcontent", ExtFrom: extfrom, Value: val}
+						if extfrom == "title" {
+							exfield.Score = 4
+						}
 						if tmp["blocktag"] != nil {
 							exfield.BlockTag = tmp["blocktag"].(map[string]bool)
 						}
-						item := ju.ScoreItem{Des: "初始化", Code: v.Code, RuleText: v.RuleText, Type: "regexp", MatchType: "regcontent", ExtFrom: extfrom, Value: val, Score: 0}
+						item := ju.ScoreItem{Des: "初始化", Code: v.Code, RuleText: v.RuleText, Type: "regexp", MatchType: "regcontent", ExtFrom: extfrom, Value: val}
+						if extfrom == "title" {
+							item.Score = 4
+						}
 						if tmp["scoreitem"] == nil {
 							sitems := make([]*ju.ScoreItem, 0)
 							sitems = append(sitems, &item)
@@ -967,11 +999,17 @@ func extRegCoreToResult(extfrom, text string, tag *map[string]bool, j *ju.Job, v
 			if j.Result[v.Field] == nil {
 				j.Result[v.Field] = [](*ju.ExtField){}
 			}
-			field := &ju.ExtField{Field: v.Field, Code: v.Code, RuleText: v.RuleText, Type: "regexp", MatchType: "regcontent", ExtFrom: extfrom, Value: val, Score: 0}
+			field := &ju.ExtField{Field: v.Field, Code: v.Code, RuleText: v.RuleText, Type: "regexp", MatchType: "regcontent", ExtFrom: extfrom, Value: val}
+			if extfrom == "title" {
+				field.Score = 4
+			}
 			if tmp["blocktag"] != nil {
 				field.BlockTag = tmp["blocktag"].(map[string]bool)
 			}
-			item := ju.ScoreItem{Des: "初始化", Code: v.Code, RuleText: v.RuleText, Type: "regexp", MatchType: "regcontent", ExtFrom: extfrom, Value: val, Score: 0}
+			item := ju.ScoreItem{Des: "初始化", Code: v.Code, RuleText: v.RuleText, Type: "regexp", MatchType: "regcontent", ExtFrom: extfrom, Value: val}
+			if extfrom == "title" {
+				item.Score = 4
+			}
 			if tmp["scoreitem"] == nil {
 				sitems := make([]*ju.ScoreItem, 0)
 				sitems = append(sitems, &item)
@@ -1031,7 +1069,7 @@ func ExtRegBack(j *ju.Job, in *RegLuaInfo, t *TaskInfo) {
 					//						continue
 					//					}
 					text := qu.ObjToString(v.Value)
-					if text != "" {
+					if text != "" && v.ExtFrom != "title" {
 						text = in.RegPreBac.Reg.ReplaceAllString(text, in.RegPreBac.Replace)
 					}
 					j.Result[in.Field][k].Value = text
@@ -1273,6 +1311,7 @@ func AnalysisSaveResult(j, jf *ju.Job, e *ExtractTask) {
 					map[string]interface{}{"$set": tmp},
 				}
 				e.BidArr = append(e.BidArr, tmparr)
+				e.BidTotal++
 			}
 			if b, ok := ju.Config["saveresult"].(bool); ok && b {
 				id := tmp["_id"]
@@ -1349,13 +1388,28 @@ func funcAnalysis(j *ju.Job) (*map[string]interface{}, map[string][]*ju.ExtField
 	values := map[string][]*ju.SortObject{}
 	for key, val := range result {
 		fieldValue := map[string][]interface{}{}
+		//cfscore := make(map[string]float64) //重复匹配加分
 		if iscore { //走打分
 			for _, v := range val {
 				if len(fmt.Sprint(v.Value)) < 1 {
 					continue //去除空串
 				}
-				fieldValue[fmt.Sprint(v.Value)+v.Type] = []interface{}{v.Score, v.Value}
+				//if v.Score >0 {
+				//	cfscore[fmt.Sprint(v.Value)] += 1
+				//}
+				if fieldValue[fmt.Sprint(v.Value)+v.Type] == nil {
+					fieldValue[fmt.Sprint(v.Value)+v.Type] = []interface{}{v.Score, v.Value}
+				} else if fieldValue[fmt.Sprint(v.Value)+v.Type][0].(float64) < v.Score {
+					fieldValue[fmt.Sprint(v.Value)+v.Type][0] = v.Score
+				}
 			}
+			//for key := range fieldValue {
+			//	for cfkey, cfv := range cfscore {
+			//		if strings.Contains(key, cfkey) {
+			//			fieldValue[key][0] = fieldValue[key][0].(float64) + cfv
+			//		}
+			//	}
+			//}
 		} else { //不走打分,按出现频次
 			for _, v := range val {
 				if len(fmt.Sprint(v.Value)) < 1 {
@@ -1425,7 +1479,7 @@ func (e *ExtractTask) QualityAudit(resulttmp map[string]interface{}) {
 func (e *ExtractTask) RedisMatch(field, fv string, val map[string]interface{}) {
 	defer qu.Catch()
 	i := redis.GetInt(field, field+"_"+fv) //查找redis
-	if i == 0 {                            //reids未找到,执行规则匹配
+	if i == 0 { //reids未找到,执行规则匹配
 		val[field+"_isredis"] = false
 		e.RuleMatch(field, fv, val) //规则匹配
 	} else { //redis找到,打标识存库

+ 13 - 2
src/jy/extract/extractInit.go

@@ -28,6 +28,7 @@ type ExtReg struct {
 	Replace    string
 	Bextract   bool
 	ExtractPos map[string]int
+	NumSign    int //正负修正标记,例如浮动率(上浮正1、下浮负-1)
 }
 type RuleCore struct {
 	Field     string        //逻辑字段
@@ -77,6 +78,7 @@ type ExtractTask struct {
 	ResultArr    [][]map[string]interface{} //抽取结果详情
 	BidChanel    chan bool                  //抽取结果
 	BidArr       [][]map[string]interface{} //抽取结果
+	BidTotal     int                        //结果数量
 
 	RecogFieldMap map[string]map[string]interface{}   //识别字段
 	FidClassMap   map[string][]map[string]interface{} //分类
@@ -427,7 +429,16 @@ func (e *ExtractTask) InfoRole(vinfo map[string]interface{}) []*RuleCore {
 			} else {
 				qu.Try(func() {
 					rinfo.RuleText = v["s_rule"].(string)
-					tmp := strings.Split(rinfo.RuleText, "__")
+					ptmp := strings.Split(rinfo.RuleText, "#")
+					sign := 0
+					if len(ptmp) == 2 {
+						if ptmp[1] == "正" {
+							sign = 1
+						} else if ptmp[1] == "负" {
+							sign = -1
+						}
+					}
+					tmp := strings.Split(ptmp[0], "__")
 					var pattern string
 					if strings.Contains(tmp[0], "\\u") {
 						tmp[0] = strings.Replace(tmp[0], "\\", "\\\\", -1)
@@ -447,7 +458,7 @@ func (e *ExtractTask) InfoRole(vinfo map[string]interface{}) []*RuleCore {
 								posm[rinfo.Field] = qu.IntAll(ks[0])
 							}
 						}
-						rinfo.RegCore = &ExtReg{Reg: regexp.MustCompile(pattern), Bextract: true, ExtractPos: posm}
+						rinfo.RegCore = &ExtReg{Reg: regexp.MustCompile(pattern), Bextract: true, ExtractPos: posm, NumSign: sign}
 					} else {
 						rinfo.RegCore = &ExtReg{Reg: regexp.MustCompile(pattern), Bextract: false}
 					}

+ 11 - 3
src/jy/extract/extractudp.go

@@ -118,7 +118,10 @@ func ExtractByUdp(sid, eid string, instanceId ...string) {
 		ext.ResultSave(true)
 		ext.BidSave(true)
 		ext.IsRun = true
+	} else {
+		ext.BidTotal = 0
 	}
+	index := 0
 	if len(instanceId) > 0 { //分布式抽取进度
 		query := bson.M{"_id": bson.M{"$gte": bson.ObjectIdHex(sid), "$lte": bson.ObjectIdHex(eid)}}
 		count1 := ext.TaskInfo.FDB.Count(ext.TaskInfo.FromColl, query)
@@ -163,6 +166,7 @@ func ExtractByUdp(sid, eid string, instanceId ...string) {
 					ext.TaskInfo.ProcessPool <- true
 					go ext.ExtractProcess(j, jf)
 					sid = _id
+					index++
 				}
 				db.Mgo.Update("ecs", `{"InstanceId":"`+instanceId[0]+`"}`,
 					map[string]interface{}{"$set": map[string]interface{}{
@@ -189,6 +193,7 @@ func ExtractByUdp(sid, eid string, instanceId ...string) {
 					ext.TaskInfo.ProcessPool <- true
 					go ext.ExtractProcess(j, jf)
 					sidback = _id
+					index++
 				}
 				db.Mgo.Update("ecs", `{"InstanceId":"`+instanceId[0]+`"}`,
 					map[string]interface{}{"$set": map[string]interface{}{
@@ -201,6 +206,7 @@ func ExtractByUdp(sid, eid string, instanceId ...string) {
 					"pagecurrent": i + 1,
 				}}, true, false)
 		}
+		log.Debug("抽取完成", "count:", count, "index:", index, "bidtotal:", ext.BidTotal)
 	} else { //普通抽取
 		query := bson.M{"_id": bson.M{"$gte": bson.ObjectIdHex(sid), "$lte": bson.ObjectIdHex(eid)}}
 		count := ext.TaskInfo.FDB.Count(ext.TaskInfo.FromColl, query)
@@ -214,7 +220,7 @@ func ExtractByUdp(sid, eid string, instanceId ...string) {
 			query = bson.M{"_id": bson.M{"$gte": bson.ObjectIdHex(sid)}}
 			fmt.Printf("page=%d,query=%v", i+1, query)
 			list, _ := ext.TaskInfo.FDB.Find(ext.TaskInfo.FromColl, query, nil, Fields, false, 0, limit)
-			for k, v := range *list {
+			for _, v := range *list {
 				if qu.ObjToString(v["sensitive"]) != "" { //去除含敏感词数据
 					continue
 				}
@@ -232,13 +238,15 @@ func ExtractByUdp(sid, eid string, instanceId ...string) {
 					defer wg.Done()
 					ext.ExtractProcess(j, jf)
 				}()
-				if k%1000 == 0 {
-					log.Debug(i, k, _id)
+				index++
+				if index%1000 == 0 {
+					log.Debug("index:", index, "页码:", i+1, "_id:", _id)
 				}
 				sid = _id
 			}
 		}
 		wg.Wait()
 		ext.BidSave(false)
+		log.Debug("抽取完成", "count:", count, "index:", index, "bidtotal:", ext.BidTotal, "sid:", eid)
 	}
 }

+ 23 - 18
src/jy/extract/score.go

@@ -106,25 +106,30 @@ func ScoreFields(j *ju.Job) map[string][]*ju.ExtField {
 				//qz := TagConfig["其他"][field]
 				//tmps[tmpsindex].Score += 2 * qz //乘以权重系数
 			}
-
-			//是否有kv值
-			if strings.Contains(tmpsvalue.Type, "colon") {
-				tmps[tmpsindex].Score += qu.Float64All(SoreConfig["extractype"]["colon"])
-				tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "colonkv", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(SoreConfig["extractype"]["colon"])})
-			} else if strings.Contains(tmpsvalue.Type, "space") {
-				tmps[tmpsindex].Score += qu.Float64All(SoreConfig["extractype"]["space"])
-				tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "spacekv", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(SoreConfig["extractype"]["space"])})
-			} else if strings.Contains(tmpsvalue.Type, "table") {
-				tmps[tmpsindex].Score += qu.Float64All(SoreConfig["extractype"]["table"])
-				tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "tablekv", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(SoreConfig["extractype"]["table"])})
+			if tmpsvalue.ExtFrom != "title" { //非标题抽取
+				//是否有kv值
+				if strings.Contains(tmpsvalue.Type, "colon") {
+					tmps[tmpsindex].Score += qu.Float64All(SoreConfig["extractype"]["colon"])
+					tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "colonkv", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(SoreConfig["extractype"]["colon"])})
+				} else if strings.Contains(tmpsvalue.Type, "space") {
+					tmps[tmpsindex].Score += qu.Float64All(SoreConfig["extractype"]["space"])
+					tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "spacekv", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(SoreConfig["extractype"]["space"])})
+				} else if strings.Contains(tmpsvalue.Type, "table") {
+					tmps[tmpsindex].Score += qu.Float64All(SoreConfig["extractype"]["table"])
+					tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "tablekv", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(SoreConfig["extractype"]["table"])})
+				}
 			}
-
-			//正则
-			if strings.Contains(tmpsvalue.Type, "regexp") {
-				tmps[tmpsindex].Score += qu.Float64All(SoreConfig["extractype"]["regexp"])
-				tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "regexp", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(SoreConfig["extractype"]["regexp"])})
+			if tmpsvalue.ExtFrom != "title" { //非标题抽取
+				if strings.Contains(tmpsvalue.Type, "regexp") {
+					tmps[tmpsindex].Score += qu.Float64All(SoreConfig["extractype"]["regexp"])
+					tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "regexp", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(SoreConfig["extractype"]["regexp"])})
+				}
+			} else {
+				if strings.Contains(tmpsvalue.Type, "regexp") {
+					tmps[tmpsindex].Score += qu.Float64All(SoreConfig["extractype"]["regexp"])+ 1
+					tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "regexp", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(SoreConfig["extractype"]["regexp"])+ 1 })
+				}
 			}
-
 			scoreRule := SoreConfig[field]
 			if scoreRule == nil {
 				continue
@@ -156,7 +161,7 @@ func ScoreFields(j *ju.Job) map[string][]*ju.ExtField {
 								tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "长度打分", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(scores[2])})
 							} else {
 								tmps[tmpsindex].Score += qu.Float64All(scores[1])
-								tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "长度打分", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score:qu.Float64All(scores[1])})
+								tmps[tmpsindex].ScoreItem = append(tmps[tmpsindex].ScoreItem, &ju.ScoreItem{Des: "长度打分", Code: tmpsvalue.Code, RuleText: tmpsvalue.RuleText, Type: tmpsvalue.Type, MatchType: tmpsvalue.MatchType, ExtFrom: tmpsvalue.ExtFrom, Value: tmpsvalue.Value, Score: qu.Float64All(scores[1])})
 							}
 						}
 					}

+ 9 - 0
src/jy/pretreated/analystep.go

@@ -82,6 +82,15 @@ func AnalyStart(job *util.Job) {
 		bl.SpaceKV = SspacekvEntity.Entrance(newCon, "", nil)
 		job.Block = append(job.Block, bl)
 	}
+	for _, v := range job.BlockPackage {
+		block := &util.Block{}
+		block.ColonKV = v.ColonKV
+		block.TableKV = v.TableKV
+		block.SpaceKV = v.SpaceKV
+		block.Text = v.Text
+		block.Winnerorder = v.WinnerOrder
+		job.Block = append(job.Block, block)
+	}
 }
 
 //分析table解析结果

+ 1 - 1
src/jy/pretreated/analytable.go

@@ -1763,7 +1763,7 @@ func (table *Table) FindTdVal(td *TD, direct, vdirect int) (b bool) {
 						bfind = true
 					}
 				}
-				if bvalfind {
+				if bvalfind && varrpos >-1{
 					vals[varrpos] = td.Val // += "__" + td.Val
 				} else {
 					//添加时候去除空值和nil

+ 28 - 14
src/res/tagscore.json

@@ -1,11 +1,11 @@
 {
-  "招标条件": {
+  "bidcondition": {
     "buyer": 1,
     "projectname": 1,
     "agency": 1,
     "approvalno": 1
   },
-  "项目概况/采购需求": {
+  "projectoverview": {
     "projectscope": 1,
     "projectcode": 1,
     "projectaddr": 1,
@@ -14,15 +14,23 @@
     "projectscale": 1,
     "funds": 1
   },
-  "投标文件的递交": {
+  "bidder_requirement": {},
+  "examineway": {},
+  "biddingsignup": {},
+  "biddingfile_obtain": {},
+  "bidfile_submit": {
     "bidopendate": 1,
     "bidopentime": 1
   },
-  "开标信息": {
+  "bidopen_info": {
     "bidopendate": 1,
     "bidopentime": 1
   },
-  "联系方式": {
+  "purchasepolicy": {
+  },
+  "noticemedia": {},
+  "superviseway": {},
+  "contactway": {
     "buyer": 1,
     "buyerperson": 1,
     "buyertel": 1,
@@ -32,29 +40,32 @@
     "agencytel": 1,
     "agencyaddr": 1
   },
-  "项目信息": {
+  "bidbond": {},
+  "bidder_inforeg": {},
+  "bid_note": {},
+  "projectinfo": {
     "projectcode": 1,
     "projectname": 1
   },
-  "采购单位信息": {
+  "buyerinfo": {
     "buyer": 1,
     "buyeraddr": 1,
     "buyerperson": 1,
     "buyertel": 1
   },
-  "招标代理机构信息": {
+  "bidagencyinfo": {
     "agency": 1,
     "agencyaddr": 1,
     "agencyperson": 1,
     "agencytel": 1
   },
-  "中标供应商": {
+  "winner": {
     "winner": 1,
     "winneraddr": 1,
     "winnerpserson": 1,
     "winnertel": 1
   },
-  "成交信息": {
+  "dealinfo": {
     "projectname": 1,
     "projectcode": 1,
     "bidamount": 1,
@@ -64,17 +75,20 @@
     "experts": 1,
     "purchasinglist": 1
   },
-  "评标委员会": {
+  "servicecharge": {},
+  "bidevaluat_result": {},
+  "bidevaluat_committee": {
     "experts": 1
   },
-  "报价明细": {
+  "offerdetail": {
     "purchasinglist": 1,
     "bidamount": 1
   },
-  "合同金额": {
+  "contractamount": {
     "bidamount": 1
   },
-  "其他": {
+  "payway": {},
+  "other": {
     "buyer": 1,
     "projectname": 1,
     "agency": 1,

+ 29 - 0
src/res/公告结构.txt

@@ -0,0 +1,29 @@
+招标公告	
+	招标条件 bidcondition
+	项目概况/采购需求 projectoverview
+	投标人资格要求 bidder_requirement
+	资格审查方式 examineway
+	投标报名 biddingsignup
+	招标文件的获取 biddingfile_obtain
+	投标文件的递交 bidfile_submit
+	开标信息 bidopen_info
+	采购项目需要落实的政府采购政策 purchasepolicy
+	公告媒体 noticemedia
+	监督方式 superviseway
+	联系方式 contactway
+	投标保证金 bidbond
+	投标人信息注册 bidder_inforeg
+	投标注意事项 bid_note
+"中标公告 合同"	
+	项目信息 projectinfo
+	采购单位信息 buyerinfo
+	招标代理机构信息 bidagencyinfo
+	中标供应商 winner
+	成交信息 dealinfo
+	采购代理服务费收取 servicecharge
+	评标结果公示 bidevaluat_result
+	评标委员会 bidevaluat_committee
+	报价明细 offerdetail
+	联系方式 contactway
+	合同金额 contractamount
+	付款方式 payway

+ 0 - 0
src/udpfileserver/README.md → udpfileocr/README.md


+ 5 - 3
src/udpfileserver/config.json → udpfileocr/config.json

@@ -1,12 +1,14 @@
 {
   "udpip": "127.0.0.1",
-  "udpport": "8888",
+  "udpport": "1490",
   "channelsize": "1",
   "dbsize": "5",
-  "mongodb_one_ip": "127.0.0.1:27017",
+  "mongodb_one_ip": "192.168.3.207:27082",
   "mongodb_one_db": "spider",
   "mongodb_one_c": "bidding_file",
   "mongodb_one_filefiled": "projectinfo",
   "file2text": "192.168.3.207:1234",
-  "PageSize":5000
+  "PageSize":5000,
+  "toudpip": "127.0.0.1",
+  "toudpport": "1481"
 }

+ 22 - 4
src/udpfileserver/main.go → udpfileocr/main.go

@@ -60,10 +60,17 @@ func processUdpMsg(act byte, data []byte, ra *net.UDPAddr) {
 			log.Println("json err :", err, string(data))
 			return
 		}
-		log.Println(mapInfo)
+		log.Println("updocr接收数据:",mapInfo)
 		stime :=time.Now()
 		gid := strings.TrimSpace(mapInfo["gtid"].(string))
+		rgid := gid
 		lid := strings.TrimSpace(mapInfo["lteid"].(string))
+		//err = udpclient.WriteUdp([]byte("updocr接收数据成功"), mu.OP_TYPE_DATA, &net.UDPAddr{
+		//	IP:   net.ParseIP(Sysconfig["toudpip"].(string)),
+		//	Port: qu.IntAll(Sysconfig["toudpport"]),
+		//})
+		////forfunc(lid)
+		//log.Println("接收数据成功,发送到:",Sysconfig["toudpip"].(string),Sysconfig["toudpport"],err)
 		if bson.IsObjectIdHex(gid) && bson.IsObjectIdHex(lid) {
 			var jsq int64
 			query := bson.M{"_id": bson.M{"$gt": bson.ObjectIdHex(gid),"$lte": bson.ObjectIdHex(lid),}}
@@ -105,7 +112,7 @@ func processUdpMsg(act byte, data []byte, ra *net.UDPAddr) {
 									ChanB <- true
 									if qu.ObjToString(fileinfo["fid"]) ==""{
 										<-ChanB
-										log.Println(mid, "mgo ", MgoFileFiled,"没有fid ")
+										//log.Println(mid, "mgo ", MgoFileFiled,"没有fid ")
 										continue
 									}
 									//if (strings.Contains(qu.ObjToString(fileinfo["url"]),"fs.qmx.top")|| strings.Contains(qu.ObjToString(fileinfo["url"]),"fj1.jianyu360.com"))&& (strings.TrimSpace(qu.ObjToString(fileinfo["content"]))==""||strings.Contains(qu.ObjToString(fileinfo["content"]),"error") ){
@@ -127,11 +134,22 @@ func processUdpMsg(act byte, data []byte, ra *net.UDPAddr) {
 					}
 				}
 			}
+			//发送udp信号
+			by, _ := json.Marshal(map[string]interface{}{
+				"gtid":  rgid,
+				"lteid": lid,
+				"stype": "fujian",
+			})
+			err := udpclient.WriteUdp(by, mu.OP_TYPE_DATA, &net.UDPAddr{
+				IP:   net.ParseIP(Sysconfig["toudpip"].(string)),
+				Port: qu.IntAll(Sysconfig["toudpport"]),
+			})
 			//识别完以后再次查询数据库,进行下一轮识别
 			log.Println("处理查询数据结束...",jsq,time.Now().Sub(stime))
-			//SendMail("处理完成")
+			SendMail(rgid+"--->"+lid+"处理完成")
 			//进行下一轮识别
 			forfunc(lid)
+			log.Println("发送到:",Sysconfig["toudpip"].(string),Sysconfig["toudpport"],err)
 		} else {
 			log.Println("开始id或结束id参数错误:", string(data))
 		}
@@ -260,7 +278,7 @@ func SendMail( body string ) error {
 	m.SetHeader("From","Get to" + "<" + mailConn["user"] + ">")  //这种方式可以添加别名,即“XD Game”, 也可以直接用<code>m.SetHeader("From",mailConn["user"])</code> 读者可以自行实验下效果
 	m.SetHeader("To", []string{"550838476@qq.com"}...)  //发送给多个用户
 	m.SetHeader("Subject", "MongoId")  //设置邮件主题
-	m.SetBody("text/html","服务器:"+ body)     //设置邮件正文
+	m.SetBody("text/html","服务器:"+ body)     //设置邮件正文
 
 	d := gomail.NewDialer(mailConn["host"], port, mailConn["user"], mailConn["pass"])
 

+ 9 - 6
src/udpfileserver/maintest.go → udpfileocr/maintest.go

@@ -8,17 +8,17 @@ import (
 )
 
 func main() {
-	udpclient := util.UdpClient{Local: "127.0.0.1:8889", BufSize: 1024}
+	udpclient := util.UdpClient{Local: "127.0.0.1:1482", BufSize: 1024}
 	udpclient.Listen(processUdpMsg2)
 	m := map[string]string{
-		"gtid":"5cb682c9ed1d910046aca2eb",
-		"lteid":"5cb683f2ed1d9100570abbc3",
+		"gtid":"5d19bf2fa5cb26b9b79b1994",
+		"lteid":"5d19bf2fa5cb26b9b79b1995",
 	}
 	b, _ := json.Marshal(m)
 	//for  range time.Tick(time.Second){
 	err := udpclient.WriteUdp(b, util.OP_TYPE_DATA, &net.UDPAddr{
-		IP:   net.ParseIP("127.0.0.1"),
-		Port: 8888,
+		IP:   net.ParseIP("172.17.145.163"),
+		Port: 1481,
 	})
 	if err != nil{
 		log.Println(err)
@@ -26,7 +26,10 @@ func main() {
 	}
 	log.Println("发送成功")
 	//}
+	select {
+
+	}
 }
 func processUdpMsg2(act byte, data []byte, ra *net.UDPAddr) {
-
+	log.Println(string(data))
 }

+ 21 - 0
versioncomparison/config.json

@@ -0,0 +1,21 @@
+{
+  "extractmgo": "192.168.3.207:27081",
+  "extractdb": "qfw",
+  "extractc": "bidding",
+  "previousmgo": "192.168.3.207:27081",
+  "previousdb": "qfw",
+  "previousc": "result_v3",
+  "newmgo": "192.168.3.207:27081",
+  "newdb": "extract_v3",
+  "newc": "result_data2",
+  "keyfield": {
+    "bidamount": 1,
+    "budget": 1,
+    "winner": 1,
+    "projectcode":1,
+    "buyer": 1,
+    "projectname": 1
+  },
+  "queryNum": 1000,
+  "querySid": "57319151edbcdc7b27000aec"
+}

+ 423 - 0
versioncomparison/main.go

@@ -0,0 +1,423 @@
+package main
+
+import (
+	"fmt"
+	"gopkg.in/mgo.v2"
+	"gopkg.in/mgo.v2/bson"
+	"jy/mongodbutil"
+	"log"
+	"qfw/common/src/github.com/tealeg/xlsx"
+	"qfw/util"
+	"strings"
+)
+
+var (
+	SysConfig   map[string]interface{}
+	Extractmgo  *mgo.Session      //抽取
+	Previousmgo *mongodbutil.Pool //之前抽取
+	Newmgo      *mongodbutil.Pool //最新抽取
+)
+
+/**
+与上个抽取版本做比较
+ */
+func init() {
+	util.ReadConfig(&SysConfig)
+	if len(SysConfig) < 1 {
+		log.Println("配置文件读取失败")
+		return
+	}
+	session, e := mgo.Dial(util.ObjToString(SysConfig["extractmgo"]))
+	if e != nil {
+		log.Fatal(e)
+	}
+	Extractmgo = session
+	Previousmgo = mongodbutil.MgoFactory(2, 5, 120, util.ObjToString(SysConfig["previousmgo"]), util.ObjToString(SysConfig["previousdb"]))
+	Newmgo = mongodbutil.MgoFactory(2, 5, 120, util.ObjToString(SysConfig["newmgo"]), util.ObjToString(SysConfig["newdb"]))
+}
+
+type versionComparison struct {
+	Id  interface{} `json:"_id"`
+	Url string      `json:"url"`
+}
+
+func main() {
+	Query(util.IntAll(SysConfig["queryNum"]), util.ObjToString(SysConfig["querySid"]))
+}
+
+func Query(num int, sid string) {
+	xf, err := xlsx.OpenFile("抽取结果对比.xlsx")
+	if err != nil {
+		log.Println("读取文件", err)
+		return
+	}
+	var projectcodenum, bidamountnum, winnernum, buyernum, budgetnum, projectnamenum int //不相等计数器
+	var projectcodenumXT, bidamountnumXT, winnernumXT, buyernumXT, budgetnumXT, projectnamenumXT int      //相等计数器
+	var pcodeNotNilNumP, bidamountNotNilNumP, winnerNotNilNumP, buyerNotNilNumP, budgetNotNilNumP, pnameNotNilNumP int //不相等计数器
+	var pcodeNotNilNumN, bidamountNotNilNumN, winnerNotNilNumN, buyerNotNilNumN, budgetNotNilNumN, pnameNotNilNumN int //不相等计数器
+
+	log.Println(num, sid)
+	if num < 1 {
+		log.Println("查询数量应该大于0")
+		return
+	}
+	sum := num //总量
+	//if strings.TrimSpace(gteid) == "" {
+	//	gteid = "386cd3000000000000000000"
+	//}
+	var iter *mgo.Iter
+	if sid == "" {
+		iter = Extractmgo.DB(util.ObjToString(SysConfig["extractdb"])).C(util.ObjToString(SysConfig["extractc"])).Find(nil).Select(bson.M{"_id": 1}).Iter()
+	} else {
+		iter = Extractmgo.DB(util.ObjToString(SysConfig["extractdb"])).C(util.ObjToString(SysConfig["extractc"])).Find(bson.M{"_id": bson.M{
+			"$gte": bson.ObjectIdHex(sid)},
+		}).Select(bson.M{"_id": 1}).Iter()
+	}
+	defer log.Println("关闭 iter:", iter.Close())
+	var data map[string]bson.ObjectId
+	getdata := make([]bson.ObjectId, 0)
+	for iter.Next(&data) {
+		if num == 0 {
+			break
+		}
+		getdata = append(getdata, data["_id"])
+		num--
+	}
+	log.Println(sum, "条数据加载完成")
+	projectnames := make([]*Projectname, 0)
+	buyers := make([]*Buyer, 0)
+	projectcodes := make([]*Projectcode, 0)
+	winners := make([]*Winner, 0)
+	budgets := make([]*Budget, 0)
+	bidamounts := make([]*Bidamount, 0)
+	for _, gv := range getdata {
+		log.Println(gv)
+		gvid := gv.Hex()
+		pdata, b := Previousmgo.FindById(util.ObjToString(SysConfig["previousc"]), gvid, SysConfig["keyfield"])
+		if !b || len(*pdata) == 0 {
+			log.Println("oldId不存在")
+			continue
+		}
+		log.Println("pdata:", pdata)
+
+		ndata, b := Newmgo.FindById(util.ObjToString(SysConfig["newc"]), gvid, SysConfig["keyfield"])
+		if !b || len(*ndata) == 0 {
+			log.Println("nweId不存在")
+			continue
+		}
+		log.Println("ndata:", ndata)
+
+		versioncomparison := new(versionComparison)
+		versioncomparison.Id = gvid
+		versioncomparison.Url = "https://www.jianyu360.com/article/content/" + util.CommonEncodeArticle("content", gvid) + ".html"
+		for k := range SysConfig["keyfield"].(map[string]interface{}) {
+			var pd interface{}
+			var nd interface{}
+			if k == "budget" || k == "bidamount" {
+				pd = util.Float64All((*pdata)[k])
+				nd = util.Float64All((*ndata)[k])
+				if pd.(float64) > 0 {
+					switch k {
+					case "budget":
+						budgetNotNilNumP++
+					case "bidamount":
+						bidamountNotNilNumP++
+					}
+				}
+				if nd.(float64) > 0 {
+					switch k {
+					case "budget":
+						budgetNotNilNumN++
+					case "bidamount":
+						bidamountNotNilNumN++
+					}
+				}
+			} else {
+				pd = strings.TrimSpace(util.ObjToString((*pdata)[k]))
+				nd = strings.TrimSpace(util.ObjToString((*ndata)[k]))
+				if strings.TrimSpace(pd.(string)) != "" {
+					switch k {
+					case "projectname":
+						pnameNotNilNumP++
+					case "buyer":
+						buyerNotNilNumP++
+					case "projectcode":
+						pcodeNotNilNumP++
+					case "winner":
+						winnerNotNilNumP++
+					}
+				}
+				if strings.TrimSpace(nd.(string)) != "" {
+					switch k {
+					case "projectname":
+						pnameNotNilNumN++
+					case "buyer":
+						buyerNotNilNumN++
+					case "projectcode":
+						pcodeNotNilNumN++
+					case "winner":
+						winnerNotNilNumN++
+					}
+				}
+			}
+			if pd != nd {
+				//log.Println(k)
+				switch k {
+				case "projectname":
+					projectname := new(Projectname)
+					projectname.versionComparison = *versioncomparison
+					pd = strings.Trim(fmt.Sprint(pd), "项目")
+					pd = strings.Trim(strings.TrimSpace(fmt.Sprint(pd)), "采购")
+					nd = strings.Trim(fmt.Sprint(nd), "项目")
+					nd = strings.Trim(strings.TrimSpace(fmt.Sprint(nd)), "采购")
+					if pd != nd{
+						projectname.ProjectnameOld = fmt.Sprint(pd)
+						projectname.ProjectnameNew = fmt.Sprint(nd)
+						projectnames = append(projectnames, projectname)
+						projectnamenum++
+					}else {
+							projectnamenumXT++
+					}
+				case "buyer":
+					buyer := new(Buyer)
+					buyer.versionComparison = *versioncomparison
+					buyer.BuyerOld = fmt.Sprint(pd)
+					buyer.BuyerNew = fmt.Sprint(nd)
+					buyers = append(buyers, buyer)
+					buyernum++
+				case "projectcode":
+					projectcode := new(Projectcode)
+					projectcode.ProjectcodeOld = fmt.Sprint(pd)
+					projectcode.ProjectcodeNew = fmt.Sprint(nd)
+					projectcode.versionComparison = *versioncomparison
+					projectcodes = append(projectcodes, projectcode)
+					projectcodenum++
+				case "winner":
+					winner := new(Winner)
+					winner.WinnerOld = fmt.Sprint(pd)
+					winner.WinnerNew = fmt.Sprint(nd)
+					winner.versionComparison = *versioncomparison
+					winners = append(winners, winner)
+					winnernum++
+				case "budget":
+					budget := new(Budget)
+					budget.BudgetOld = fmt.Sprint(pd)
+					budget.BudgetNew = fmt.Sprint(nd)
+					budget.versionComparison = *versioncomparison
+					budgets = append(budgets, budget)
+					budgetnum++
+				case "bidamount":
+					bidamount := new(Bidamount)
+					bidamount.BidamountOld = fmt.Sprint(pd)
+					bidamount.BidamountNew = fmt.Sprint(nd)
+					bidamount.versionComparison = *versioncomparison
+					bidamounts = append(bidamounts, bidamount)
+					bidamountnum++
+				}
+			}else {
+				//相同统计
+				pd = strings.TrimSpace(fmt.Sprint(pd))
+				nd = strings.TrimSpace(fmt.Sprint(nd))
+				if pd == ""||pd == "0" || nd == ""|| nd == "0"{
+					continue
+				}
+				if pd == nd {
+					switch k {
+					case "projectname":
+						projectnamenumXT++
+					case "buyer":
+						buyernumXT++
+					case "projectcode":
+						projectcodenumXT++
+					case "winner":
+						winnernumXT++
+					case "budget":
+						budgetnumXT++
+					case "bidamount":
+						bidamountnumXT++
+					}
+				}
+			}
+		}
+		fmt.Println()
+	}
+
+	//log.Println(projectcodenum, bidamountnum, winnernum, buyernum, budgetnum, projectnamenum)
+	for ins, ivs := range xf.Sheets {
+		for inr, ivr := range ivs.Rows {
+			for _, ivc := range ivr.Cells {
+				//抽取对比
+				if ins == 0 {
+					if inr < 3 {
+						continue
+					}
+					switch strings.TrimSpace(ivc.String()) {
+					case "projectname":
+						style := ivr.Cells[1].GetStyle()
+						style.Font.Color = "000000"
+						ivr.Cells[1].SetValue(pnameNotNilNumP)
+						ivr.Cells[2].SetValue(pnameNotNilNumN)
+						//结果相同数量
+						ivr.Cells[3].SetValue(projectnamenumXT)
+						ivr.Cells[3].SetStyle(style)
+						//结果不同数量
+						ivr.Cells[4].SetValue(projectnamenum)
+						ivr.Cells[4].SetStyle(style)
+					case "buyer":
+						style := ivr.Cells[1].GetStyle()
+						style.Font.Color = "000000"
+						ivr.Cells[1].SetValue(buyerNotNilNumP)
+						ivr.Cells[2].SetValue(buyerNotNilNumN)
+						//结果相同数量
+						ivr.Cells[3].SetValue(buyernumXT)
+						ivr.Cells[3].SetStyle(style)
+						//结果不同数量
+						ivr.Cells[4].SetValue(buyernum)
+						ivr.Cells[4].SetStyle(style)
+					case "projectcode":
+						style := ivr.Cells[1].GetStyle()
+						style.Font.Color = "000000"
+						ivr.Cells[1].SetValue(pcodeNotNilNumP)
+						ivr.Cells[2].SetValue(pcodeNotNilNumN)
+						//结果相同数量
+						ivr.Cells[3].SetValue(projectcodenumXT)
+						ivr.Cells[3].SetStyle(style)
+						//结果不同数量
+						ivr.Cells[4].SetValue(projectcodenum)
+						ivr.Cells[4].SetStyle(style)
+					case "winner":
+						style := ivr.Cells[1].GetStyle()
+						style.Font.Color = "000000"
+						ivr.Cells[1].SetValue(winnerNotNilNumP)
+						ivr.Cells[2].SetValue(winnerNotNilNumN)
+						//结果相同数量
+						ivr.Cells[3].SetValue(winnernumXT)
+						ivr.Cells[3].SetStyle(style)
+						//结果不同数量
+						ivr.Cells[4].SetValue(winnernum)
+						ivr.Cells[4].SetStyle(style)
+					case "budget":
+						style := ivr.Cells[1].GetStyle()
+						style.Font.Color = "000000"
+						ivr.Cells[1].SetValue(budgetNotNilNumP)
+						ivr.Cells[2].SetValue(budgetNotNilNumN)
+						//结果相同数量
+						ivr.Cells[3].SetValue(budgetnumXT)
+						ivr.Cells[3].SetStyle(style)
+						//结果不同数量
+						ivr.Cells[4].SetValue(budgetnum)
+						ivr.Cells[4].SetStyle(style)
+					case "bidamount":
+						style := ivr.Cells[1].GetStyle()
+						style.Font.Color = "000000"
+						ivr.Cells[1].SetValue(bidamountNotNilNumP)
+						ivr.Cells[2].SetValue(bidamountNotNilNumN)
+						//结果相同数量
+						ivr.Cells[3].SetValue(bidamountnumXT)
+						ivr.Cells[3].SetStyle(style)
+						//结果不同数量
+						ivr.Cells[4].SetValue(bidamountnum)
+						ivr.Cells[4].SetStyle(style)
+					}
+				}
+			}
+		}
+		if ins > 0 {
+			if len(ivs.Rows) == 0 {
+				row := ivs.AddRow()
+				row.AddCell().SetValue("ObjectId")
+				row.AddCell().SetValue("dev3.1.2")
+				row.AddCell().SetValue("dev3.2")
+				row.AddCell().SetValue("URL")
+			}
+			//log.Println(ivs.Name)
+			switch strings.TrimSpace(ivs.Name) {
+			case "projectname":
+				for _, v := range projectnames {
+					row := ivs.AddRow()
+					row.AddCell().SetValue(v.Id)
+					row.AddCell().SetValue(v.ProjectnameOld)
+					row.AddCell().SetValue(v.ProjectnameNew)
+					row.AddCell().SetValue(v.Url)
+				}
+			case "buyer":
+				for _, v := range buyers {
+					row := ivs.AddRow()
+					row.AddCell().SetValue(v.Id)
+					row.AddCell().SetValue(v.BuyerOld)
+					row.AddCell().SetValue(v.BuyerNew)
+					row.AddCell().SetValue(v.Url)
+				}
+			case "projectcode":
+				for _, v := range projectcodes {
+					row := ivs.AddRow()
+					row.AddCell().SetValue(v.Id)
+					row.AddCell().SetValue(v.ProjectcodeOld)
+					row.AddCell().SetValue(v.ProjectcodeNew)
+					row.AddCell().SetValue(v.Url)
+				}
+			case "winner":
+				for _, v := range winners {
+					row := ivs.AddRow()
+					row.AddCell().SetValue(v.Id)
+					row.AddCell().SetValue(v.WinnerOld)
+					row.AddCell().SetValue(v.WinnerNew)
+					row.AddCell().SetValue(v.Url)
+				}
+			case "budget":
+				for _, v := range budgets {
+					row := ivs.AddRow()
+					row.AddCell().SetValue(v.Id)
+					row.AddCell().SetValue(v.BudgetOld)
+					row.AddCell().SetValue(v.BudgetNew)
+					row.AddCell().SetValue(v.Url)
+				}
+			case "bidamount":
+				for _, v := range bidamounts {
+					row := ivs.AddRow()
+					row.AddCell().SetValue(v.Id)
+					row.AddCell().SetValue(v.BidamountOld)
+					row.AddCell().SetValue(v.BidamountNew)
+					row.AddCell().SetValue(v.Url)
+				}
+			}
+		}
+	}
+	err = xf.Save("resultdata.xlsx")
+	if err != nil {
+		log.Println("保存xlsx失败:", err)
+		return
+	}
+	log.Println("xlsx保存成功")
+}
+
+type Projectname struct {
+	versionComparison
+	ProjectnameOld string
+	ProjectnameNew string
+}
+type Buyer struct {
+	versionComparison
+	BuyerOld string
+	BuyerNew string
+}
+type Projectcode struct {
+	versionComparison
+	ProjectcodeOld string
+	ProjectcodeNew string
+}
+type Winner struct {
+	versionComparison
+	WinnerOld string
+	WinnerNew string
+}
+type Budget struct {
+	versionComparison
+	BudgetOld string
+	BudgetNew string
+}
+type Bidamount struct {
+	versionComparison
+	BidamountOld string
+	BidamountNew string
+}

BIN
versioncomparison/抽取结果对比.xlsx