Commit 8ee0512d by mushishixian

推荐接口

parent 2d80e9d5
*
!.gitignore
\ No newline at end of file
......@@ -12,6 +12,8 @@ api_url = http://192.168.2.232:60004
url = http://192.168.2.232:9200
urls = http://192.168.2.232:9200,http://192.168.2.232:9200
index_name = future,rochester,tme,verical,element14,digikey,chip1stop,aipco,arrow,alliedelec,avnet,mouser,zhuanmai,peigenesis,powell,rs,buerklin,liexin_ziying
search_supplier = future,rochester,tme,verical,element14,digikey,chip1stop,aipco,arrow,alliedelec,avnet,mouser,peigenesis,powell,rs,buerklin,zhuanmai
hk_delivery_type_supplier = future,rochester,tme,verical,element14,digikey,chip1stop,aipco,arrow,alliedelec,avnet,mouser,peigenesis,powell,rs,buerklin
[database]
user_name = root
......
......@@ -14,7 +14,13 @@ func init() {
WithMiddleware(Cors_Middleware()).
WithEndpoint(AutoSpuEndpoint(bomService)).
WithRequest(AutoSpuRequest()).
WithResponse(AutoSpuResponse()).Build("/autospu", "GET")
WithResponse(AutoSpuResponse()).Build("/autospu", "POST")
gin_.NewBuilder().WithService(bomService).
WithMiddleware(Check_Middleware()).
WithMiddleware(Cors_Middleware()).
WithEndpoint(RecommendEndpoint(bomService)).
WithRequest(RecommendRequest()).
WithResponse(RecommendResponse()).Build("/recommend", "POST")
}
//获取列表相关
......@@ -46,3 +52,32 @@ func AutoSpuResponse() gin_.DecodeResponseFunc {
return nil
}
}
//获取列表相关
func RecommendEndpoint(c *service.BomServiceImpl) gin_.Endpoint {
return func(context *gin.Context, request interface{}) (response interface{}, err error) {
rsp := &bom.RecommendResponse{}
err = c.Recommend(context, request.(*bom.RecommendRequest), rsp)
return rsp, err
}
}
//这个函数的作用是怎么处理请求
func RecommendRequest() gin_.EncodeRequestFunc {
return func(context *gin.Context) (i interface{}, e error) {
bReq := &bom.RecommendRequest{}
err := context.Bind(bReq) //使用的是post参数
if err != nil {
return nil, err
}
return bReq, nil
}
}
//这个函数作用是:怎么处理响应结果
func RecommendResponse() gin_.DecodeResponseFunc {
return func(context *gin.Context, res interface{}) error {
context.JSON(200, res)
return nil
}
}
......@@ -16,6 +16,7 @@ require (
github.com/prometheus/common v0.9.1
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/testify v1.5.1 // indirect
github.com/syyongx/php2go v0.9.4
github.com/tidwall/gjson v1.6.0
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 // indirect
golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect
......
package model
type ApiGoods struct {
GoodsID string `json:"goods_id"`
GoodsName string `json:"goods_name"`
GoodsType int `json:"goods_type"`
SupplierID int `json:"supplier_id"`
Moq int `json:"moq"`
Mpq int `json:"mpq"`
Stock int `json:"stock"`
HkDeliveryTime string `json:"hk_delivery_time"`
CnDeliveryTime string `json:"cn_delivery_time"`
LadderPrice []LadderPrice `json:"ladder_price"`
BrandName string `json:"brand_name"`
SupplierName string `json:"supplier_name"`
BrandID int `json:"brand_id"`
IsBuy int `json:"is_buy"`
Mpl int `json:"mpl"`
Status int `json:"status"`
Pdf string `json:"pdf"`
Encap string `json:"encap"`
AcType int `json:"ac_type"`
//ErpTax bool `json:"erp_tax"`
}
type LadderPrice struct {
Purchases int `json:"purchases"`
PriceUs float64 `json:"price_us"`
PriceCn float64 `json:"price_cn"`
PriceAc float64 `json:"price_ac"`
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package common
import (
"crypto/md5"
"encoding/hex"
"github.com/syyongx/php2go"
)
// Md5 md5()
......@@ -10,4 +11,25 @@ func Md5(str string) string {
hash := md5.New()
hash.Write([]byte(str))
return hex.EncodeToString(hash.Sum(nil))
}
//非精确匹配,字符串截取向下80%,5个字符以下不截,5-10个截一个,10-20个向下取80%,20个以上向下取70%
func SubKeyWordStr(str string) string {
strLen := len(str)
strLenFloat := float64(strLen)
if strLen < 5 {
return str
}
if strLen >= 5 && strLen <= 10 {
str = php2go.Substr(str, 0, strLen-1)
}
if strLen > 10 && strLen <= 20 {
num := php2go.Floor(strLenFloat * 0.2)
str = php2go.Substr(str, 0, strLen-int(num))
}
if strLen > 20 {
num := php2go.Floor(strLenFloat * 0.3)
str = php2go.Substr(str, 0, strLen-int(num))
}
return str
}
\ No newline at end of file
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: goods.proto
package goods
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
......@@ -5,10 +5,6 @@ service BomService {
rpc AutoSpu(AutoSpuRequest) returns (AutoSpuResponse);
}
message GoodsNameModel{
string goods_name = 1;
}
message AutoSpuRequest {
// @inject_tag: uri:"goods_name"
string goods_name = 1;
......@@ -19,5 +15,94 @@ message AutoSpuResponse{
int32 error_code = 1;
// @inject_tag: json:"error_message"
string error_message = 2;
// @inject_tag: json:"data"
repeated string data = 3;
}
message RecommendRequest{
// @inject_tag: form:"goods_name"
string goods_name = 1;
// @inject_tag: form:"num"
int32 num = 2;
// @inject_tag: form:"delivery_type"
int32 delivery_type = 3;
// @inject_tag: form:"flag"
int32 flag = 4;
// @inject_tag: form:"p"
int32 p = 5;
// @inject_tag: form:"offset"
int32 offset = 6;
}
message ResponseData{
int64 total = 1;
int32 flag = 2;
repeated GoodsModel data = 3;
}
message RecommendResponse{
// @inject_tag: json:"error_code"
int32 error_code = 1;
// @inject_tag: json:"error_message"
string error_message = 2;
// @inject_tag: json:"data"
ResponseData data = 3;
}
message OTHER_ATTRS {
string gross_wegiht = 1;
}
message LADDER_PRICE {
int64 purchases = 1;
float price_cn = 2;
float price_us = 3;
float price_ac = 4;
}
message GoodsModel {
OTHER_ATTRS other_attrs = 1;
int64 pick_type = 2;
string barcode = 3;
string goods_id = 4;
int64 goods_type = 5;
int64 supplier_id = 6;
int64 brand_id = 7;
int64 class_id1 = 8;
int64 class_id2 = 9;
string goods_name = 10;
int64 status = 11;
string encoded = 12;
string encap = 13;
int64 packing = 14;
int64 goods_unit = 15;
bool goods_images = 16;
string pdf = 17;
string goods_brief = 18;
int64 moq = 19;
int64 mpq = 20;
repeated LADDER_PRICE ladder_price = 21;
int64 update_time = 22;
string sku_name = 23;
int64 mpl = 24;
int64 stock = 25;
string attrs = 26;
string cost = 27;
string new_cost = 28;
int64 supplier_stock = 29;
int64 self_supplier_type = 30;
string cn_delivery_time = 31;
string brand_name = 32;
string supplier_name = 33;
string goods_unit_name = 34;
string packing_name = 35;
string mpq_unit_name = 36;
int64 ac_type = 37;
int64 allow_coupon = 38;
string class_id1_name = 39;
string class_id2_name = 40;
int64 is_buy = 41;
string hk_delivery_type = 42;
}
\ No newline at end of file
syntax = "proto3";
package goods;
message OTHER_ATTRS {
string gross_wegiht = 1;
}
message LADDER_PRICE {
int64 purchases = 1;
float price_cn = 2;
float price_us = 3;
float price_ac = 4;
}
message GoodsModel {
OTHER_ATTRS other_attrs = 1;
int64 pick_type = 2;
string barcode = 3;
string goods_id = 4;
int64 goods_type = 5;
int64 supplier_id = 6;
int64 brand_id = 7;
int64 class_id1 = 8;
int64 class_id2 = 9;
string goods_name = 10;
int64 status = 11;
string encoded = 12;
string encap = 13;
int64 packing = 14;
int64 goods_unit = 15;
bool goods_images = 16;
bool pdf = 17;
string goods_brief = 18;
int64 moq = 19;
int64 mpq = 20;
repeated LADDER_PRICE ladder_price = 21;
int64 update_time = 22;
string sku_name = 23;
int64 mpl = 24;
int64 stock = 25;
string attrs = 26;
string cost = 27;
string new_cost = 28;
int64 supplier_stock = 29;
int64 self_supplier_type = 30;
string cn_delivery_time = 31;
string brand_name = 32;
string supplier_name = 33;
string goods_unit_name = 34;
string packing_name = 35;
string mpq_unit_name = 36;
int64 ac_type = 37;
int64 allow_coupon = 38;
string class_id1_name = 39;
string class_id2_name = 40;
int64 is_buy = 41;
string hk_delivery_type = 42;
}
\ No newline at end of file
......@@ -4,19 +4,15 @@ import (
"context"
"github.com/prometheus/common/log"
"github.com/tidwall/gjson"
elastic "gopkg.in/olivere/elastic.v5"
"gopkg.in/olivere/elastic.v5"
"regexp"
"search_server/dao"
"search_server/pkg/common"
"search_server/pkg/config"
"search_server/pkg/es"
"search_server/protopb/bom"
. "search_server/protopb/course"
"strings"
)
//func NewCourseModel(id int32, name string) *CourseModel {
// return &CourseModel{CourseId: id, CourseName: name}
//}
type BomServiceImpl struct{}
func (bs *BomServiceImpl) AutoSpu(ctx context.Context, req *bom.AutoSpuRequest, rsp *bom.AutoSpuResponse) error {
......@@ -25,20 +21,14 @@ func (bs *BomServiceImpl) AutoSpu(ctx context.Context, req *bom.AutoSpuRequest,
return nil
}
func (bs *BomServiceImpl) GetDetail(ctx context.Context, req *DetailRequest, rsp *DetailResponse) error {
//只取课程详细
if req.FetchType == 0 || req.FetchType == 1 || req.FetchType == 3 {
if err := dao.GetCourseDetail(int(req.CourseId)).Find(rsp.Course).Error; err != nil {
return err
}
}
//只取计数表详细
if req.FetchType == 2 || req.FetchType == 3 {
if err := dao.GetCourseCounts(int(req.CourseId)).Find(&rsp.Counts).Error; err != nil {
return err
}
func (bs *BomServiceImpl) Recommend(ctx context.Context, req *bom.RecommendRequest, rsp *bom.RecommendResponse) error {
if req.GoodsName == "" || req.Flag == 0 {
rsp.ErrorCode = 101
rsp.ErrorMessage = "参数不全"
return nil
}
recommendData := Recommend(req)
rsp.Data = recommendData
return nil
}
......@@ -78,3 +68,114 @@ func getTermQuery(goodsName string) (query *elastic.BoolQuery) {
query.MustNot(elastic.NewTermQuery("brand_id", 0))
return query
}
//推荐商品搜索
func Recommend(req *bom.RecommendRequest) (rsp *bom.ResponseData) {
//转换请求参数
req = changeRecommendReq(req)
//获取需要请求的索引
index := getRecommendSearchIndex(req)
//是否是精确匹配
isRawSearch := false
if req.Flag == 3 {
isRawSearch = true
}
//获取es的请求参数
queryJson := getRecommendSearchParams(isRawSearch, req)
result, err := es.CurlES(index, queryJson)
if err != nil {
log.Error(err)
}
//获取需要的数据
total := gjson.Get(result, "hits.total").Int()
var response bom.ResponseData
response.Total = total
//获取goods_id列表去商品服务获取商品
list := gjson.Get(result, "hits.hits.#._source").Array()
var goodsIdList []string
var goodsIdListStr string
for _, goods := range list {
goodsId := gjson.Get(goods.String(), "goods_id").String()
goodsIdList = append(goodsIdList, goodsId)
}
goodsIdListStr = strings.Join(goodsIdList, ",")
goodsList, err := GetGoodsInfo(goodsIdListStr)
response.Data = goodsList
response.Flag = req.Flag
return &response
}
//处理recommend接口的请求参数
func changeRecommendReq(req *bom.RecommendRequest) (res *bom.RecommendRequest) {
//设置默认值
if req.Num == 0 {
req.Num = 1
}
if req.P == 0 {
req.P = 1
}
if !(req.P > 1) {
req.Flag = 3
}
//转换处理商品名称
replace, _ := regexp.Compile("[^A-Za-z0-9]+")
req.GoodsName = replace.ReplaceAllString(req.GoodsName, "")
req.GoodsName = strings.ToUpper(req.GoodsName)
if req.Flag == 2 {
//截取字符后再精确匹配
req.GoodsName = common.SubKeyWordStr(req.GoodsName)
}
return req
}
//获取recommend接口需要请求的索引
func getRecommendSearchIndex(req *bom.RecommendRequest) (index string) {
index = config.Get("es.hk_delivery_type_supplier").String()
//如果是内地收货的情况下
if req.DeliveryType == 1 {
index = index + ",liexin_ziying,zhuanmai"
}
return
}
//获取请求es的参数
func getRecommendSearchParams(isRawSearch bool, req *bom.RecommendRequest) (result string) {
result = getBomTermQuery(req.GoodsName, "", req.Num, isRawSearch)
return
}
//获取bom单的term查询
func getBomTermQuery(goodsName, brandName string, number int32, isRawSearch bool) (result string) {
query := elastic.NewBoolQuery()
if isRawSearch {
field := "auto_goods_name.raw"
replace, _ := regexp.Compile("[^A-Za-z0-9]+")
goodsName := replace.ReplaceAllString(goodsName, "")
goodsName = strings.ToUpper(goodsName)
//搜索商品名称
query = query.Filter(elastic.NewTermQuery(field, goodsName))
//判断是否存在brandName,存在就去搜索brandName
if brandName != "" {
brandName = strings.ToUpper(brandName)
query = query.Should(elastic.NewConstantScoreQuery(elastic.NewTermQuery("brand_name", brandName)).Boost(2))
}
//搜索库存
query = query.Should(elastic.NewConstantScoreQuery(elastic.NewRangeQuery("stock").Gte(number)))
} else {
field := "auto_goods_name"
query = query.Must(elastic.NewTermQuery(field, goodsName))
}
//query = query.Filter(elastic.NewTermQuery("status", 1))
source := elastic.NewSearchSource().Query(query)
source.From(0)
if isRawSearch {
source.Size(100)
} else {
source.Size(1)
}
source.Sort("_score", false).Sort("sort", false).Sort("single_price", true)
queryRequest := elastic.NewSearchRequest().Source(source)
result, _ = queryRequest.Body()
return result
}
package service
import (
"github.com/imroc/req"
"github.com/tidwall/gjson"
"search_server/pkg/config"
"search_server/protopb/bom"
)
func GetGoodsInfo(goodsIdsStr string) (goodsList []*bom.GoodsModel, err error) {
goodsServerUrl := config.Get("goods.api_url").String()
params := req.Param{
"goods_id": goodsIdsStr,
}
//fmt.Println(goodsIdsStr)
resp, err := req.Post(goodsServerUrl+"/synchronization", params)
if err != nil {
return
}
//先判断返回的data是不是字典,不是字典代表可能是返回字符串了
if gjson.Get(resp.String(), "data").IsObject() {
for _, data := range gjson.Get(resp.String(), "data").Map() {
//还要去判断是否是bool
if data.IsObject() {
var goods bom.GoodsModel
goods.GoodsName = data.Get("goods_name").String()
goods.GoodsId = data.Get("goods_id").String()
goods.BrandId = data.Get("goods_id").Int()
goods.Pdf = data.Get("pdf").String()
goods.Stock = data.Get("stock").Int()
goods.Mpq = data.Get("mpq").Int()
goods.Moq = data.Get("moq").Int()
goods.SupplierName = data.Get("supplier_name").String()
goods.BrandName = data.Get("brand_name").String()
goods.HkDeliveryType = data.Get("hk_delivery_time").String()
goods.CnDeliveryTime = data.Get("cn_delivery_time").String()
goods.IsBuy = data.Get("is_buy").Int()
goods.Mpl = data.Get("mpl").Int()
goods.Encap = data.Get("encap").String()
goods.SupplierId = data.Get("supplier_id").Int()
goods.Status = data.Get("status").Int()
goods.GoodsType = data.Get("goods_type").Int()
goods.AcType = data.Get("ac_type").Int()
var ladderPrice []*bom.LADDER_PRICE
for _, price := range data.Get("ladder_price").Array() {
var ladder bom.LADDER_PRICE
ladder = bom.LADDER_PRICE{
Purchases: price.Get("purchases").Int(),
PriceUs: float32(price.Get("price_us").Float()),
PriceCn: float32(price.Get("price_cn").Float()),
PriceAc: float32(price.Get("price_ac").Float()),
}
ladderPrice = append(ladderPrice, &ladder)
}
goods.LadderPrice = ladderPrice
goodsList = append(goodsList, &goods)
}
}
}
return
}
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