Commit 9d4889cb by mushishixian

temp

parent 8f487d98
...@@ -14,17 +14,17 @@ type RecvPro struct { ...@@ -14,17 +14,17 @@ type RecvPro struct {
} }
func init() { func init() {
//queueExchange := rabbitmq.QueueExchange{ queueExchange := rabbitmq.QueueExchange{
// "bom_match", "bom_match",
// "bom_match", "bom_match",
// "bom", "bom",
// "direct", "direct",
// "amqp://huntadmin:jy2y2900@192.168.1.237:5672/", "amqp://huntadmin:jy2y2900@192.168.1.237:5672/",
//} }
//
////str := `{"bom_id":666,"delivery_type":1,"sort":1}` //str := `{"bom_id":666,"delivery_type":1,"sort":1}`
//str := `{"bom_id":717,"delivery_type":1,"sort":1}` str := `{"bom_id":692,"delivery_type":1,"sort":1}`
//rabbitmq.Send(queueExchange, str) rabbitmq.Send(queueExchange, str)
} }
func (t *RecvPro) Consumer(dataByte []byte) (err error) { func (t *RecvPro) Consumer(dataByte []byte) (err error) {
......
package logic package logic
import ( import (
"bom_server/configs"
"bom_server/internal/common" "bom_server/internal/common"
"bom_server/internal/mapping" "bom_server/internal/mapping"
"bom_server/internal/model" "bom_server/internal/model"
"bom_server/internal/pkg/gredis" "bom_server/internal/pkg/gredis"
"context"
"fmt" "fmt"
"github.com/gomodule/redigo/redis" "github.com/gomodule/redigo/redis"
"github.com/syyongx/php2go" "github.com/imroc/req"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
es "gopkg.in/olivere/elastic.v5"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
) )
//根据参数去匹配商品 func GetStandardAttrs(bomItems []model.BomItem) []model.BomItem {
func MatchGoodsNameByAttrs(bomItems []model.BomItem) (result []model.BomItem, err error) {
client, err := es.NewClient(es.SetURL(configs.ESSetting.Url))
if err != nil {
return
}
defer client.Stop()
index := configs.ESSetting.AttrIndex
search := client.MultiSearch().Index(index)
searchFlag := false
//先根据参数去构建批量查询条件 //先根据参数去构建批量查询条件
for _, item := range bomItems { for key, item := range bomItems {
//如果有型号,但是型号有可能是参数,所以先去匹配下参数,有的话转成对应的型号
//用参数去请求接口,获取转换后的参数
var attrParams []string
//如果有型号,没有参数,则尝试用型号当作参数去请求,判断是否为参数
if item.GoodsName != "" && item.Attrs == "" { if item.GoodsName != "" && item.Attrs == "" {
search = searchAttr(item, search) attrParams = []string{item.GoodsName}
searchFlag = true
} else { } else {
search = searchAttr(item, search) attrParams = []string{item.Attrs}
searchFlag = true
} }
}
if !searchFlag {
return bomItems, nil
}
res, err := search.Do(context.Background())
if err != nil {
return
}
if len(res.Responses) == 0 {
return
}
//因为是多重查询,所以会有多套结果
for key, responses := range res.Responses {
//有数据进行转换
if responses.Hits != nil {
for _, hit := range responses.Hits.Hits {
res, _ := hit.Source.MarshalJSON()
if bomItems[key].GoodsName == "" || (bomItems[key].Attrs == "" && bomItems[key].GoodsName != "") {
bomItems[key].GoodsName = gjson.Get(string(res), "goods_name").String()
bomItems[key].IsGoodsNameByAttrs = true
//还要打上是匹配到参数的标志
} //fmt.Println(attrParams)
params := req.BodyJSON(attrParams)
resp, err := req.Post("http://192.168.2.232:50053/unit_conversion", params)
if err != nil {
fmt.Println(err)
}
result := resp.String()
//匹配出来的型号
var words, attrsList, encapList []string
wordsArray := gjson.Get(result, "words").Array()
for _, word := range wordsArray {
words = append(words, word.String())
}
attrsArray := gjson.Get(result, "attrs").Array()
for _, attr := range attrsArray {
attrsList = append(attrsList, attr.String())
}
encapArray := gjson.Get(result, "encap").Array()
for _, attr := range encapArray {
encapList = append(encapList, attr.String())
}
fmt.Println("匹配的型号为 : ", words, "匹配的参数列表为 : ", attrsList)
//如果words大于0,则代表是型号
if len(words) > 0 {
item.GoodsName = words[0]
}
//如果words等于0,但是属性有的情况
if len(words) == 0 && len(attrsList) > 0 {
if item.GoodsName == "" && len(item.AttrList) == 0 {
item.GoodsName = ""
}
if item.GoodsName != "" {
item.GoodsName = ""
} }
item.AttrList = attrsList
} }
//如果原来的encap为空的情况下,识别出encap的话,就要补充
if item.Encap == "" && len(encapList) > 0 {
item.Encap = encapList[0]
}
bomItems[key] = item
}
return bomItems
}
//转换参数,使其成为标准参数
func MatchGoodsNameByAttrs(bomItems []model.BomItem) (result []model.BomItem, err error) {
//先根据参数去构建批量查询条件
for key, item := range bomItems {
//如果有型号,但是型号有可能是参数,所以先去匹配下参数,有的话转成对应的型号
bomItems[key].AttrList = TransformAttr(item.Attrs, item.Encap)
} }
result = bomItems result = bomItems
//for _,item:=range bomItems {
// fmt.Println(item.GoodsName)
//}
return return
} }
func searchAttr(bomItem model.BomItem, search *es.MultiSearchService) (result *es.MultiSearchService) { //转换精简参数
func TransformAttr(attrStr, encap string) []string {
//先去切割参数得到参数列表 //先去切割参数得到参数列表
var attrs []string attrs := splitAttrs(attrStr)
if bomItem.GoodsName != "" && bomItem.Attrs == "" {
attrs = splitAttrs(strings.Trim(bomItem.GoodsName, " "))
} else {
attrs = splitAttrs(bomItem.Attrs)
}
//当切割出来的参数大于1个的时候,就要去针对每个参数进行里面再一次提纯 //当切割出来的参数大于1个的时候,就要去针对每个参数进行里面再一次提纯
if len(attrs) > 1 { if len(attrs) > 1 {
for key, attr := range attrs { for key, attr := range attrs {
attrs[key] = changeKeyword(attr) attrs[key] = changeStandardUnit(attr)
//切割完以后,还要去对切割后的参数提取值,因为有可能参数没有分隔符 //切割完以后,还要去对切割后的参数提取值,因为有可能参数没有分隔符
extractRes := extractAttr(attrs[key]) extract := extractAttr(attrs[key])
for ek, eAttr := range extractRes { for ek, eAttr := range extract {
if ek == 0 { if ek == 0 {
attrs[key] = extractRes[0] attrs[key] = extract[0]
} else { } else {
attrs = append(attrs, eAttr) attrs = append(attrs, eAttr)
} }
} }
} }
} else { } else {
attrs[0] = changeKeyword(attrs[0]) attrs[0] = changeStandardUnit(attrs[0])
attrs = extractAttrsByStr(attrs[0]) attrs = extractAttrsByStr(attrs[0])
} }
var attrsSlice []string var attrsSlice []string
//去转换每一个参数,得到去查询es的标准格式 //去转换每一个参数,得到去查询es的标准格式
for _, attr := range attrs { for _, attr := range attrs {
attr = TransformESParam(attr) attr = GetStandardEsAttr(attr)
if attr != "" { if attr != "" {
attrsSlice = append(attrsSlice, attr) attrsSlice = append(attrsSlice, attr)
} }
} }
query, shouldQueryNumber, mustQueryNumber := getQuery(attrsSlice) //转换成新约定的形式
//单独针对封装进行转换 attrsSlice = transformNew(attrsSlice)
if bomItem.Encap != "" { return attrsSlice
//先提取出纯数字
//numberR, _ := regexp.Compile(mapping.PureNumberRegular)
//pureNumber := numberR.FindString(bomItem.Encap)
////再去找对应属性
//attrValue := "封装" + "€" + pureNumber
attrValue := TransformEncap(bomItem.Encap)
if !php2go.InArray(attrValue, attrsSlice) {
subQuery := es.NewTermQuery("attrs.attr_value", attrValue)
nestedQuery := es.NewNestedQuery("attrs", subQuery)
query.Must(nestedQuery)
mustQueryNumber++
}
}
//如果ZyBrandId不为空,则代表匹配到了映射id
if bomItem.ZyBrandId != "" && len(attrsSlice) > 0 {
query.Should(es.NewTermQuery("brand_name", bomItem.ZyBrandName))
shouldQueryNumber++
} else {
if bomItem.BrandName != "" && len(attrsSlice) > 0 {
brandName := bomItem.BrandName
//提取全英文,转成大写
if strings.Contains(brandName, " ") {
//有空格隔开只取第一个
brandName = strings.Split(brandName, " ")[0]
}
//转成全大写,因为ES存的是大写
brandName = strings.ToUpper(brandName)
//去除特殊符号和中文等等
r1, _ := regexp.Compile(`/[^A-Za-z0-9]+/`)
brandName = r1.ReplaceAllString(brandName, "")
query.Should(es.NewTermQuery("brand_name", brandName))
shouldQueryNumber++
}
}
shouldMatchNumber := getShouldMatchNumber(shouldQueryNumber, mustQueryNumber)
query.MinimumNumberShouldMatch(shouldMatchNumber)
source := es.NewSearchSource().Query(query)
source.Sort("_score", false)
source.Sort("stock", false)
source.Sort("brand_sort", true)
source = source.From(0).Size(1)
searchRequest := es.NewSearchRequest().Source(source).Preference("_primary")
//fmt.Println(searchRequest.Body())
return search.Add(searchRequest)
} }
//切割参数 //切割参数
...@@ -201,7 +167,7 @@ func extractAttrsByStr(attr string) []string { ...@@ -201,7 +167,7 @@ func extractAttrsByStr(attr string) []string {
} }
//将写法转成正规写法,转换单位,比如有的人喜欢将Ω输成欧姆或者O,所以要统一转成正常的Ω //将写法转成正规写法,转换单位,比如有的人喜欢将Ω输成欧姆或者O,所以要统一转成正常的Ω
func changeKeyword(attr string) (result string) { func changeStandardUnit(attr string) (result string) {
regulars := mapping.KeywordRegular regulars := mapping.KeywordRegular
for regexpStr, regular := range regulars { for regexpStr, regular := range regulars {
if strings.Contains(attr, "Ω") { if strings.Contains(attr, "Ω") {
...@@ -219,14 +185,7 @@ func changeKeyword(attr string) (result string) { ...@@ -219,14 +185,7 @@ func changeKeyword(attr string) (result string) {
} }
//将属性值转成ES的标准值(例如 : 阻值(欧姆)€3000) //将属性值转成ES的标准值(例如 : 阻值(欧姆)€3000)
func TransformESParam(attr string) (result string) { func GetStandardEsAttr(attr string) (result string) {
attrValue := getAttrValueByAttr(attr)
return attrValue
}
//根据参数单位或者参数值获取对应的重要属性,组成最后查询的字符串
//±
func getAttrValueByAttr(attr string) (attrValue string) {
//先找出单位,通过将数字替换成,第一个字符不是数字的,跳过 //先找出单位,通过将数字替换成,第一个字符不是数字的,跳过
r, _ := regexp.Compile(mapping.GetAttrUnitRegular) r, _ := regexp.Compile(mapping.GetAttrUnitRegular)
attrUnit := strings.Trim(r.ReplaceAllString(attr, ""), " ") attrUnit := strings.Trim(r.ReplaceAllString(attr, ""), " ")
...@@ -269,7 +228,7 @@ func getAttrValueByAttr(attr string) (attrValue string) { ...@@ -269,7 +228,7 @@ func getAttrValueByAttr(attr string) (attrValue string) {
attrName = value attrName = value
} }
attrNumberStr := common.ToString(attrNumber * value64) attrNumberStr := common.ToString(attrNumber * value64)
attrValue = attrName + "€" + attrNumberStr result = attrName + "€" + attrNumberStr
break break
} }
} }
...@@ -279,57 +238,12 @@ func getAttrValueByAttr(attr string) (attrValue string) { ...@@ -279,57 +238,12 @@ func getAttrValueByAttr(attr string) (attrValue string) {
//再去找没有单位的对应属性 //再去找没有单位的对应属性
attrName, _ = redis.String(gredis.HGet("sku_map2", attr)) attrName, _ = redis.String(gredis.HGet("sku_map2", attr))
if attrName != "" { if attrName != "" {
attrValue = attrName + "€" + attr result = attrName + "€" + attr
}
return attrValue
}
//获取匹配的条件
func getQuery(attrs []string) (query *es.BoolQuery, shouldQueryNumber, mustQueryNumber int) {
//如果attrs为空,也要构建一个结果为空的查询,因为要使结果和bomItems数量对应起来
if len(attrs) == 0 {
attrs = []string{"€_€"}
}
var subQuery *es.TermQuery
var nestedQuery *es.NestedQuery
query = es.NewBoolQuery()
for _, attr := range attrs {
//还要判断是不是一个单位对应多个属性的
if strings.Contains(attr, "|") {
name := strings.Split(attr, "€")[0]
value := strings.Split(attr, "€")[1]
multiAttr := strings.Split(name, "|")
for _, temp := range multiAttr {
subQuery = es.NewTermQuery("attrs.attr_value", temp+"€"+value)
nestedQuery = es.NewNestedQuery("attrs", subQuery)
//目前一个单位对应多个属性的都是非必要属性
query.Should(nestedQuery)
shouldQueryNumber++
}
} else {
subQuery = es.NewTermQuery("attrs.attr_value", attr)
nestedQuery = es.NewNestedQuery("attrs", subQuery)
//封装是必须要完全满足
//构建必须要满足条件的列表
hasMustQuery := false
mustQueryUnitKeyWords := []string{"阻值(欧姆)", "容值", "电感", "封装"}
splitWords := strings.Split(attr, "€")
if len(splitWords) > 0 {
if php2go.InArray(splitWords[0], mustQueryUnitKeyWords) {
hasMustQuery = true
query.Must(nestedQuery)
mustQueryNumber++
}
}
if !hasMustQuery {
shouldQueryNumber++
query.Should(nestedQuery)
}
}
} }
return return result
} }
//获取需要检查的单位
func getNeedCheckUnit() (unitSlice []string) { func getNeedCheckUnit() (unitSlice []string) {
unitMapping := mapping.UnitValueMapping unitMapping := mapping.UnitValueMapping
for unit, _ := range unitMapping { for unit, _ := range unitMapping {
...@@ -338,31 +252,16 @@ func getNeedCheckUnit() (unitSlice []string) { ...@@ -338,31 +252,16 @@ func getNeedCheckUnit() (unitSlice []string) {
return return
} }
func getShouldMatchNumber(shouldQueryNumber, mustQueryNumber int) (shouldMatchNumber int) { //转成新约定的形式
//到底要符合多少个should,要根据shouldQueryNumber和mustQueryNumber来决定 func transformNew(attrs []string) []string {
//当必须条件有两个或者两个以上了(一般是封装+某个重要参数),should那边就可以放款限制,should可以为0 attrMapping := mapping.AttrBomTransformMapping
if mustQueryNumber >= 2 { for key, value := range attrMapping {
return for k, attr := range attrs {
} if strings.Contains(attr, key) {
//必须条件只有一个的前提下 attrs[k] = strings.Replace(attr, key, value, -1)
if mustQueryNumber == 1 { }
if shouldQueryNumber >= 6 {
shouldMatchNumber = 3
} else if shouldQueryNumber >= 4 {
shouldMatchNumber = 2
} else {
shouldMatchNumber = 1
}
}
//不存在必须条件
if mustQueryNumber == 0 {
if shouldQueryNumber >= 5 {
shouldMatchNumber = 3
} else if shouldQueryNumber >= 3 {
shouldMatchNumber = 2
} else {
shouldMatchNumber = 1
} }
} }
return
return attrs
} }
...@@ -89,10 +89,9 @@ func UpdateBomItem(bomId, bomItemId int) (err error) { ...@@ -89,10 +89,9 @@ func UpdateBomItem(bomId, bomItemId int) (err error) {
return err return err
} }
defer client.Stop() defer client.Stop()
//先去查询品牌映射,有映射关系的,就用映射关系得到的brand_id进行查询
bomItems, err = GetBrandMap(bomItems)
//匹配之前,去遍历bom_item,把没有型号名称但是有参数的bom_item进行型号补充 //匹配之前,去遍历bom_item,把没有型号名称但是有参数的bom_item进行型号补充
bomItems, err = MatchGoodsNameByAttrs(bomItems) bomItems, err = MatchGoodsNameByAttrs(bomItems)
//bomItems, err = MatchGoodsNameByAttrs(bomItems)
//第一次去精确匹配,没有再去模糊匹配 //第一次去精确匹配,没有再去模糊匹配
var goodsMapList []GoodsMap var goodsMapList []GoodsMap
goodsMapList, err = getUpdateGoodsData(bomId, bomItems, where.DeliveryType, where.Sort, client, true) goodsMapList, err = getUpdateGoodsData(bomId, bomItems, where.DeliveryType, where.Sort, client, true)
......
package logic
import (
"bom_server/configs"
"bom_server/internal/model"
"context"
"github.com/tidwall/gjson"
es "gopkg.in/olivere/elastic.v5"
"regexp"
"strings"
)
//和品牌映射有关的逻辑
func GetBrandMap(bomItems []model.BomItem) (result []model.BomItem, err error) {
client, err := es.NewClient(es.SetURL(configs.ESSetting.Url))
if err != nil {
return
}
index := "stand_brand"
search := client.MultiSearch().Index(index)
for _, bomItem := range bomItems {
search = searchBrandMap(bomItem, search)
}
res, err := search.Do(context.Background())
if err != nil {
return
}
if len(res.Responses) == 0 {
return
}
//因为是多重查询,所以会有多套结果
for key, responses := range res.Responses {
//有数据进行转换
if responses.Hits != nil {
var lyBrandIds []string
for _, hit := range responses.Hits.Hits {
res, _ := hit.Source.MarshalJSON()
lyIdArray := gjson.Get(string(res), "attrs.#.attr_brand_id").Array()
for _, id := range lyIdArray {
idSlice := strings.Split(id.String(), ",")
lyBrandIds = append(lyBrandIds, idSlice...)
}
bomItems[key].ZyBrandId = hit.Id
bomItems[key].ZyBrandName = gjson.Get(string(res), "stand_zy_brand_name").String()
}
bomItems[key].LyBrandIds = lyBrandIds
}
}
result = bomItems
return
}
//根据用户输入的品牌获取映射后的品牌,没有映射的话不变,有的话变
func searchBrandMap(bomItem model.BomItem, search *es.MultiSearchService) (result *es.MultiSearchService) {
query := getBrandMapQuery(bomItem)
source := es.NewSearchSource().Query(query)
source = source.From(0).Size(1)
searchRequest := es.NewSearchRequest().Source(source)
search.Add(searchRequest)
return search
}
//获取品牌映射搜索的查询条件
func getBrandMapQuery(bomItem model.BomItem) (query *es.BoolQuery) {
var subQuery *es.TermQuery
var nestedQuery *es.NestedQuery
query = es.NewBoolQuery()
brandName := bomItem.BrandName
brandName = strings.ToUpper(brandName)
//提取出纯中文
r, _ := regexp.Compile("[\u4e00-\u9fa5]+")
brandNameCn := r.FindString(brandName)
if brandNameCn != "" {
query.Should(es.NewMatchQuery("brand_name_cn", brandNameCn))
}
//提取出纯英文
re, _ := regexp.Compile("[A-Za-z0-9]+")
brandNameEn := re.FindString(brandName)
subQuery = es.NewTermQuery("attrs.attr_brand_name", brandNameEn)
nestedQuery = es.NewNestedQuery("attrs", subQuery)
query.Should(nestedQuery)
query.MinimumNumberShouldMatch(1)
return query
}
//
package logic
import (
"bom_server/internal/mapping"
"bom_server/internal/pkg/gredis"
"github.com/gomodule/redigo/redis"
"regexp"
)
//转换封装
func TransformEncap(encap string) (attrValue string) {
numberR, _ := regexp.Compile(mapping.PureNumberRegular)
pureNumber := numberR.FindString(encap)
//判断是多少位数字,如果是3位,则代表可能需要往前面补零
if len(pureNumber) == 3 {
encapCheck := "0" + pureNumber
//补全完以后,去sku_map2尝试获取值,如果存在的话,就代表是正确的封装
attrName, _ := redis.String(gredis.HGet("sku_map2", encapCheck))
if attrName != "" {
pureNumber = encapCheck
}
}
//再去找对应属性
attrValue = "封装" + "€" + pureNumber
return attrValue
}
...@@ -4,11 +4,7 @@ import ( ...@@ -4,11 +4,7 @@ import (
"bom_server/configs" "bom_server/configs"
"bom_server/internal/common" "bom_server/internal/common"
"bom_server/internal/model" "bom_server/internal/model"
"context"
"encoding/json"
"math" "math"
"regexp"
"strings"
"sync" "sync"
"github.com/prometheus/common/log" "github.com/prometheus/common/log"
...@@ -21,7 +17,6 @@ import ( ...@@ -21,7 +17,6 @@ import (
3.搜索匹配到以后,用goods_id去请求商品服务 3.搜索匹配到以后,用goods_id去请求商品服务
4.得到具体的商品数据以后,针对对应的商品进行修改 4.得到具体的商品数据以后,针对对应的商品进行修改
**/ **/
func MatchGoods(message model.BomMessage) (err error) { func MatchGoods(message model.BomMessage) (err error) {
//获取bom //获取bom
bomId := message.BomId bomId := message.BomId
...@@ -30,6 +25,7 @@ func MatchGoods(message model.BomMessage) (err error) { ...@@ -30,6 +25,7 @@ func MatchGoods(message model.BomMessage) (err error) {
return nil return nil
} }
bomItems := bom.BomItems bomItems := bom.BomItems
//每个协程处理的数量
var perGoDealNumber int var perGoDealNumber int
if configs.ApiSetting.Mode == "debug" { if configs.ApiSetting.Mode == "debug" {
perGoDealNumber = 200 perGoDealNumber = 200
...@@ -57,8 +53,10 @@ func MatchGoods(message model.BomMessage) (err error) { ...@@ -57,8 +53,10 @@ func MatchGoods(message model.BomMessage) (err error) {
bomData = bomItems[i : i+perGoDealNumber] bomData = bomItems[i : i+perGoDealNumber]
} }
go func() { go func() {
if err := SearchGoods(bomId, bomData, message.DeliveryType, message.Sort, &wg); err != nil { if len(bomData) != 0 {
log.Error(err) if err := SearchGoods(bomId, bomData, message.DeliveryType, message.Sort, &wg); err != nil {
log.Error(err)
}
} }
}() }()
} }
...@@ -69,32 +67,29 @@ func MatchGoods(message model.BomMessage) (err error) { ...@@ -69,32 +67,29 @@ func MatchGoods(message model.BomMessage) (err error) {
//去es搜索商品,得到对应的商品对应关系 //去es搜索商品,得到对应的商品对应关系
func SearchGoods(bomId int, bomItems []model.BomItem, deliveryType, sort int, wg *sync.WaitGroup) (err error) { func SearchGoods(bomId int, bomItems []model.BomItem, deliveryType, sort int, wg *sync.WaitGroup) (err error) {
client, err := es.NewClient(es.SetURL(configs.ESSetting.Url))
if err != nil {
panic(err)
}
defer func() { defer func() {
wg.Done() wg.Done()
client.Stop()
}() }()
if len(bomItems) == 0 {
return
}
//去除首尾空格 //去除首尾空格
bomItems = common.TrimBomItemSpace(bomItems) bomItems = common.TrimBomItemSpace(bomItems)
client, err := es.NewClient(es.SetURL(configs.ESSetting.Url)) //获取转换后的标准参数,或者是识别出参数列是否有型号
if err != nil { bomItems = GetStandardAttrs(bomItems)
panic(err)
}
defer client.Stop()
//先去查询品牌映射,有映射关系的,就用映射关系得到的brand_id进行查询
bomItems, err = GetBrandMap(bomItems)
//匹配之前,去遍历bom_item,把没有型号名称但是有参数的bom_item进行型号补充
bomItems, err = MatchGoodsNameByAttrs(bomItems)
//第一次先去精确匹配 //第一次先去精确匹配
goodsMapList, err := getUpdateGoodsData(bomId, bomItems, deliveryType, sort, client, true) goodsMapList, err := getUpdateGoodsData(bomId, bomItems, deliveryType, sort, client, true)
if err != nil { if err != nil {
return return
} }
//要删除已经精确匹配过的bomItem //要删除已经精确匹配过的bomItem,得到需要去模糊匹配的商品
var fuzzyBomItems []model.BomItem var fuzzyBomItems []model.BomItem
for _, bomItem := range bomItems { for _, bomItem := range bomItems {
if !checkInGoodsMap(bomItem, goodsMapList) { //不在精确匹配结果里面的,同时商品名称不能为空的
if !checkInGoodsMap(bomItem, goodsMapList) && bomItem.GoodsName != "" {
fuzzyBomItems = append(fuzzyBomItems, bomItem) fuzzyBomItems = append(fuzzyBomItems, bomItem)
} }
} }
...@@ -177,190 +172,13 @@ func getUpdateGoodsData(bomId int, bomItems []model.BomItem, deliveryType, sort ...@@ -177,190 +172,13 @@ func getUpdateGoodsData(bomId int, bomItems []model.BomItem, deliveryType, sort
return return
} }
index := configs.ESSetting.GoodsIndexName index := configs.ESSetting.GoodsIndexName
var ziyingGoodsMapList []GoodsMap
//如果是大陆收货(type=1),就要包含专卖,其中自营单独查 //如果是大陆收货(type=1),就要包含专卖,其中自营单独查
if deliveryType == 1 { index = index + ",zhuanmai,liexin_ziying"
//如果是综合排序(sort=1) goodsMapList, err = search(index, bomId, bomItems, deliveryType, sort, client, rawSearch)
if sort == 1 {
//先去自营查一遍
ziyingGoodsMapList, err = search("liexin_ziying", bomId, bomItems, deliveryType, sort, client, rawSearch)
if err != nil {
return nil, err
}
index = index + ",zhuanmai"
//查完以后去除已经匹配的自营商品,然后去搜索联营的商品
bomItems = removeZiyingMatchBomItem(ziyingGoodsMapList, bomItems)
var lianyingGoodsMapList []GoodsMap
if len(bomItems) != 0 {
lianyingGoodsMapList, _ = search(index, bomId, bomItems, deliveryType, sort, client, rawSearch)
}
goodsMapList = append(ziyingGoodsMapList, lianyingGoodsMapList...)
} else {
index = index + ",zhuanmai,liexin_ziying"
goodsMapList, err = search(index, bomId, bomItems, deliveryType, sort, client, rawSearch)
if err != nil {
return nil, err
}
}
} else {
index = index + ",zhuanmai,liexin_ziying"
goodsMapList, err = search(index, bomId, bomItems, deliveryType, sort, client, rawSearch)
if err != nil {
return nil, err
}
}
return
}
func removeZiyingMatchBomItem(ziyingGoodsMapList []GoodsMap, bomItems []model.BomItem) (result []model.BomItem) {
for _, bomItem := range bomItems {
if !checkInGoodsMap(bomItem, ziyingGoodsMapList) {
result = append(result, bomItem)
}
}
return
}
func search(index string, bomId int, bomItems []model.BomItem, deliveryType, sort int, client *es.Client, rawSearch bool) (goodsMapList []GoodsMap, err error) {
//先去自营查一遍
search := client.MultiSearch().Index(index)
searchFlag := false
//多重搜索,第一次先去精确匹配
for _, bom := range bomItems {
//如果是模糊查询,还要去截取字符串
if !rawSearch {
bom.GoodsName = common.SubKeyWordStr(bom.GoodsName)
}
//经过了最前面的参数匹配
//如果型号还是为空,则用参数去匹配,因为有可能参数里面填了型号
if bom.GoodsName == "" && bom.Attrs == "" {
continue
} else if bom.GoodsName == "" && bom.Attrs != "" {
bom.GoodsName = bom.Attrs
}
//模糊匹配之前要先去看这个bomItem的商品名称是否是由参数获取到的
//如果是的话,就不需要模糊匹配了,因为参数获取到的型号才是最符合参数的,如果再去模糊匹配,就不符合参数了
var paramsRawSearch bool
paramsRawSearch = rawSearch
if bom.IsGoodsNameByAttrs && rawSearch == false {
paramsRawSearch = true
}
//构建一个goods_name对应的bomItems列表
searchRequest := getSearchParams(index, bom, sort, paramsRawSearch)
searchFlag = true
search.Add(searchRequest)
}
//没有搜索条件的话,直接返回空值即可
if !searchFlag {
return nil, err
}
res, err := search.Do(context.Background())
if err != nil { if err != nil {
return return nil, err
}
if len(res.Responses) == 0 {
return
}
//因为是多重查询,所以会有多套结果
for key, responses := range res.Responses {
//有数据进行转换
if responses.Hits != nil {
for _, hit := range responses.Hits.Hits {
var goods model.Goods
err := json.Unmarshal(*hit.Source, &goods)
if err != nil {
return nil, err
}
if goods.GoodsName == "" {
break
}
var goodsMap GoodsMap
goodsMap.GoodsId = hit.Id
goodsMap.Amount = bomItems[key].Amount
goodsMap.Number = bomItems[key].Number
goodsMap.GoodsName = bomItems[key].GoodsName
goodsMap.BomItemId = bomItems[key].BomItemID
goodsMap.BomId = bomId
goodsMap.DeliveryType = deliveryType
goodsMapList = append(goodsMapList, goodsMap)
break
}
}
} }
return return
} }
//构建请求参数
func getSearchParams(index string, bomItem model.BomItem, sort int, flag bool) (searchRequest *es.SearchRequest) {
query := getTermQuery(index, bomItem, sort, flag)
source := es.NewSearchSource().Query(query)
if sort == 1 {
source.Sort("_score", false)
source.Sort("sort", false)
source.Sort("stock", false)
source.Sort("single_price", true)
}
//要去判断sort,sort=2是按照价格排序
if sort == 2 {
source.Sort("_score", false)
source.Sort("single_price", true)
//sort=3是按照库存排序
} else if sort == 3 {
source.Sort("_score", false)
source.Sort("stock", false)
}
source = source.From(0).Size(1)
searchRequest = es.NewSearchRequest().Source(source)
//fmt.Println(searchRequest.Body())
return searchRequest
}
//构建term条件
func getTermQuery(index string, bomItem model.BomItem, sort int, flag bool) (query *es.BoolQuery) {
query = es.NewBoolQuery()
if flag {
field := "auto_goods_name.raw"
replace, _ := regexp.Compile("[^A-Za-z0-9]+")
goodsName := replace.ReplaceAllString(bomItem.GoodsName, "")
goodsName = strings.ToUpper(goodsName)
//商品名称太短的,限制搜索
if len(goodsName) <= 3 {
query = query.Filter(es.NewTermQuery(field, "€_€"))
} else {
query = query.Filter(es.NewTermQuery(field, goodsName))
}
//判断是否存在brandName并且匹配不到对应的标准品牌
if bomItem.BrandName != "" {
bomItem.BrandName = strings.ToUpper(bomItem.BrandName)
query = query.Should(es.NewConstantScoreQuery(es.NewTermQuery("brand_name", bomItem.BrandName)).Boost(2))
}
//搜索库存
query = query.Should(es.NewConstantScoreQuery(es.NewRangeQuery("stock").Gte(bomItem.Number * bomItem.Amount)))
} else {
field := "auto_goods_name"
query = query.Must(es.NewTermQuery(field, bomItem.GoodsName))
}
//对品牌进行判断搜索,如果能匹配到对应的自营标准品牌(那么同时也有对应的联营品牌)
//还要去判断当前索引是否包含自营,不包含,直接跳过自营的brand_id
if strings.Contains(index, "liexin_ziying") {
query.Should(es.NewTermQuery("brand_id", bomItem.ZyBrandId))
}
query.Must(es.NewRangeQuery("stock").Gt(0))
if bomItem.ZyBrandId != "" {
for _, id := range bomItem.LyBrandIds {
query.Should(es.NewTermQuery("brand_id", id))
}
}
//按价格排序
if sort == 2 {
query = query.Filter(es.NewRangeQuery("single_price").Gt(0))
}
//库存排序
if sort == 3 {
query = query.Filter(es.NewRangeQuery("stock").Gt(0))
}
if configs.ApiSetting.Mode != "debug" {
query = query.Filter(es.NewTermQuery("status", 1))
}
return query
}
package logic
import (
"bom_server/configs"
"bom_server/internal/common"
"bom_server/internal/model"
"context"
"encoding/json"
"fmt"
es "gopkg.in/olivere/elastic.v5"
"regexp"
"strings"
)
func search(index string, bomId int, bomItems []model.BomItem, deliveryType, sort int, client *es.Client, rawSearch bool) (goodsMapList []GoodsMap, err error) {
//先去自营查一遍
search := client.MultiSearch().Index(index)
//是否已经搜索过标签
searchFlag := false
//多重搜索,第一次先去精确匹配
for _, bom := range bomItems {
//如果是模糊查询,还要去截取字符串
if !rawSearch {
bom.GoodsName = common.SubKeyWordStr(bom.GoodsName)
}
if bom.GoodsName == "" && bom.Attrs == "" {
continue
}
//模糊匹配之前要先去看这个bomItem的商品名称是否是由参数获取到的
//如果是的话,就不需要模糊匹配了,因为参数获取到的型号才是最符合参数的,如果再去模糊匹配,就不符合参数了
var paramsRawSearch bool
paramsRawSearch = rawSearch
if bom.IsGoodsNameByAttrs && rawSearch == false {
paramsRawSearch = true
}
//构建一个goods_name对应的bomItems列表
searchRequest := getSearchParams(index, bom, sort, paramsRawSearch)
searchFlag = true
search.Add(searchRequest)
}
//没有搜索条件的话,直接返回空值即可
if !searchFlag {
return nil, err
}
res, err := search.Do(context.Background())
if err != nil {
return
}
if len(res.Responses) == 0 {
return
}
//因为是多重查询,所以会有多套结果
for key, responses := range res.Responses {
//有数据进行转换
if responses.Hits != nil {
for _, hit := range responses.Hits.Hits {
var goods model.Goods
err := json.Unmarshal(*hit.Source, &goods)
if err != nil {
return nil, err
}
if goods.GoodsName == "" {
break
}
var goodsMap GoodsMap
goodsMap.GoodsId = hit.Id
goodsMap.Amount = bomItems[key].Amount
goodsMap.Number = bomItems[key].Number
goodsMap.GoodsName = bomItems[key].GoodsName
goodsMap.BomItemId = bomItems[key].BomItemID
goodsMap.BomId = bomId
goodsMap.DeliveryType = deliveryType
goodsMapList = append(goodsMapList, goodsMap)
break
}
}
}
return
}
//构建请求参数
func getSearchParams(index string, bomItem model.BomItem, sort int, flag bool) (searchRequest *es.SearchRequest) {
fmt.Println("商品名称 : ",bomItem.GoodsName)
fmt.Println("参数列表 : ",bomItem.AttrList)
fmt.Println("封装 : ",bomItem.Encap)
query := getTermQuery(bomItem, sort, flag)
source := es.NewSearchSource().Query(query)
if sort == 1 {
source.Sort("_score", false)
source.Sort("single_price", true)
}
//要去判断sort,sort=2是按照价格排序
if sort == 2 {
source.Sort("_score", false)
source.Sort("single_price", true)
//sort=3是按照库存排序
} else if sort == 3 {
source.Sort("_score", false)
source.Sort("stock", false)
}
source = source.From(0).Size(1)
searchRequest = es.NewSearchRequest().Source(source)
return searchRequest
}
//构建term条件
func getTermQuery(bomItem model.BomItem, sort int, flag bool) (query *es.BoolQuery) {
query = es.NewBoolQuery()
if flag {
field := "auto_goods_name.raw"
replace, _ := regexp.Compile("[^A-Za-z0-9]+")
goodsName := replace.ReplaceAllString(bomItem.GoodsName, "")
goodsName = strings.ToUpper(goodsName)
//商品名称太短的或者没有商品名称的,去搜索参数
if len(goodsName) <= 3 {
if len(bomItem.AttrList) > 0 {
var params []interface{}
for _, attr := range bomItem.AttrList {
params = append(params, attr)
}
query = query.Must(es.NewTermsQuery("attr_bom", params...))
} else {
query = query.Must(es.NewTermsQuery("attr_bom", "$_$"))
}
} else {
query = query.Filter(es.NewTermQuery(field, goodsName))
}
//判断是否存在brandName并且匹配不到对应的标准品牌
if bomItem.BrandName != "" {
bomItem.BrandName = strings.ToUpper(bomItem.BrandName)
query = query.Should(es.NewConstantScoreQuery(es.NewTermQuery("brand_name", bomItem.BrandName)).Boost(2))
}
//判断封装是否有,有的话,直接去搜索封装
if bomItem.Encap != "" {
query = query.Must(es.NewTermQuery("encap", bomItem.Encap))
}
//搜索库存
query = query.Should(es.NewConstantScoreQuery(es.NewRangeQuery("stock").Gte(bomItem.Number * bomItem.Amount)))
} else {
query = query.Must(es.NewTermQuery("auto_goods_name", bomItem.GoodsName))
}
//只显示库存大于0的数据
query.Must(es.NewRangeQuery("stock").Gt(0))
//按价格排序
if sort == 2 || sort == 1 {
query = query.Filter(es.NewRangeQuery("single_price").Gt(0))
}
//库存排序
if sort == 3 {
query = query.Filter(es.NewRangeQuery("stock").Gt(0))
}
if configs.ApiSetting.Mode != "debug" {
query = query.Filter(es.NewTermQuery("status", 1))
}
return query
}
...@@ -14,6 +14,7 @@ var KeywordRegular = map[string]string{ ...@@ -14,6 +14,7 @@ var KeywordRegular = map[string]string{
`(Mf|MF|mf)$`: "mF", `(Mf|MF|mf)$`: "mF",
`(Uh|uh|μh|uH|UH)$`: "μH", `(Uh|uh|μh|uH|UH)$`: "μH",
`(Mh|mh|mH|MH)$`: "mH", `(Mh|mh|mH|MH)$`: "mH",
`(Ma|ma|mA|MA)$`: "mA",
`(K)$`: "nF", `(K)$`: "nF",
`(V|v)`: "V", `(V|v)`: "V",
} }
......
package mapping
var AttrBomTransformMapping = map[string]string{
"阻值(欧姆)": "OM",
"容值": "DR",
"电感值": "DGZ",
"额定电压": "EDDY",
"额定电流": "EDDL",
"功率": "GL",
"直流电阻(内阻)": "ZLNZ",
"精度": "JD",
"封装": "FZ",
"温漂系数(介质材料)": "WPXS",
}
package model
\ No newline at end of file
...@@ -13,6 +13,7 @@ type BomItem struct { ...@@ -13,6 +13,7 @@ type BomItem struct {
Number int `json:"number"` Number int `json:"number"`
Amount int `json:"amount"` Amount int `json:"amount"`
Attrs string `json:"attrs"` Attrs string `json:"attrs"`
AttrList []string `json:"-"`
Encap string `json:"encap"` Encap string `json:"encap"`
// ItemStatus 匹配状态 1:等待匹配 2:可购现货 3:待询价 4:需要修正 // ItemStatus 匹配状态 1:等待匹配 2:可购现货 3:待询价 4:需要修正
ItemStatus int `json:"item_status"` ItemStatus int `json:"item_status"`
......
package main package main
import "bom_server/internal/logic" import (
"bom_server/configs"
"bom_server/internal/logic"
"bom_server/internal/model"
"bom_server/internal/pkg/gredis"
"flag"
"fmt"
)
func main() { func main() {
logic.ChangeUnit("100kr(1002) ") var path string
flag.StringVar(&path, "config", "C:/laragon/usr/go/src/bom_server/conf/config.ini", "../conf/config.ini")
flag.Parse()
configs.Setup(path)
model.Setup()
gredis.Setup()
//logic.ChangeUnit("10KΩ(1002) ") //logic.ChangeUnit("10KΩ(1002) ")
//logic.ChangeUnit("±1%") //logic.ChangeUnit("±1%")
result:=logic.TransformAttr("SMA(DO-214AC) ,SS34 肖特基二极管 40V/3A", "0603")
fmt.Println(result)
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment