Commit a22aff01 by 刘栋

UDI-规则三和规则四

parent f6e2f9eb
No preview for this file type
package com.infynova.udi.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.methods.AlwaysUpdateSomeColumnById;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* @author liudong
* 2024/5/15 17:12
* @version 1.0
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
@Bean
public ISqlInjector sqlInjector() {
return new DefaultSqlInjector() {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new InsertBatchSomeColumn());
methodList.add(new AlwaysUpdateSomeColumnById());
return methodList;
}
};
}
}
...@@ -157,5 +157,8 @@ public class MatchTemp { ...@@ -157,5 +157,8 @@ public class MatchTemp {
@ApiModelProperty(value = "修改时间") @ApiModelProperty(value = "修改时间")
private LocalDateTime updateTime; private LocalDateTime updateTime;
@ApiModelProperty(value = "来源规则:1、2、3、4")
private Integer source;
} }
...@@ -2,6 +2,7 @@ package com.infynova.udi.entity; ...@@ -2,6 +2,7 @@ package com.infynova.udi.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
...@@ -17,6 +18,7 @@ import java.time.LocalDateTime; ...@@ -17,6 +18,7 @@ import java.time.LocalDateTime;
*/ */
@Data @Data
@ApiModel(value="udi", description="") @ApiModel(value="udi", description="")
@TableName(value = "product")
public class Udi implements Serializable { public class Udi implements Serializable {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
......
...@@ -17,4 +17,6 @@ public class UdiMatchRateVo extends Udi { ...@@ -17,4 +17,6 @@ public class UdiMatchRateVo extends Udi {
private BigDecimal matchRatio; private BigDecimal matchRatio;
@ApiModelProperty(value = "输入值") @ApiModelProperty(value = "输入值")
private String userItem; private String userItem;
@ApiModelProperty(value = "来源规则:1、2、3、4")
private Integer source;
} }
...@@ -139,10 +139,17 @@ ...@@ -139,10 +139,17 @@
<dependency> <dependency>
<groupId>com.infynova</groupId> <groupId>com.infynova</groupId>
<artifactId>saas-ucpm-api</artifactId> <artifactId>saas-ucpm-api</artifactId>
<version>1.0.0</version> <version>4.1.1</version>
<scope>system</scope> <scope>system</scope>
<systemPath>${project.basedir}/../libs/saas-ucpm-api-1.0.0.jar</systemPath> <systemPath>${project.basedir}/../libs/saas-ucpm-api-1.0.0.jar</systemPath>
</dependency> </dependency>
<dependency>
<groupId>org.simmetrics</groupId>
<artifactId>simmetrics-core</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/../libs/simmetrics-core-4.1.1.jar</systemPath>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
...@@ -7,6 +7,7 @@ import com.infynova.udi.service.helper.EsSearchHelper; ...@@ -7,6 +7,7 @@ import com.infynova.udi.service.helper.EsSearchHelper;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.client.indices.CreateIndexResponse;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
...@@ -46,15 +47,15 @@ public class UdiEsController { ...@@ -46,15 +47,15 @@ public class UdiEsController {
@ApiOperationSupport(order = 400) @ApiOperationSupport(order = 400)
@ApiOperation(value = "searchThree", notes = "searchThree") @ApiOperation(value = "searchThree", notes = "searchThree")
@PostMapping("searchThree") @PostMapping("searchThree")
public Object searchThree(@RequestParam(value = "companyName", required = false) String companyName, public SearchResponse searchThree(@RequestParam(value = "companyName", required = false) String companyName,
@RequestParam(value = "productFactoryCode", required = false) String productFactoryCode){ @RequestParam(value = "productFactoryCode", required = false) String productFactoryCode){
return esSearchHelper.searchThree(companyName,productFactoryCode); return esSearchHelper.searchThree(companyName,productFactoryCode);
} }
@ApiOperationSupport(order = 500) @ApiOperationSupport(order = 500)
@ApiOperation(value = "searchFour", notes = "searchFour") @ApiOperation(value = "searchFour", notes = "searchFour")
@PostMapping("searchFour") @PostMapping("searchFour")
public Object searchFour(@RequestParam(value = "brandName", required = false) String brandName, public SearchResponse searchFour(@RequestParam(value = "brandName", required = false) String brandName,
@RequestParam(value = "productName", required = false) String productName, @RequestParam(value = "productName", required = false) String productName,
@RequestParam(value = "specification", required = false) String specification, @RequestParam(value = "specification", required = false) String specification,
@RequestParam(value = "model", required = false) String model){ @RequestParam(value = "model", required = false) String model){
......
...@@ -3,27 +3,19 @@ package com.infynova.udi.mapper; ...@@ -3,27 +3,19 @@ package com.infynova.udi.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.infynova.udi.dto.UdiListQry; import com.infynova.udi.dto.UdiListQry;
import com.infynova.udi.entity.Udi;
import com.infynova.udi.mapper.base.SuperMapper;
import com.infynova.udi.vo.UdiMatchRateVo; import com.infynova.udi.vo.UdiMatchRateVo;
import com.infynova.udi.vo.UdiVo; import com.infynova.udi.vo.UdiVo;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
public interface UdiMapper { public interface UdiMapper extends SuperMapper<Udi> {
Page<UdiVo> getUdiPage(IPage page, @Param("query") UdiListQry udiListQry); Page<UdiVo> getUdiPage(IPage page, @Param("query") UdiListQry udiListQry);
List<UdiVo> getUdiList(@Param("query") UdiListQry udiListQry); List<UdiVo> getUdiList(@Param("query") UdiListQry udiListQry);
Page<UdiVo> getUdi(IPage page, @Param("udi") String udiCode,
@Param("yiBaoCode") String yiBaoCode,
@Param("companyName") String companyName,
@Param("productFactoryCode") String productFactoryCode,
@Param("brandName") String brandName,
@Param("productName") String productName,
@Param("specification") String specification,
@Param("model") String model
);
List<UdiMatchRateVo> getUdiCodeRegex(@Param("udiCode") String udiCode, @Param("udiCodeList") List<String> udiCodeList); List<UdiMatchRateVo> getUdiCodeRegex(@Param("udiCode") String udiCode, @Param("udiCodeList") List<String> udiCodeList);
List<UdiMatchRateVo> getYiBaoCodeRegex(@Param("yiBaoCode") String yiBaoCode, @Param("yiBaoCodeList") List<String> yiBaoCodeList); List<UdiMatchRateVo> getYiBaoCodeRegex(@Param("yiBaoCode") String yiBaoCode, @Param("yiBaoCodeList") List<String> yiBaoCodeList);
......
package com.infynova.udi.service.helper; package com.infynova.udi.service.helper;
import com.infynova.udi.mapper.UdiMapper; import com.infynova.udi.mapper.UdiMapper;
import com.infynova.udi.vo.UdiMatchRateVo;
import com.infynova.udi.vo.UdiVo; import com.infynova.udi.vo.UdiVo;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkRequest;
...@@ -27,15 +29,15 @@ import org.elasticsearch.common.xcontent.XContentBuilder; ...@@ -27,15 +29,15 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*; import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch; import org.springframework.util.StopWatch;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.math.BigDecimal;
import java.util.List; import java.util.*;
import java.util.Map;
/** /**
* @author liudong * @author liudong
...@@ -186,14 +188,22 @@ public class EsSearchHelper { ...@@ -186,14 +188,22 @@ public class EsSearchHelper {
} }
@SneakyThrows @SneakyThrows
public Object searchThree(String companyName,String productFactoryCode){ public SearchResponse searchThree(String companyName,String productFactoryCode){
if(StringUtils.isBlank(companyName) && StringUtils.isBlank(productFactoryCode)){
return null;
}
SearchRequest searchRequest = new SearchRequest(INDEX_NAME); SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
// 构建查询条件 // 构建查询条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery() BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
.should(new MatchQueryBuilder("companyName", companyName)) if(StringUtils.isNotBlank(companyName)){
.should(new TermQueryBuilder("companyName.keyword", companyName)) boolQueryBuilder.should(new MatchQueryBuilder("companyName", companyName))
.should(new MatchQueryBuilder("productFactoryCode", productFactoryCode)) .should(new TermQueryBuilder("companyName.keyword", companyName));
.should(new TermQueryBuilder("productFactoryCode.keyword", productFactoryCode)); }
// boost 倾向性:查询时倾向于productFactoryCode
if(StringUtils.isNotBlank(productFactoryCode)){
boolQueryBuilder.should(new MatchQueryBuilder("productFactoryCode", productFactoryCode).boost(2))
.should(new TermQueryBuilder("productFactoryCode.keyword", productFactoryCode).boost(2));
}
// 构建搜索源 // 构建搜索源
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(boolQueryBuilder); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(boolQueryBuilder);
...@@ -205,19 +215,59 @@ public class EsSearchHelper { ...@@ -205,19 +215,59 @@ public class EsSearchHelper {
return searchResponse; return searchResponse;
} }
/**
* 规则三
* @param companyName 企业名称
* @param productFactoryCode 产品厂家编码
*/
public List<UdiMatchRateVo> threeQuery(String companyName, String productFactoryCode){
List<UdiMatchRateVo> resultList = new ArrayList<>();
SearchResponse searchResponse = searchThree(companyName, productFactoryCode);
if(Objects.isNull(searchResponse)){
return new ArrayList<>();
}
// 处理搜索结果
SearchHit[] searchHits = searchResponse.getHits().getHits();
for (SearchHit hit : searchHits) {
UdiMatchRateVo udiMatchRateVo = new UdiMatchRateVo();
Long idQuery = Long.valueOf(hit.getSourceAsMap().get("id").toString());
String companyNameQuery = Optional.ofNullable(hit.getSourceAsMap().get("companyName")).orElse("").toString();
String productFactoryCodeQuery = Optional.ofNullable(hit.getSourceAsMap().get("productFactoryCode")).orElse("").toString();
udiMatchRateVo.setId(idQuery);
udiMatchRateVo.setCompanyName(companyNameQuery);
udiMatchRateVo.setProductFactoryCode(productFactoryCodeQuery);
resultList.add(udiMatchRateVo);
}
return resultList;
}
@SneakyThrows @SneakyThrows
public Object searchFour(String brandName,String productName,String specification,String model){ public SearchResponse searchFour(String brandName,String productName,String specification,String model){
if(StringUtils.isBlank(brandName)
&& StringUtils.isBlank(productName)
&& StringUtils.isBlank(specification)
&& StringUtils.isBlank(model) ){
return null;
}
SearchRequest searchRequest = new SearchRequest(INDEX_NAME); SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
// 构建查询条件 // 构建查询条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery() BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
.should(new MatchQueryBuilder("brandName", brandName)) if(StringUtils.isNotBlank(brandName)){
.should(new TermQueryBuilder("brandName.keyword", brandName)) boolQueryBuilder.should(new MatchQueryBuilder("brandName", brandName))
.should(new MatchQueryBuilder("productName", productName)) .should(new TermQueryBuilder("brandName.keyword", brandName));
.should(new TermQueryBuilder("productName.keyword", productName)) }
.should(new MatchQueryBuilder("specification", specification)) if(StringUtils.isNotBlank(productName)){
.should(new TermQueryBuilder("specification.keyword", specification)) boolQueryBuilder.should(new MatchQueryBuilder("productName", productName))
.should(new MatchQueryBuilder("model", model)) .should(new TermQueryBuilder("productName.keyword", productName));
.should(new TermQueryBuilder("model.keyword", model)); }
if(StringUtils.isNotBlank(specification)){
boolQueryBuilder.should(new MatchQueryBuilder("specification", specification))
.should(new TermQueryBuilder("specification.keyword", specification));
}
if(StringUtils.isNotBlank(model)){
boolQueryBuilder.should(new MatchQueryBuilder("model", model))
.should(new TermQueryBuilder("model.keyword", model));
}
// 构建搜索源 // 构建搜索源
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(boolQueryBuilder); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(boolQueryBuilder);
...@@ -228,4 +278,34 @@ public class EsSearchHelper { ...@@ -228,4 +278,34 @@ public class EsSearchHelper {
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
return searchResponse; return searchResponse;
} }
/**
* 规则四
* @param brandName
* @param productName
* @param specification
* @param model
* @return
*/
public List<UdiMatchRateVo> fourQuery(String brandName, String productName, String specification, String model){
List<UdiMatchRateVo> resultList = new ArrayList<>();
SearchResponse searchResponse = searchFour(brandName, productName, specification, model);
// 处理搜索结果
SearchHit[] searchHits = searchResponse.getHits().getHits();
for (SearchHit hit : searchHits) {
UdiMatchRateVo udiMatchRateVo = new UdiMatchRateVo();
Long idQuery = Long.valueOf(hit.getSourceAsMap().get("id").toString());
String brandNameQuery = Optional.ofNullable(hit.getSourceAsMap().get("brandName")).orElse("").toString();
String productNameQuery = Optional.ofNullable(hit.getSourceAsMap().get("productName")).orElse("").toString();
String specificationQuery = Optional.ofNullable(hit.getSourceAsMap().get("specification")).orElse("").toString();
String modelQuery = Optional.ofNullable(hit.getSourceAsMap().get("model")).orElse("").toString();
udiMatchRateVo.setId(idQuery);
udiMatchRateVo.setBrandName(brandNameQuery);
udiMatchRateVo.setProductName(productNameQuery);
udiMatchRateVo.setSpecification(specificationQuery);
udiMatchRateVo.setModel(modelQuery);
resultList.add(udiMatchRateVo);
}
return resultList;
}
} }
//package com.infynova.udi.service.helper;
//
//import lombok.extern.slf4j.Slf4j;
//import org.apache.commons.lang3.StringUtils;
//import org.wltea.analyzer.core.IKSegmenter;
//import org.wltea.analyzer.core.Lexeme;
//
//import java.io.StringReader;
//import java.util.ArrayList;
//import java.util.List;
//
///**
// * @author liudong
// * 2024/3/14 18:27
// * @version 1.0
// */
//@Slf4j
//public class IKAnalyzerSupport {
//
// /**
// * IK分词
// * @param target
// * @return
// */
// public static List<String> iKSegmenterToList(String target) throws Exception {
// if (StringUtils.isEmpty(target)){
// return new ArrayList<>();
// }
// List<String> result = new ArrayList<>();
// StringReader sr = new StringReader(target);
// // false:关闭智能分词 (对分词的精度影响较大)
// IKSegmenter ik = new IKSegmenter(sr, true);
// Lexeme lex;
// while((lex=ik.next())!=null) {
// String lexemeText = lex.getLexemeText();
// result.add(lexemeText);
// }
// return result;
// }
//}
package com.infynova.udi.service.helper;
import com.infynova.udi.entity.Udi;
import com.infynova.udi.mapper.UdiMapper;
import com.infynova.udi.vo.UdiMatchRateVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.simmetrics.StringMetric;
import org.simmetrics.metrics.Levenshtein;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author liudong
* 2024/5/15 14:12
* @version 1.0
*/
@Slf4j
@Component("matchESHelper")
public class MatchESHelper {
@Resource
private EsSearchHelper esSearchHelper;
@Resource
private UdiMapper udiMapper;
private static final BigDecimal ONE_HUNDRED_RATE = new BigDecimal("100");
private static final BigDecimal NINE_RATE = new BigDecimal("90");
/**
* 规则三
*/
public List<UdiMatchRateVo> three(String companyName,String productFactoryCode){
List<UdiMatchRateVo> udiMatchRateVos = esSearchHelper.threeQuery(companyName, productFactoryCode);
if(CollectionUtils.isEmpty(udiMatchRateVos)){
return udiMatchRateVos;
}
List<Long> idList = udiMatchRateVos.stream().map(UdiMatchRateVo::getId).collect(Collectors.toList());
List<Udi> udiList = udiMapper.selectBatchIds(idList);
Map<Long, Udi> udiMap = udiList.stream().collect(Collectors.toMap(Udi::getId, Function.identity()));
for (UdiMatchRateVo udiMatchRateVo : udiMatchRateVos) {
Long id = udiMatchRateVo.getId();
if(udiMap.containsKey(id)){
Udi udi = udiMap.get(id);
BeanUtils.copyProperties(udi,udiMatchRateVo);
// todo 如何去计算匹配率
String companyNameUdi = udi.getCompanyName();
String productFactoryCodeUdi = udi.getProductFactoryCode();
BigDecimal matchRatio = this.matchThree(companyName, productFactoryCode, companyNameUdi, productFactoryCodeUdi);
udiMatchRateVo.setMatchRatio(matchRatio);
}else{
// 没匹配成功
udiMatchRateVo.setMatchRatio(BigDecimal.ZERO);
}
}
return udiMatchRateVos;
}
/**
* 规则三 - 计算匹配率
* @param companyName excel中的companyName
* @param productFactoryCode excel中的productFactoryCode
* @param companyNameUdi 找到的companyName
* @param productFactoryCodeUdi 找到的productFactoryCode
* @return 匹配率
*/
private BigDecimal matchThree(String companyName,String productFactoryCode,String companyNameUdi,String productFactoryCodeUdi){
if(StringUtils.isBlank(companyName)){
// 如果【公司名称】为空,则只判断厂家产品货号/编号
if(StringUtils.equals(productFactoryCode,productFactoryCodeUdi)){
// 如果这个编码对得上,则90%;
return NINE_RATE;
}else{
// 匹配率 关键~!!
StringMetric metric = new Levenshtein();
float result = metric.compare(productFactoryCode, productFactoryCodeUdi);
result = result*100;
return new BigDecimal(result);
}
}else if(StringUtils.isBlank(productFactoryCode)){
// 如果【厂家产品货号/编号】为空,则只判断公司名称
if(StringUtils.equals(companyName,companyNameUdi)){
// 如果这个编码对得上,则90%;
return NINE_RATE;
}else{
// 匹配率 关键~!!
StringMetric metric = new Levenshtein();
float result = metric.compare(companyName, companyNameUdi);
result = result*100;
return new BigDecimal(result);
}
}else{
// 两者都不为空
// Levenshtein距离算法 算出匹配率
StringMetric metric = new Levenshtein();
double productFactoryCodeWeight = 0.6;
double companyNameWeight = 0.4;
// 如果productFactoryCode相等 计算匹配率倾向于productFactoryCode
if(StringUtils.equals(productFactoryCode, productFactoryCodeUdi)){
productFactoryCodeWeight = 0.8;
companyNameWeight = 0.2;
}
float productFactoryCodeResult = metric.compare(productFactoryCode, productFactoryCodeUdi);
float companyNameResult = metric.compare(companyName, companyNameUdi);
// 权重,偏向productFactoryCode
double result = PercentageCalculatorUtil.calculateWeightedAverageRate(productFactoryCodeResult, companyNameResult, productFactoryCodeWeight, companyNameWeight);
result = result*100;
return new BigDecimal(result);
}
}
/**
* 规则四
*/
public List<UdiMatchRateVo> four(String brandName, String productName, String specification, String model){
List<UdiMatchRateVo> udiMatchRateVos = esSearchHelper.fourQuery(brandName, productName, specification, model);
List<Long> idList = udiMatchRateVos.stream().map(UdiMatchRateVo::getId).collect(Collectors.toList());
List<Udi> udiList = udiMapper.selectBatchIds(idList);
Map<Long, Udi> udiMap = udiList.stream().collect(Collectors.toMap(Udi::getId, Function.identity()));
for (UdiMatchRateVo udiMatchRateVo : udiMatchRateVos) {
Long id = udiMatchRateVo.getId();
if(udiMap.containsKey(id)){
Udi udi = udiMap.get(id);
BeanUtils.copyProperties(udi,udiMatchRateVo);
// todo 如何去计算匹配率
String brandNameUdi = udi.getBrandName();
String productNameUdi = udi.getProductName();
String specificationUdi = udi.getSpecification();
String modelUdi = udi.getModel();
BigDecimal matchRatio = this.matchFour(brandName,productName,specification,model, brandNameUdi,productNameUdi,specificationUdi,modelUdi);
udiMatchRateVo.setMatchRatio(matchRatio);
}else{
// 没匹配成功
udiMatchRateVo.setMatchRatio(BigDecimal.ZERO);
}
}
return udiMatchRateVos;
}
/**
* 规则四 - 计算匹配率
* @param brandName excel中的
* @param productName excel中的
* @param specification excel中的
* @param model excel中的
* @param brandNameUdi 找到的
* @param productNameUdi 找到的
* @param specificationUdi 找到的
* @param modelUdi 找到的
* @return 匹配率
*/
private BigDecimal matchFour(String brandName, String productName, String specification, String model,
String brandNameUdi, String productNameUdi, String specificationUdi, String modelUdi){
// Levenshtein距离算法 算出匹配率
StringMetric metric = new Levenshtein();
float brandNameRate = 0;
if(StringUtils.isNotBlank(brandName)){
brandNameRate = metric.compare(brandName, brandNameUdi);
}
float productNameRate = 0;
if(StringUtils.isNotBlank(productName)){
productNameRate = metric.compare(productName, productNameUdi);
}
float specificationRate = 0;
if(StringUtils.isNotBlank(specification)){
specificationRate = metric.compare(specification, specificationUdi);
}
float modelRate = 0;
if(StringUtils.isNotBlank(model)){
modelRate = metric.compare(model, modelUdi);
}
double result = PercentageCalculatorUtil.calculateWeightedAverageRate(brandNameRate, productNameRate, specificationRate, modelRate,
0.25, 0.25, 0.25, 0.25);
result = result*100;
return new BigDecimal(result);
}
}
...@@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; ...@@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.infynova.udi.entity.MatchData; import com.infynova.udi.entity.MatchData;
import com.infynova.udi.entity.MatchTemp; import com.infynova.udi.entity.MatchTemp;
import com.infynova.udi.entity.Udi;
import com.infynova.udi.enums.match.MatchStatusEnum; import com.infynova.udi.enums.match.MatchStatusEnum;
import com.infynova.udi.enums.match.MatchUpdateStatusEnum; import com.infynova.udi.enums.match.MatchUpdateStatusEnum;
import com.infynova.udi.mapper.MatchDataMapper; import com.infynova.udi.mapper.MatchDataMapper;
...@@ -12,7 +11,6 @@ import com.infynova.udi.mapper.MatchTempMapper; ...@@ -12,7 +11,6 @@ import com.infynova.udi.mapper.MatchTempMapper;
import com.infynova.udi.mapper.UdiMapper; import com.infynova.udi.mapper.UdiMapper;
import com.infynova.udi.vo.TaskVo; import com.infynova.udi.vo.TaskVo;
import com.infynova.udi.vo.UdiMatchRateVo; import com.infynova.udi.vo.UdiMatchRateVo;
import com.infynova.udi.vo.UdiVo;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
...@@ -52,6 +50,9 @@ public class MatchHelper { ...@@ -52,6 +50,9 @@ public class MatchHelper {
@Resource @Resource
private UdiLock udiLock; private UdiLock udiLock;
@Resource
private MatchESHelper matchESHelper;
private static final BigDecimal ONE_HUNDRED_RATE = new BigDecimal("100"); private static final BigDecimal ONE_HUNDRED_RATE = new BigDecimal("100");
private String getKey(String key){ private String getKey(String key){
...@@ -139,14 +140,17 @@ public class MatchHelper { ...@@ -139,14 +140,17 @@ public class MatchHelper {
// 去匹配YiBaoCode // 去匹配YiBaoCode
matchRateVoList = this.queryYiBaoCode(matchData); matchRateVoList = this.queryYiBaoCode(matchData);
} else if(StringUtils.isNotBlank(matchData.getCompanyName()) || StringUtils.isNotBlank(matchData.getProductFactoryCode())){ } else if(StringUtils.isNotBlank(matchData.getCompanyName()) || StringUtils.isNotBlank(matchData.getProductFactoryCode())){
// 厂家+产品货号/编号 todo // 厂家+产品货号/编号
matchRateVoList = matchESHelper.three(matchData.getCompanyName(), matchData.getProductFactoryCode());
} else if (StringUtils.isNotBlank(matchData.getBrandName()) } else if (StringUtils.isNotBlank(matchData.getBrandName())
|| StringUtils.isNotBlank(matchData.getProductName()) || StringUtils.isNotBlank(matchData.getProductName())
|| StringUtils.isNotBlank(matchData.getSpecification()) || StringUtils.isNotBlank(matchData.getSpecification())
|| StringUtils.isNotBlank(matchData.getModel())) { || StringUtils.isNotBlank(matchData.getModel())) {
// 品牌+名称+规格+型号; todo // 品牌+名称+规格+型号;
matchRateVoList = matchESHelper.four(matchData.getBrandName(),
matchData.getProductName(),
matchData.getSpecification(),
matchData.getModel());
} }
// 计算匹配率 // 计算匹配率
...@@ -181,7 +185,6 @@ public class MatchHelper { ...@@ -181,7 +185,6 @@ public class MatchHelper {
matchData.setUpdateStatus(MatchUpdateStatusEnum.NOT_APPLICABLE.getCode()); matchData.setUpdateStatus(MatchUpdateStatusEnum.NOT_APPLICABLE.getCode());
matchData.setUpdateTime(LocalDateTime.now()); matchData.setUpdateTime(LocalDateTime.now());
matchDataMapper.updateById(matchData); matchDataMapper.updateById(matchData);
return;
}else{ }else{
if(hundredRate){ if(hundredRate){
// 100%对码 // 100%对码
...@@ -200,29 +203,6 @@ public class MatchHelper { ...@@ -200,29 +203,6 @@ public class MatchHelper {
} }
} }
/**
* 查询udi
*/
private Page<UdiVo> queryUdi(int pageNo, int pageSize, MatchData matchData){
String udiCode = matchData.getUdiCode();
String yiBaoCode = matchData.getYiBaoCode();
String companyName = matchData.getCompanyName();
String productFactoryCode = matchData.getProductFactoryCode();
String brandName = matchData.getBrandName();
String productName = matchData.getProductName();
String specification = matchData.getSpecification();
String model = matchData.getModel();
Page<UdiVo> page = new Page<>(pageNo, pageSize);
return udiMapper.getUdi(page,udiCode,
yiBaoCode,
companyName,
productFactoryCode,
brandName,
productName,
specification,
model);
}
/** /**
* 查询udi * 查询udi
...@@ -262,7 +242,6 @@ public class MatchHelper { ...@@ -262,7 +242,6 @@ public class MatchHelper {
*/ */
private List<UdiMatchRateVo> queryYiBaoCode(MatchData matchData){ private List<UdiMatchRateVo> queryYiBaoCode(MatchData matchData){
String yiBaoCode = matchData.getYiBaoCode(); String yiBaoCode = matchData.getYiBaoCode();
// todo 分次
List<String> yiBaoCodeRegexList = new ArrayList<>(); List<String> yiBaoCodeRegexList = new ArrayList<>();
String lastYiBaoCode = yiBaoCode; String lastYiBaoCode = yiBaoCode;
// 规定udi截取的最小长度 // 规定udi截取的最小长度
...@@ -280,66 +259,9 @@ public class MatchHelper { ...@@ -280,66 +259,9 @@ public class MatchHelper {
return udiMapper.getUdiCodeRegex(yiBaoCode,yiBaoCodeRegexList); return udiMapper.getUdiCodeRegex(yiBaoCode,yiBaoCodeRegexList);
} }
/** private void setSource(List<UdiMatchRateVo> list, Integer source){
* 对目标进行分词 if(CollectionUtils.isNotEmpty(list)){
*/ list.forEach(i -> i.setSource(source));
// private String splitWord(String item){
// log.info("对目标进行分词");
//
// List<String> splitWord = new ArrayList<>();
// String result = item;
// try {
// splitWord = IKAnalyzerSupport.iKSegmenterToList(item);
// result = splitWord.stream().map(String::valueOf).distinct().collect(Collectors.joining("|")) ;
// log.info("分词结果:{}",result);
// } catch (Exception e) {
// log.error("分词报错:{}",e.getMessage());
// }
// return result;
// }
private final BigDecimal RATE = new BigDecimal("0.25");
/**
* 匹配率计算逻辑
*/
private BigDecimal matchRate(Udi udi, MatchData matchData){
BigDecimal matchRate = BigDecimal.ZERO;
// - 规则1:DI码,即69码;
String udiCode = udi.getUdiCode();
String matchUdiCode = matchData.getUdiCode();
if(StringUtils.equals(udiCode,matchUdiCode)){
matchRate = matchRate.add(RATE);
}
// - 规则2:C码 ,是指医保编码;
String yiBaoCode = udi.getYiBaoCode();
String matchYiBaoCode = matchData.getYiBaoCode();
if(StringUtils.equals(yiBaoCode,matchYiBaoCode)){
matchRate = matchRate.add(RATE);
}
// - 规则3:厂家+产品货号/编号;
String companyName = udi.getCompanyName();
String matchCompanyName = matchData.getCompanyName();
String productFactoryCode = udi.getProductFactoryCode();
String matchProductFactoryCode = matchData.getProductFactoryCode();
if(StringUtils.equals(companyName,matchCompanyName) && StringUtils.equals(productFactoryCode,matchProductFactoryCode)){
matchRate = matchRate.add(RATE);
}
// - 规则4:品牌+名称+规格+型号;
String brandName = udi.getBrandName();
String matchBrandName = matchData.getBrandName();
String productName = udi.getProductName();
String matchProductName = matchData.getProductName();
String specification = udi.getSpecification();
String matchSpecification = matchData.getSpecification();
String model = udi.getModel();
String matchModel = matchData.getModel();
if(StringUtils.equals(brandName,matchBrandName)
&& StringUtils.equals(productName,matchProductName)
&& StringUtils.equals(specification,matchSpecification)
&& StringUtils.equals(model,matchModel)){
matchRate = matchRate.add(RATE);
} }
return matchRate;
} }
} }
package com.infynova.udi.service.helper;
/**
* @author liudong
* 2024/5/15 18:20
* @version 1.0
*/
public class PercentageCalculatorUtil {
public static void main(String[] args) {
example01();
example02();
example03();
example04();
}
/**
* 简单平均
* 这种方法计算两个百分比的平均值
*/
public static double calculateAverageRate(double percentage1, double percentage2) {
return (percentage1 + percentage2) / 2;
}
public static void example01() {
double percentage1 = 75.0;
double percentage2 = 85.0;
double result = calculateAverageRate(percentage1, percentage2);
System.out.println("Average Rate 简单平均: " + result + "%");
}
/**
* 加权平均
* 如果两个百分比的权重不同,可以根据权重计算加权平均
* @param percentage1
* @param percentage2
* @param weight1
* @param weight2
* @return
*/
public static double calculateWeightedAverageRate(double percentage1, double percentage2, double weight1, double weight2) {
return (percentage1 * weight1 + percentage2 * weight2) / (weight1 + weight2);
}
public static double calculateWeightedAverageRate(double percentage1, double percentage2, double percentage3, double percentage4, double weight1, double weight2, double weight3, double weight4) {
return (percentage1 * weight1 + percentage2 * weight2 + percentage3 * weight3 + percentage4 * weight4) / (weight1 + weight2 + weight3 + weight4);
}
public static void example02() {
double percentage1 = 75.0;
double percentage2 = 85.0;
double weight1 = 0.4; // 权重1
double weight2 = 0.6; // 权重2
double result = calculateWeightedAverageRate(percentage1, percentage2, weight1, weight2);
System.out.println("Weighted Average Rate 加权平均: " + result + "%");
}
/**
* 乘法平均(几何平均)
* 这种方法适用于计算多个百分比的综合效果。
* @param percentage1
* @param percentage2
* @return
*/
public static double calculateGeometricMeanRate(double percentage1, double percentage2) {
return Math.sqrt(percentage1 * percentage2);
}
public static void example03() {
double percentage1 = 75.0;
double percentage2 = 85.0;
double result = calculateGeometricMeanRate(percentage1, percentage2);
System.out.println("Geometric Mean Rate 乘法平均(几何平均): " + result + "%");
}
/**
* 自定义算法
* 你可以根据具体业务需求,设计一个自定义的算法。例如,可以通过计算两个百分比的差异来调整符合率。
* @param percentage1
* @param percentage2
* @return
*/
public static double calculateCustomRate(double percentage1, double percentage2) {
double difference = Math.abs(percentage1 - percentage2);
return (percentage1 + percentage2 - difference) / 2;
}
public static void example04() {
double percentage1 = 75.0;
double percentage2 = 85.0;
double result = calculateCustomRate(percentage1, percentage2);
System.out.println("Custom Rate 自定义算法: " + result + "%");
}
}
...@@ -78,20 +78,6 @@ ...@@ -78,20 +78,6 @@
</if> </if>
</sql> </sql>
<select id="getUdi" resultType="com.infynova.udi.vo.UdiVo">
select *
from product
where udi_code = #{udi}
OR yi_bao_code = #{yiBaoCode}
OR company_name = #{companyName}
OR product_factory_code = #{productFactoryCode}
OR brand_name = #{brandName}
OR product_name = #{productName}
OR specification = #{specification}
OR model = #{model}
order by id desc
</select>
<select id="getUdiCodeRegex" resultType="com.infynova.udi.vo.UdiMatchRateVo"> <select id="getUdiCodeRegex" resultType="com.infynova.udi.vo.UdiMatchRateVo">
SELECT SELECT
ifnull(calculate_match_ratio(p.udi_code, #{udiCode}),0) as match_ratio, ifnull(calculate_match_ratio(p.udi_code, #{udiCode}),0) as match_ratio,
......
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