1.首先就是编辑距离算法,此处匹配的是两个字符串,由于标签不止一个,我们需要进行适当的修改
/**
* 编辑距离算法,(用于计算距离相近的字符串)
* @param word1
* @param word2
* @return
*/
public int minDistance(String word1, String word2){
int n = word1.length();
int m = word2.length();
if(n * m == 0)
return n + m;
int[][] d = new int[n + 1][m + 1];
for (int i = 0; i < n + 1; i++){
d[i][0] = i;
}
for (int j = 0; j < m + 1; j++){
d[0][j] = j;
}
for (int i = 1; i < n + 1; i++){
for (int j = 1; j < m + 1; j++){
int left = d[i - 1][j] + 1;
int down = d[i][j - 1] + 1;
int left_down = d[i - 1][j - 1];
if (word1.charAt(i - 1) != word2.charAt(j - 1))
left_down += 1;
d[i][j] = Math.min(left, Math.min(down, left_down));
}
}
return d[n][m];
}
}
修改过后的匹配算法
/**
* 编辑距离算法,(用于计算距离相近的标签)
* @param tagList1
* @param tagList2
* @return
*/
public static int minDistance(List<String> tagList1, List<String> tagList2){
int n = tagList1.size();
int m = tagList2.size();
if(n * m == 0)
return n + m;
int[][] d = new int[n + 1][m + 1];
for (int i = 0; i < n + 1; i++){
d[i][0] = i;
}
for (int j = 0; j < m + 1; j++){
d[0][j] = j;
}
for (int i = 1; i < n + 1; i++){
for (int j = 1; j < m + 1; j++){
int left = d[i - 1][j] + 1;
int down = d[i][j - 1] + 1;
int left_down = d[i - 1][j - 1];
if (!Objects.equals(tagList1.get(i-1), tagList2.get(j - 1)))
left_down += 1;
d[i][j] = Math.min(left, Math.min(down, left_down));
}
}
return d[n][m];
}
我的项目是每个用户都会有标签,设置开启匹配模式,也就是说展示匹配之后的用户,实现方法如下
controller层
/**
* 匹配用户
* @param num
* @param request
* @return
*/
@GetMapping("/match")
public List<User> matchUsers(long num, HttpServletRequest request){
if (num==0 || num>20){
throw new BusinessException(ErrorCode.NULL_ERROR);
}
User loginUser = userService.getLoginUser(request);
return userService.matchUsers(num,loginUser);
}
service层
List<User> matchUsers(long num, User loginUser);
serviceimpl层
@Override
public List<User> matchUsers(long num, User loginUser) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//选择要查询的列
queryWrapper.select("id","tags");
queryWrapper.isNotNull("tags");
//遍历所有用户
List<User> userList = this.list(queryWrapper);
//获取当前用户的tags,并且将字符串转换为列表形式
String tags = loginUser.getTags();
Gson gson = new Gson();
List<String> tagList = gson.fromJson(tags, new TypeToken<List<String>>() {
}.getType());
//用户下表相似度
List<Pair<User,Long>> list = new ArrayList<>();
//获得所有用户与登陆用户的相似度
for (int i=0 ; i < userList.size();i++) {
//将所有用户的标签搜索出,然后将字符串转换为列表
User user = userList.get(i);
String userTags = user.getTags();
//如果userTags或者遍历到当前登录用户,返回
if (StringUtils.isBlank(userTags) || user.getId()==loginUser.getId()){
continue;
}
//将gson格式的字符串转化为java对象列表
List<String> userTagList = gson.fromJson(userTags, new TypeToken<List<String>>() {
}.getType());
//与当前登录用户进行比较,返回分数
long distance = AlgorithmUtils.minDistance(tagList, userTagList);
list.add(new Pair<>(user,distance));
}
//将编辑距离由小到大排序
List<Pair<User, Long>> topUserPairList = list.stream()
.sorted((a, b) -> (int) (a.getValue() - b.getValue()))
.limit(num)
.collect(Collectors.toList());
// 获取id列表
List<Long> userIdlist =topUserPairList.stream().map(pair -> pair.getKey().getId()).collect(Collectors.toList());
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
//查询id是否包含在useridlist
userQueryWrapper.in("id",userIdlist);
//用户脱敏,转换为key是id的map
Map<Long, List<User>> userIdUserListMap = this.list(userQueryWrapper)
.stream()
.map(user -> getSafetyUser(user))
.collect(Collectors.groupingBy(User::getId));
//创建一个新的列表,
List<User> finalUserList = new ArrayList<>();
for (Long userId : userIdlist) {
//获取map的值
finalUserList.add(userIdUserListMap.get(userId).get(0));
}
return finalUserList;
}
其中num这个参数指的是你所要展示的条数,就是匹配出来的之后展示的由大到小前几条