Commit 877b932f by xmh

初版

1 parent 4f063055
...@@ -29,3 +29,4 @@ build/ ...@@ -29,3 +29,4 @@ build/
### VS Code ### ### VS Code ###
.vscode/ .vscode/
/logs/
...@@ -8,12 +8,11 @@ ...@@ -8,12 +8,11 @@
<version>2.3.1.RELEASE</version> <version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<groupId>com.xmh.es</groupId> <groupId>com.viontech</groupId>
<artifactId>xmh-test</artifactId> <artifactId>VVAS-Match</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<name>xmh-test</name> <name>VVAS-Match</name>
<packaging>jar</packaging> <packaging>jar</packaging>
<description>Demo project for Spring Boot</description>
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>
...@@ -26,11 +25,6 @@ ...@@ -26,11 +25,6 @@
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
...@@ -39,25 +33,19 @@ ...@@ -39,25 +33,19 @@
<groupId>com.viontech.keliu</groupId> <groupId>com.viontech.keliu</groupId>
<artifactId>keliu-base</artifactId> <artifactId>keliu-base</artifactId>
<version>6.0.8-SNAPSHOT</version> <version>6.0.8-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<groupId>com.github.pagehelper</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency>
<groupId>com.viontech.keliu</groupId>
<artifactId>keliu-storage</artifactId>
<version>6.0.8-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.viontech.keliu</groupId>
<artifactId>keliu-storage</artifactId>
<version>6.0.8-SNAPSHOT</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
...@@ -89,7 +77,7 @@ ...@@ -89,7 +77,7 @@
</dependencies> </dependencies>
<build> <build>
<finalName>es-match</finalName> <finalName>VVAS-Match</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
......
package com.viontech.match;
/**
* .
*
* @author 谢明辉
* @date 2020/11/25
*/
public enum PoolEnum {
/** */
POOL_2K("test_pool_2k", 2000),
POOL_5K("test_pool_5k", 5000),
POOL_2W("test_pool_2w", 20000),
POOL_10W("test_pool_10w", 100000),
POOL_50W("test_pool_50w", 500000),
POOL_100W("test_pool_100w", 1000000),
POOL_200W("test_pool_200w", 2000000);
public String name;
public int num;
PoolEnum(String name, int num) {
this.name = name;
this.num = num;
}
}
...@@ -5,8 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; ...@@ -5,8 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication @SpringBootApplication
@ComponentScan(basePackages = {"com.viontech"}) @ComponentScan(basePackages = {"com.viontech"})public class XmhTestApplication {
public class XmhTestApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(XmhTestApplication.class, args); SpringApplication.run(XmhTestApplication.class, args);
......
package com.viontech.match.config;
import com.viontech.keliu.websocket.AlgApiClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: 王洪波
* @Date: 2019/2/22.
*/
@Configuration
public class AlgApiClientConfiguration {
@Value("${ws.featureUrl:}")
private String featureUrl;
@Value("${ws.url:}")
private String compareUrl;
@Bean("algApiClientFeature")
@ConditionalOnProperty(name = "ws.featureUrl")
public AlgApiClient algApiClientFeatureConfig() {
return new AlgApiClient(featureUrl);
}
@Bean("algApiClient")
@ConditionalOnProperty(name = "ws.url")
public AlgApiClient algApiClient() {
return new AlgApiClient(compareUrl);
}
}
package com.viontech.match.controller; package com.viontech.match.controller;
import com.fasterxml.jackson.core.JsonProcessingException; import com.viontech.match.entity.vo.RequestVo;
import com.fasterxml.jackson.databind.ObjectMapper; import com.viontech.match.entity.vo.ResponseVo;
import com.viontech.keliu.storage.Storage; import com.viontech.match.service.PersonService;
import com.viontech.keliu.util.DateUtil; import com.viontech.match.service.PoolService;
import com.viontech.match.PoolEnum; import lombok.extern.slf4j.Slf4j;
import com.viontech.match.entity.*; import org.springframework.web.bind.annotation.PostMapping;
import com.viontech.match.entity.vo.RequestData; import org.springframework.web.bind.annotation.RequestBody;
import com.viontech.match.repository.FaceRecognitionRepository; import org.springframework.web.bind.annotation.RequestMapping;
import com.viontech.match.service.AlgService; import org.springframework.web.bind.annotation.RestController;
import com.viontech.match.service.MatchService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/** /**
* . * .
...@@ -30,154 +20,37 @@ import java.util.stream.Collectors; ...@@ -30,154 +20,37 @@ import java.util.stream.Collectors;
*/ */
@RestController @RestController
@RequestMapping("/alg") @RequestMapping("/alg")
@Slf4j
public class MainController { public class MainController {
private final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(20, 30, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
private final AtomicInteger integer = new AtomicInteger();
@Resource @Resource
ObjectMapper objectMapper; private PersonService personService;
@Resource @Resource
private MatchService matchService; private PoolService poolService;
@Resource
private FaceRecognitionRepository faceRecognitionRepository; @PostMapping
@Resource public ResponseVo all(@RequestBody RequestVo requestVo) throws Exception {
private AlgService algService; String rid = requestVo.getRid();
@Resource try{
private Storage featureStorage; switch (requestVo.getCommand()) {
case AddPersonPool:
@PostMapping("/match") return poolService.createPool(requestVo);
public Object match(RequestData requestData) throws Exception { case DelPersonPool:
MultipartFile file = requestData.getFile(); return poolService.deletePool(requestVo);
Double[] data = matchService.extractFeature(file); case ModifyPersonPool:
Person person = new Person().setFeature(data); return poolService.modifyPool(requestVo);
long begin = System.currentTimeMillis(); case QueryPersonPool:
List<MatchResult> match = algService.matchPerson(person, requestData.getPoolId()); return poolService.queryPool(requestVo);
long timeConsumingMatching = System.currentTimeMillis() - begin; case MatchPerson:
List<String> collect = match.stream().map(MatchResult::getPersonId).collect(Collectors.toList()); return personService.matchPerson(requestVo);
List<FaceRecognition> faceRecognitions = faceRecognitionRepository.queryFaceRecognitionByUnids(collect); case UpdatePerson:
if (faceRecognitions == null) { return personService.updatePerson(requestVo);
return null; default:
} return ResponseVo.commandNotFound(rid);
Map<String, FaceRecognition> map = faceRecognitions.stream().collect(Collectors.toMap(FaceRecognition::getUnid, x -> x, (x, y) -> y));
for (MatchResult item : match) {
FaceRecognition faceRecognition = map.get(item.getPersonId());
if (faceRecognition != null) {
faceRecognition.setMatchScore(item.getScore());
}
}
Collection<FaceRecognition> values = map.values();
List<FaceRecognition> collect1 = values.stream().sorted((o1, o2) -> {
if (o1.getMatchScore() > o2.getMatchScore()) {
return -1;
} else if (o1.getMatchScore().equals(o2.getMatchScore())) {
return 0;
} else {
return 1;
}
}).collect(Collectors.toList());
HashMap<String, Object> resultMap = new HashMap<>(2);
resultMap.put("time", timeConsumingMatching);
resultMap.put("result", collect1);
return resultMap;
}
@GetMapping("/poolIds")
public Object getPoolIds() throws IOException {
return algService.queryPoolList();
}
@GetMapping("/create/{num}")
public Object createPool(@PathVariable("num") Integer num) throws Exception {
PoolEnum pool;
switch (num) {
case 2000:
pool = PoolEnum.POOL_2K;
break;
case 5000:
pool = PoolEnum.POOL_5K;
break;
case 20000:
pool = PoolEnum.POOL_2W;
break;
case 100000:
pool = PoolEnum.POOL_10W;
break;
case 500000:
pool = PoolEnum.POOL_50W;
break;
case 1000000:
pool = PoolEnum.POOL_100W;
break;
case 2000000:
pool = PoolEnum.POOL_200W;
break;
default:
throw new RuntimeException("请输入[2000,5000,20000,100000,500000,1000000,2000000]");
}
algService.deletePool(pool.name);
algService.createPool(pool.name);
Date end = DateUtil.addDays(new Date(), -1);
Date start = DateUtil.addDays(end, -30);
integer.set(0);
List<Date> days = DateUtil.getDaysBetweenDates(start, end);
for (Date day : days) {
List<FaceRecognition> faceRecognitions = faceRecognitionRepository.queryFaceRecognitions(day, 2L);
for (FaceRecognition faceRecognition : faceRecognitions) {
poolExecutor.execute(() -> {
try {
if (integer.get() >= pool.num) {
return;
}
Double[] feature = getFeature(faceRecognition);
if (feature == null) {
return;
}
Person person = new Person();
person.setPersonId(faceRecognition.getPersonUnid());
person.setFeature(feature);
person.setId(faceRecognition.getUnid());
Object o = algService.addPerson(person, pool.name);
System.out.println(objectMapper.writeValueAsString(o));
integer.addAndGet(1);
} catch (Exception e) {
e.printStackTrace();
}
});
if (integer.get() > pool.num) {
return "success";
}
while (poolExecutor.getQueue().size() > 10000) {
System.out.println(poolExecutor.getQueue().size());
TimeUnit.SECONDS.sleep(4);
}
if (integer.get() > pool.num) {
return "success";
}
}
}
return "success";
}
private Double[] getFeature(FaceRecognition face) throws JsonProcessingException {
Short faceFeatureType = face.getFaceFeatureType();
String facePic = face.getFacePic();
if (faceFeatureType == 1) {
facePic = facePic.replace("face-0.jpg", "face-F.jpg");
}
String json = (String) featureStorage.getItem(face.getChannelSerialnum() + "/" + facePic);
Feature feature = objectMapper.readValue(json, Feature.class);
List<Data> datas = feature.getDatas();
if (datas != null && datas.size() > 0) {
Data data = datas.get(0);
Double[] data1 = data.getData();
if (data1.length == 512) {
return data1;
} }
}catch(Exception e){
log.error("",e);
return ResponseVo.error(rid, e.getMessage());
} }
return null;
} }
} }
package com.viontech.match.entity;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Data {
private String type;
private Double[] data;
}
package com.viontech.match.entity;
import com.viontech.keliu.base.BaseModel;
import com.viontech.keliu.util.DateUtil;
import java.util.Date;
public class FaceRecognition extends BaseModel {
private Long id;
private Long deviceId;
private Long channelId;
private Long gateId;
private String deviceSerialnum;
private String channelSerialnum;
private Short personType;
private String facePic;
private Short facePicNum;
private Short bodyPicNum;
private String bodyPic;
private String showbodyPic;
private Short mood;
private Short age;
private Short gender;
private Short direction;
private Date counttime;
private Date countdate;
private Date modifyTime;
private Date createTime;
private Long mallId;
private Long accountId;
private String personUnid;
private Short status;
private Short faceFeatureType;
private Short bodyFeatureType;
private String trackInfo;
private Integer trackTime;
private String facePath;
private String trackPath;
private Short happyConf;
/** 历史到店次数 */
private Short historyArrivalCount;
/** 今日到店次数 */
private Short todayArrivalCount;
private String unid;
/** 图像质量分 **/
private Float faceScore;
private Float matchScore;
@Override
public Long getId() {
return id;
}
@Override
public void setId(Long id) {
this.id = id;
}
public Long getDeviceId() {
return deviceId;
}
public void setDeviceId(Long deviceId) {
this.deviceId = deviceId;
}
public Long getChannelId() {
return channelId;
}
public void setChannelId(Long channelId) {
this.channelId = channelId;
}
public Long getGateId() {
return gateId;
}
public void setGateId(Long gateId) {
this.gateId = gateId;
}
public String getDeviceSerialnum() {
return deviceSerialnum;
}
public void setDeviceSerialnum(String deviceSerialnum) {
this.deviceSerialnum = deviceSerialnum;
}
public String getChannelSerialnum() {
return channelSerialnum;
}
public void setChannelSerialnum(String channelSerialnum) {
this.channelSerialnum = channelSerialnum;
}
public Short getPersonType() {
return personType;
}
public void setPersonType(Short personType) {
this.personType = personType;
}
public String getFacePic() {
if (facePic == null) {
facePic = unid + "-" + DateUtil.format("yyyyMMddHHmmss", counttime) + "-face-0.jpg";
}
return facePic;
}
public void setFacePic(String facePic) {
this.facePic = facePic;
}
public String getBodyPic() {
if (bodyPic == null) {
bodyPic = unid + "-" + DateUtil.format("yyyyMMddHHmmss", counttime) + "-body-0.jpg";
}
return bodyPic;
}
public void setBodyPic(String bodyPic) {
this.bodyPic = bodyPic;
}
public String getShowbodyPic() {
return showbodyPic;
}
public void setShowbodyPic(String showbodyPic) {
this.showbodyPic = showbodyPic;
}
public Short getMood() {
return mood;
}
public void setMood(Short mood) {
this.mood = mood;
}
public Short getAge() {
return age;
}
public void setAge(Short age) {
this.age = age;
}
public Short getGender() {
return gender;
}
public void setGender(Short gender) {
this.gender = gender;
}
public Short getDirection() {
return direction;
}
public void setDirection(Short direction) {
this.direction = direction;
}
public Date getCounttime() {
return counttime;
}
public void setCounttime(Date counttime) {
this.counttime = counttime;
}
public Date getCountdate() {
return countdate;
}
public void setCountdate(Date countdate) {
this.countdate = countdate;
}
public Date getModifyTime() {
return modifyTime;
}
public void setModifyTime(Date modifyTime) {
this.modifyTime = modifyTime;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Long getMallId() {
return mallId;
}
public void setMallId(Long mallId) {
this.mallId = mallId;
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getPersonUnid() {
return personUnid;
}
public void setPersonUnid(String personUnid) {
this.personUnid = personUnid;
}
public Short getStatus() {
return status;
}
public void setStatus(Short status) {
this.status = status;
}
public String getTrackInfo() {
return trackInfo;
}
public void setTrackInfo(String trackInfo) {
this.trackInfo = trackInfo;
}
public Integer getTrackTime() {
return trackTime;
}
public void setTrackTime(Integer trackTime) {
this.trackTime = trackTime;
}
public Short getHappyConf() {
return happyConf;
}
public void setHappyConf(Short happyConf) {
this.happyConf = happyConf;
}
public Short getHistoryArrivalCount() {
return historyArrivalCount;
}
public void setHistoryArrivalCount(Short historyArrivalCount) {
this.historyArrivalCount = historyArrivalCount;
}
public Short getTodayArrivalCount() {
return todayArrivalCount;
}
public void setTodayArrivalCount(Short todayArrivalCount) {
this.todayArrivalCount = todayArrivalCount;
}
public String getUnid() {
return unid;
}
public void setUnid(String unid) {
this.unid = unid;
}
public Float getFaceScore() {
return faceScore;
}
public void setFaceScore(Float faceScore) {
this.faceScore = faceScore;
}
public Short getFacePicNum() {
return facePicNum;
}
public void setFacePicNum(Short facePicNum) {
this.facePicNum = facePicNum;
}
public Short getBodyPicNum() {
return bodyPicNum;
}
public void setBodyPicNum(Short bodyPicNum) {
this.bodyPicNum = bodyPicNum;
}
public Short getFaceFeatureType() {
return faceFeatureType;
}
public void setFaceFeatureType(Short faceFeatureType) {
this.faceFeatureType = faceFeatureType;
}
public Short getBodyFeatureType() {
return bodyFeatureType;
}
public void setBodyFeatureType(Short bodyFeatureType) {
this.bodyFeatureType = bodyFeatureType;
}
private String getRootPath(String pathType) {
Date countdate = this.getCountdate();
if (countdate == null) {
return "获取轨迹根路径失败。【日期字段无法获取】";
}
String yyyyMMdd = DateUtil.format("yyyyMMdd", countdate);
String channelSerialnum = this.getChannelSerialnum();
if (channelSerialnum == null) {
return "获取轨迹根路径失败。【通道序列号字段无法获取】";
}
return pathType + "/" + yyyyMMdd + "/" + channelSerialnum + "/";
}
public String getFacePath() {
facePath = getRootPath("face");
return facePath;
}
public String getTrackPath() {
trackPath = getRootPath("track");
return trackPath;
}
public void setFacePath(String facePath) {
this.facePath = facePath;
}
public void setTrackPath(String trackPath) {
this.trackPath = trackPath;
}
public Float getMatchScore() {
return matchScore;
}
public void setMatchScore(Float matchScore) {
this.matchScore = matchScore;
}
}
\ No newline at end of file \ No newline at end of file
package com.viontech.match.entity;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class Feature {
private String filename;
private String type;
private List<Data> datas;
private Float face_score;
private Integer face_type;
}
package com.viontech.match.entity;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* .
*
* @author 谢明辉
* @date 2020/11/23
*/
@Getter
@Setter
@Accessors(chain = true)
public class Person {
private String id;
private Double[] feature;
private String personId;
}
...@@ -2,21 +2,19 @@ package com.viontech.match.entity; ...@@ -2,21 +2,19 @@ package com.viontech.match.entity;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.Accessors;
/** /**
* . * .
* *
* @author 谢明辉 * @author 谢明辉
* @date 2020/11/20 * @date 2020/11/27
*/ */
@Getter @Getter
@Setter @Setter
@Accessors(chain = true) public class PoolInfo {
public class MatchResult {
private String personId;
private String poolId; private String poolId;
private float score; private Integer poolType;
private Long personCount;
} }
package com.viontech.match.entity.vo;
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;
/**
* .
*
* @author 谢明辉
* @date 2020/11/23
*/
@Getter
@Setter
public class RequestData {
private MultipartFile file;
private String poolId;
}
package com.viontech.match.entity.vo;
import com.viontech.keliu.model.Person;
import com.viontech.match.enumeration.CommandEnum;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.List;
/**
* .
*
* @author 谢明辉
* @date 2020/11/27
*/
@Getter
@Setter
public class RequestVo {
/** 公用 */
private CommandEnum command;
private String rid;
private String poolId;
/** 增加修改特征池时使用 */
private Integer poolType;
private List<Person> personPool;
private Integer updateType;
/** 删除时使用 */
private List<HashMap<String, String>> personIds;
private Integer flushPool;
/** 查询时使用 */
private Integer listAll;
/** 人员匹配时用 */
private Integer personType;
private Person person;
private String personPoolId;
private List<String> unionPersonPoolId;
public void setPoolId(String poolId) {
this.poolId = poolId.toLowerCase();
}
public Integer getFlushPool() {
if (flushPool == null) {
flushPool = 1;
}
return flushPool;
}
public Integer getListAll() {
if (listAll == null) {
listAll = 1;
}
return listAll;
}
}
package com.viontech.match.entity.vo;
import com.viontech.keliu.model.Person;
import com.viontech.keliu.model.Pool;
import com.viontech.match.entity.PoolInfo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.List;
/**
* .
*
* @author 谢明辉
* @date 2020/11/27
*/
@Getter
@Setter
@ToString
public class ResponseVo {
private Integer success;
private String description;
private String rid;
private Integer errCode;
private List<Pool> personPoolStatus;
private Integer oper;
private Integer index;
private Integer match;
private List<PoolInfo> poolIds;
private List<Person> matchPersons;
public ResponseVo(String rid) {
this.rid = rid;
}
public static ResponseVo commandNotFound(String rid) {
return error(rid, "command not found");
}
public static ResponseVo error(String rid, String description) {
return error(rid, 1, description);
}
public static ResponseVo error(String rid, Integer errCode, String description) {
ResponseVo responseVo = new ResponseVo(rid);
responseVo.setSuccess(0);
responseVo.setErrCode(errCode);
responseVo.setDescription(description);
return responseVo;
}
public static ResponseVo success(String rid) {
return success(rid, "success");
}
public static ResponseVo success(String rid, String description) {
ResponseVo responseVo = new ResponseVo(rid);
responseVo.setSuccess(1);
responseVo.setDescription(description);
responseVo.setErrCode(0);
return responseVo;
}
}
package com.viontech.match.enumeration;
/**
* .
*
* @author 谢明辉
* @date 2020/11/27
*/
public enum CommandEnum {
/** 命令 */
AddPersonPool,
DelPersonPool,
ModifyPersonPool,
QueryPersonPool,
MatchPerson,
UpdatePerson
}
package com.viontech.match.repository;
import com.viontech.match.entity.FaceRecognition;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* .
*
* @author 谢明辉
* @date 2020/11/20
*/
@Repository
public class FaceRecognitionRepository {
private static final BeanPropertyRowMapper<FaceRecognition> FACE_RECOGNITION_ROW_MAPPER = new BeanPropertyRowMapper<>(FaceRecognition.class);
private static final String QUERY_FACE = "select unid,person_unid,face_feature_type,face_pic,channel_serialnum from d_face_recognition where countdate=? and direction=1 and gender>-1 and face_score>0.7";
private static final String QUERY_FACE_BY_UNID = "select face_pic,id,channel_serialnum,device_serialnum,person_unid,unid,id,countdate,counttime,age,gender,direction,mall_id,account_id,gate_id,face_score,person_type from d_face_recognition where unid in (:unids)";
@Resource
private JdbcTemplate jdbcTemplate;
@Resource
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public List<FaceRecognition> queryFaceRecognitions(Date date, Long mallId) {
return jdbcTemplate.query(QUERY_FACE, FACE_RECOGNITION_ROW_MAPPER, date);
}
public List<FaceRecognition> queryFaceRecognitionByUnids(List<String> unidList) {
if (unidList == null || unidList.size() == 0) {
return null;
}
Map<String, List<String>> param = Collections.singletonMap("unids", unidList);
return namedParameterJdbcTemplate.query(QUERY_FACE_BY_UNID, param, FACE_RECOGNITION_ROW_MAPPER);
}
}
package com.viontech.match.service;
import com.viontech.match.entity.Person;
import com.viontech.match.entity.MatchResult;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.ScriptScoreQueryBuilder;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* .
*
* @author 谢明辉
* @date 2020/11/20
*/
@Service
public class AlgService {
@Resource
private RestHighLevelClient client;
/**
* 建立特征库索引
*
* @param poolName 特征库名称,作为index
*/
public Object createPool(String poolName) throws IOException {
CreateIndexRequest test2 = new CreateIndexRequest(poolName);
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
{
builder.startObject("properties");
{
builder.startObject("data");
{
builder.field("type", "dense_vector");
builder.field("dims", 512);
}
builder.endObject();
builder.startObject("personId");
{
builder.field("type", "keyword");
}
builder.endObject();
}
builder.endObject();
}
builder.endObject();
test2.mapping(builder);
CreateIndexResponse createIndexResponse = client.indices().create(test2, RequestOptions.DEFAULT);
if (createIndexResponse.isAcknowledged()) {
return "success";
} else {
return "failed";
}
}
/**
* 删除特征库
*
* @param poolName 特征库名称,index
*/
public Object deletePool(String poolName) throws IOException {
boolean exists = client.indices().exists(new GetIndexRequest(poolName), RequestOptions.DEFAULT);
if (!exists) {
return "特征池不存在";
}
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(poolName);
AcknowledgedResponse delete = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
if (delete.isAcknowledged()) {
return "success";
} else {
return "failed";
}
}
/**
* 查询特征库列表
*/
public String[] queryPoolList() throws IOException {
GetIndexResponse response = client.indices().get(new GetIndexRequest("*"), RequestOptions.DEFAULT);
return response.getIndices();
}
/**
* 人员比对
*
* @param person 需要比对的人员
* @param poolId 用来比对的特征库
*/
public List<MatchResult> matchPerson(Person person, String poolId) throws Exception {
Double[] feature = person.getFeature();
if (feature.length < 512) {
throw new Exception("特征维数为:" + feature.length + ",小于512维");
}
SearchRequest searchRequest = new SearchRequest(poolId);
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.fetchSource("personId", null);
builder.size(40);
Map<String, Object> params = new HashMap<>(1);
params.put("data", feature);
Script script = new Script(
ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG,
"(cosineSimilarity(params.data, 'data') + 1) / 2 * 100", params);
ScriptScoreQueryBuilder queryBuilder = QueryBuilders.scriptScoreQuery(QueryBuilders.matchAllQuery(), script);
builder.query(queryBuilder);
builder.fetchSource("personId", null);
SearchRequest source = searchRequest.source(builder);
SearchResponse search = client.search(source, RequestOptions.DEFAULT);
SearchHits hits = search.getHits();
SearchHit[] hits1 = hits.getHits();
ArrayList<MatchResult> matchResults = new ArrayList<>();
for (SearchHit item : hits1) {
String personId = item.getId();
float score = item.getScore();
String index = item.getIndex();
MatchResult matchResult = new MatchResult().setPersonId(personId).setScore(score).setPoolId(index);
matchResults.add(matchResult);
}
return matchResults;
}
/**
* 添加人员
*
* @param person 需要添加的人员
* @param poolId 特征库名称
*/
public Object addPerson(Person person, String poolId) throws IOException {
IndexRequest indexRequest = new IndexRequest(poolId)
.id(person.getId())
.source(XContentType.JSON, "personId", person.getPersonId(), "data", person.getFeature());
return client.index(indexRequest, RequestOptions.DEFAULT);
}
public Object addAllPerson(List<Person> persons, String poolId) throws Exception {
BulkRequest bulkRequest = new BulkRequest();
for (Person person : persons) {
bulkRequest.add(new IndexRequest(poolId)
.id(person.getId())
.source(XContentType.JSON, "personId", person.getPersonId(), "data", person.getFeature()));
}
return client.bulk(bulkRequest, RequestOptions.DEFAULT);
}
/**
* 删除人员
*
* @param personId 需要删除的人员的id
* @param poolId 特征池名称
*/
public Object delPerson(String personId, String poolId) throws Exception {
DeleteRequest deleteRequest = new DeleteRequest(poolId, personId);
return client.delete(deleteRequest, RequestOptions.DEFAULT);
}
}
package com.viontech.match.service;
import com.viontech.keliu.i18n.util.LocalMessageUtil;
import com.viontech.keliu.websocket.AlgApiClient;
import com.viontech.match.entity.MatchResult;
import com.viontech.match.entity.Person;
import com.viontech.match.entity.vo.RequestData;
import com.viontech.match.util.Utils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* .
*
* @author 谢明辉
* @date 2020/11/23
*/
@Service
public class MatchService {
@Resource
private AlgApiClient algApiClientFeature;
@Resource
private AlgService algService;
public List<MatchResult> match(RequestData requestData) throws Exception {
MultipartFile file = requestData.getFile();
Double[] data = extractFeature(file);
Person person = new Person().setFeature(data);
return algService.matchPerson(person, requestData.getPoolId());
}
public Double[] extractFeature(MultipartFile file) throws Exception {
BufferedImage originalImage = ImageIO.read(file.getInputStream());
BufferedImage jpgImage = Utils.convertImg2Jpg(originalImage);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(jpgImage, "jpg", out);
String base64 = Base64.getEncoder().encodeToString(out.toByteArray());
Map<String, Object> options = new HashMap<>();
options.put("vendor", "vion");
options.put("needFaceCheck", 1);
options.put("vendor", "vion");
CompletableFuture<JSONObject> responseFuture = algApiClientFeature.getFeatureAndAttr(base64,
AlgApiClient.IMAGE_TYPE_FACE, AlgApiClient.IMAGE_FORMAT_JPG, null, options);
JSONObject jsonObject = responseFuture.get(120, TimeUnit.SECONDS);
int success = jsonObject.getInt("success");
if (0 == success) {
throw new RuntimeException(jsonObject.getString("description"));
}
JSONObject faceFeatureJson = jsonObject.getJSONObject("faceFeature");
String message = LocalMessageUtil.getMessage("Message.picError");
if (faceFeatureJson == null) {
throw new Exception("无法提取特征");
}
JSONArray feature = faceFeatureJson.getJSONArray("feature");
List<Object> objects = feature.toList();
return objects.toArray(new Double[]{});
}
}
package com.viontech.match.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.viontech.keliu.model.FaceFeature;
import com.viontech.keliu.model.Person;
import com.viontech.keliu.model.Pool;
import com.viontech.match.entity.vo.RequestVo;
import com.viontech.match.entity.vo.ResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScriptScoreQueryBuilder;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
* .
*
* @author 谢明辉
* @date 2020/11/27
*/
@Service
@Slf4j
public class PersonService {
@Resource
private RestHighLevelClient client;
@Resource
private PoolService poolService;
@Resource
private ObjectMapper objectMapper;
/**
* 人员比对
*/
public ResponseVo matchPerson(RequestVo requestVo) throws Exception {
String rid = requestVo.getRid();
String poolId = requestVo.getPersonPoolId();
List<String> unionPersonPoolId = requestVo.getUnionPersonPoolId();
List<String> poolIds = new ArrayList<>();
List<Person> result = new ArrayList<>();
List<Pool> poolStatus = new ArrayList<>();
if (unionPersonPoolId != null && unionPersonPoolId.size() > 0) {
poolIds.addAll(unionPersonPoolId);
}
if (poolId != null) {
poolIds.add(poolId);
}
log.info("人员匹配操作开始,PoolIds:[{}]", poolIds.toString());
try {
for (String id : poolIds) {
Pool pool = new Pool();
pool.setPersonPoolId(id);
if (poolService.existPool(id)) {
pool.setStatus(0);
List<Person> people = matchPerson(id, requestVo.getPerson());
result.addAll(people);
} else {
pool.setStatus(1);
}
poolStatus.add(pool);
}
ResponseVo success = ResponseVo.success(rid, "success");
success.setMatchPersons(result);
success.setMatch(1);
success.setPersonPoolStatus(poolStatus);
log.info("人员匹配操作完成,PoolIds:[{}},结果:[{}]", poolIds.toString(), objectMapper.writeValueAsString(success));
return success;
} catch (ElasticsearchStatusException e) {
log.error("matchPerson", e);
ResponseVo error = ResponseVo.error(rid, e.getDetailedMessage());
error.setMatch(0);
return error;
}
}
/**
* 修改人员特征
*/
public ResponseVo updatePerson(RequestVo requestVo) {
return null;
}
/**
* 添加人员
*/
public BulkResponse addPerson(String poolId, List<Person> personPool) throws IOException {
BulkRequest bulkRequest = new BulkRequest(poolId);
for (Person person : personPool) {
Integer age = person.getAge();
String gender = person.getGender();
String personId = person.getPersonId();
List<FaceFeature> faceFeatures = person.getFaceFeatures();
if (faceFeatures != null && faceFeatures.size() > 0) {
for (FaceFeature faceFeature : faceFeatures) {
Double[] feature = faceFeature.getFeature();
String fid = faceFeature.getFid();
IndexRequest indexRequest = new IndexRequest(poolId)
.source(XContentType.JSON, "personId", personId, "data", feature, "fid", fid, "age", age, "gender", gender);
bulkRequest.add(indexRequest);
}
}
}
if (bulkRequest.requests().size() == 0) {
return null;
}
return client.bulk(bulkRequest, RequestOptions.DEFAULT);
}
/**
* 删除人员
*/
public BulkByScrollResponse deletePerson(String poolId, String personId) throws IOException {
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(poolId)
.setQuery(new TermQueryBuilder("personId", personId))
.setRefresh(true);
return client.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
}
public List<Person> matchPerson(String poolId, Person person) throws Exception {
List<FaceFeature> faceFeatures = person.getFaceFeatures();
List<Person> persons = new ArrayList<>();
if (faceFeatures != null && faceFeatures.size() > 0) {
for (FaceFeature faceFeature : faceFeatures) {
Double[] feature = faceFeature.getFeature();
if (feature.length < 512) {
continue;
}
Script script = new Script(
ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG,
"(cosineSimilarity(params.data, 'data') + 1) / 2 * 100", Collections.singletonMap("data", feature));
ScriptScoreQueryBuilder queryBuilder = QueryBuilders.scriptScoreQuery(QueryBuilders.matchAllQuery(), script);
SearchSourceBuilder builder = new SearchSourceBuilder()
.size(5)
.query(queryBuilder)
.fetchSource(new String[]{"personId", "age", "gender", "fid"}, null);
SearchRequest searchRequest = new SearchRequest(poolId)
.source(builder);
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = search.getHits();
SearchHit[] hits1 = hits.getHits();
for (SearchHit item : hits1) {
Map<String, Object> source = item.getSourceAsMap();
Person p = new Person();
p.setPersonId((String) source.get("personId"));
p.setAge((Integer) source.get("age"));
p.setGender((String) source.get("gender"));
p.setScore((int) item.getScore());
p.setPersonPoolId(item.getIndex());
persons.add(p);
}
}
} else {
log.info("no face feature");
}
if (persons.size() > 5) {
persons = persons.stream().sorted(Comparator.comparingInt(Person::getScore)).limit(5).collect(Collectors.toList());
}
return persons;
}
}
package com.viontech.match.service;
import com.viontech.keliu.model.Person;
import com.viontech.match.entity.PoolInfo;
import com.viontech.match.entity.vo.RequestVo;
import com.viontech.match.entity.vo.ResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.ElasticsearchStatusException;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.rest.RestStatus;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* .
*
* @author 谢明辉
* @date 2020/11/27
*/
@Service
@Slf4j
public class PoolService {
@Resource
private PersonService personService;
@Resource
private RestHighLevelClient client;
/**
* 添加特征池
*/
public ResponseVo createPool(RequestVo requestVo) throws Exception {
String rid = requestVo.getRid();
String poolId = requestVo.getPoolId();
log.info("特征池创建操作开始:[{}}", poolId);
try {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(poolId);
XContentBuilder builder = getCreateIndexXContentBuilder();
createIndexRequest.mapping(builder);
CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
List<Person> personPool = requestVo.getPersonPool();
if (personPool != null && personPool.size() > 0) {
BulkResponse bulkItemResponses = personService.addPerson(poolId, personPool);
if (bulkItemResponses != null) {
log.info(bulkItemResponses.buildFailureMessage());
}
}
log.info("特征池创建操作完成:[{}]", poolId);
return ResponseVo.success(rid);
} catch (ElasticsearchStatusException e) {
if (e.status() == RestStatus.BAD_REQUEST) {
return ResponseVo.error(rid, 20, "already exit poolId");
} else {
log.error("createPool", e);
return ResponseVo.error(rid, e.getDetailedMessage());
}
}
}
/**
* 删除特征池
*/
public ResponseVo deletePool(RequestVo requestVo) throws Exception {
String rid = requestVo.getRid();
Integer flushPool = requestVo.getFlushPool();
String poolId = requestVo.getPoolId();
log.info("特征池删除操作开始:[{}],FlushPool:[{}]", poolId, flushPool);
try {
if (0 == flushPool) {
List<HashMap<String, String>> personIds = requestVo.getPersonIds();
for (HashMap<String, String> item : personIds) {
String personId = item.get("personId");
if (personId != null) {
personService.deletePerson(poolId, personId);
}
}
} else if (flushPool == 1) {
AcknowledgedResponse delete = client.indices().delete(new DeleteIndexRequest(poolId), RequestOptions.DEFAULT);
}
log.info("特征池删除操作完成:[{}],FlushPool:[{}]", poolId, flushPool);
return ResponseVo.success(rid);
} catch (ElasticsearchStatusException e) {
if (e.status() == RestStatus.NOT_FOUND) {
return ResponseVo.error(rid, 4, "pollID not exist");
} else {
return ResponseVo.error(rid, e.getDetailedMessage());
}
}
}
/**
* 修改特征池(添加人员)
*/
public ResponseVo modifyPool(RequestVo requestVo) throws Exception {
String rid = requestVo.getRid();
String poolId = requestVo.getPoolId();
List<Person> personPool = requestVo.getPersonPool();
Integer updateType = requestVo.getUpdateType();
log.info("特征池修改操作开始:[{}],updateType:[{}]", poolId, updateType);
try {
BulkResponse bulkItemResponses = personService.addPerson(poolId, personPool);
if (bulkItemResponses != null && bulkItemResponses.hasFailures()) {
log.info(bulkItemResponses.buildFailureMessage());
}
log.info("特征池修改操作完成:[{}],updateType:[{}]", poolId, updateType);
return ResponseVo.success(rid, "success");
} catch (ElasticsearchStatusException e) {
log.error("modifyPool", e);
return ResponseVo.error(rid, e.getDetailedMessage());
}
}
/**
* 查询特征池信息
*/
public ResponseVo queryPool(RequestVo requestVo) throws Exception {
String rid = requestVo.getRid();
Integer listAll = requestVo.getListAll();
String poolId = requestVo.getPoolId();
try {
List<PoolInfo> poolInfos = new ArrayList<>();
if (listAll != 0) {
poolId = "*";
}
log.info("查询特征池操作开始:[{}],ListAll:[{}]", poolId, listAll);
GetIndexResponse response = client.indices().get(new GetIndexRequest(poolId), RequestOptions.DEFAULT);
String[] indices = response.getIndices();
for (String index : indices) {
PoolInfo poolInfo = new PoolInfo();
poolInfo.setPoolId(index);
CountRequest countRequest = new CountRequest(index);
CountResponse count = client.count(countRequest, RequestOptions.DEFAULT);
poolInfo.setPersonCount(count.getCount());
poolInfos.add(poolInfo);
}
ResponseVo success = ResponseVo.success(rid, "success");
success.setPoolIds(poolInfos);
log.info("查询特征池操作完成:[{}],ListAll:[{}]", poolId, listAll);
return success;
} catch (ElasticsearchStatusException e) {
log.error("queryPool", e);
return ResponseVo.error(rid, e.getDetailedMessage());
}
}
public XContentBuilder getCreateIndexXContentBuilder() throws IOException {
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
{
builder.startObject("properties");
{
builder.startObject("data");
{
builder.field("type", "dense_vector");
builder.field("dims", 512);
}
builder.endObject();
builder.startObject("personId");
{
builder.field("type", "keyword");
}
builder.endObject();
builder.startObject("fid");
{
builder.field("type", "text");
}
builder.endObject();
builder.startObject("age");
{
builder.field("type", "integer");
}
builder.endObject();
builder.startObject("gender");
{
builder.field("type", "keyword");
}
builder.endObject();
}
builder.endObject();
}
builder.endObject();
return builder;
}
public boolean existPool(String poolId) throws IOException {
return client.indices().exists(new GetIndexRequest(poolId), RequestOptions.DEFAULT);
}
}
package com.viontech.match.test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.viontech.keliu.model.Person;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
/**
* .
*
* @author 谢明辉
* @date 2020/11/19
*/
@Component
public class AlgUtil {
@Resource
private RestTemplateBuilder restTemplateBuilder;
public Object matchPerson(String poolId, Person person) {
RestTemplate restTemplate = restTemplateBuilder.build();
MatchPersonRequestBody matchPersonRequestBody = new MatchPersonRequestBody(Arrays.asList(person.getFaceFeatures().get(0).getFeature()));
ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://127.0.0.1:9200/" + poolId.toLowerCase() + "/_search", matchPersonRequestBody, String.class);
return responseEntity.getBody();
}
public Object addPerson(String poolId, Person person) throws JsonProcessingException {
RestTemplate restTemplate = restTemplateBuilder.build();
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString());
HashMap<String, Object> req = new HashMap<>();
req.put("personId", person.getPersonId());
req.put("data", person.getFaceFeatures().get(0).getFeature());
HttpEntity<HashMap> httpEntity = new HttpEntity<>(req, headers);
ResponseEntity<String> response = restTemplate.exchange("http://127.0.0.1:9200/" + poolId.toLowerCase() + "/_doc/" + person.getPersonId(), HttpMethod.PUT, httpEntity, String.class);
return response.getBody();
}
public Object createPersonPool(String poolId) {
RestTemplate restTemplate = restTemplateBuilder.build();
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString());
HttpEntity<String> stringHttpEntity = new HttpEntity<>("{\"mappings\":{\"properties\":{\"data\":{\"type\":\"dense_vector\",\"dims\":512},\"personId\":{\"type\":\"keyword\"}}}}", headers);
ResponseEntity<HashMap> exchange = restTemplate.exchange("http://127.0.0.1:9200/" + poolId.toLowerCase(), HttpMethod.PUT, stringHttpEntity, HashMap.class);
HashMap body = exchange.getBody();
return body;
}
public Object deletePersonPool(String poolId) {
try {
RestTemplate restTemplate = restTemplateBuilder.build();
ResponseEntity<HashMap> exchange = restTemplate.exchange("http://127.0.0.1:9200/" + poolId.toLowerCase(), HttpMethod.DELETE, null, HashMap.class);
return exchange.getBody();
} catch (HttpClientErrorException e) {
int rawStatusCode = e.getRawStatusCode();
if (rawStatusCode != HttpStatus.NOT_FOUND.value()) {
return "failed";
} else {
return "success";
}
}
}
}
# database
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://pgm-2ze197c18ro6p1r1fo.pg.rds.aliyuncs.com:3433/ShoppingMall_retail2.0
spring.datasource.username=vion
spring.datasource.password=cdmqYwBq9uAdvLJb
# oss
oss.config.endPoint=oss-cn-beijing.aliyuncs.com
oss.config.accessKeyId=LTAI9WfUr3GDne4c
oss.config.accessKeySecret=SDzMs26kNyiDIIRJIY2qUBxBOeUEZ8
oss.config.bucket=vion-retail
# ws
ws.featureUrl=http://101.200.130.13:10000
# other # other
server.port=12000 server.port=12000
spring.jackson.time-zone=GMT+8 spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# es # es
spring.elasticsearch.rest.uris=http://139.217.100.35:9200
\ No newline at end of file \ No newline at end of file
spring.elasticsearch.rest.uris=http://192.168.9.116:9200
\ No newline at end of file \ No newline at end of file
spring: spring:
profiles: profiles:
active: option active: option
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
default-property-inclusion: non_null
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<property name="log.path" value="logs"/>
<property name="pattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger{50} - %msg%n"/>
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
<encoder>
<Pattern>${pattern}</Pattern>
<!-- 设置字符集 -->
</encoder>
</appender>
<!--输出到文件-->
<!-- 时间滚动输出 level为 DEBUG 日志 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_debug.log</file>
<!--日志文件输出格式-->
<encoder>
<Pattern>${pattern}</Pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<Pattern>${pattern}</Pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>NEUTRAL</onMismatch>
</filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<Pattern>${pattern}</Pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>5</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<Pattern>${pattern}</Pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<logger name="com.viontech.match" level="debug">
<appender-ref ref="DEBUG_FILE"/>
</logger>
<root level="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</configuration>
\ No newline at end of file \ No newline at end of file
package com.viontech.match; package com.viontech.match;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.viontech.keliu.storage.Storage;
import com.viontech.keliu.util.DateUtil;
import com.viontech.match.entity.*;
import com.viontech.match.repository.FaceRecognitionRepository;
import com.viontech.match.service.AlgService;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* . * .
* *
...@@ -42,137 +15,5 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -42,137 +15,5 @@ import java.util.concurrent.atomic.AtomicInteger;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
public class Test0 { public class Test0 {
private final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(20, 30, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
private final AtomicInteger integer = new AtomicInteger();
private final PoolEnum pool = PoolEnum.POOL_50W;
@Resource
ObjectMapper objectMapper;
@Resource
private AlgService algService;
@Resource
private FaceRecognitionRepository faceRecognitionRepository;
@Resource
private Storage featureStorage;
@Resource
private RestHighLevelClient client;
@Test
public void createPoolTest() throws IOException {
Object test2 = algService.createPool(pool.name);
System.out.println(test2);
}
@Test
public void deleteIndexTest() throws IOException {
algService.deletePool(pool.name);
}
@Test
public void queryIndex() throws IOException {
String[] strings = algService.queryPoolList();
HashMap<String, Object> result = new HashMap<>();
for (String item : strings) {
CountResponse count = client.count(new CountRequest(item), RequestOptions.DEFAULT);
long count1 = count.getCount();
result.put(item, count1);
}
System.out.println(result.toString());
}
@Test
public void addPersonTest() throws IOException {
Person person1 = getPerson("3");
Object test2 = algService.addPerson(person1, pool.name);
System.out.println(objectMapper.writeValueAsString(test2));
}
@Test
public void matchPersonTest() throws Exception {
Person person = getPerson("3");
List<MatchResult> test2 = algService.matchPerson(person, pool.name);
System.out.println(objectMapper.writeValueAsString(test2));
}
@Test
public void batchAdd() throws ParseException, IOException, InterruptedException {
algService.deletePool(pool.name);
algService.createPool(pool.name);
Date start = DateUtil.parse(DateUtil.FORMAT_SHORT, "2020-11-01");
Date end = DateUtil.parse(DateUtil.FORMAT_SHORT, "2020-11-24");
int i = 0;
List<Date> days = DateUtil.getDaysBetweenDates(start, end);
for (Date day : days) {
List<FaceRecognition> faceRecognitions = faceRecognitionRepository.queryFaceRecognitions(day, 2L);
for (FaceRecognition faceRecognition : faceRecognitions) {
poolExecutor.execute(() -> {
try {
if (integer.get() >= pool.num) {
return;
}
Double[] feature = getFeature(faceRecognition);
if (feature == null) {
return;
}
Person person = new Person();
person.setPersonId(faceRecognition.getPersonUnid());
person.setFeature(feature);
person.setId(faceRecognition.getUnid());
Object o = algService.addPerson(person, pool.name);
System.out.println(objectMapper.writeValueAsString(o));
integer.addAndGet(1);
} catch (Exception e) {
e.printStackTrace();
}
});
if (integer.get() > pool.num) {
return;
}
while (poolExecutor.getQueue().size() > 1000) {
System.out.println(poolExecutor.getQueue().size());
TimeUnit.SECONDS.sleep(10);
}
if (integer.get() > pool.num) {
return;
}
}
}
}
private Double[] getFeature(FaceRecognition face) throws JsonProcessingException {
Short faceFeatureType = face.getFaceFeatureType();
String facePic = face.getFacePic();
if (faceFeatureType == 1) {
facePic = facePic.replace("face-0.jpg", "face-F.jpg");
}
String json = (String) featureStorage.getItem(face.getChannelSerialnum() + "/" + facePic);
Feature feature = objectMapper.readValue(json, Feature.class);
List<Data> datas = feature.getDatas();
if (datas != null && datas.size() > 0) {
Data data = datas.get(0);
Double[] data1 = data.getData();
if (data1.length == 512) {
return data1;
}
}
return null;
}
public Person getPerson(String id) throws IOException {
Path path = Paths.get("C:\\Users\\vion\\Desktop\\" + id + ".feature");
String featureStr = Files.readAllLines(path).get(0);
Feature feature = objectMapper.readValue(featureStr, Feature.class);
Double[] data = feature.getDatas().get(0).getData();
Person person = new Person();
person.setPersonId(UUID.randomUUID().toString());
person.setFeature(data);
return person;
}
} }
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!