场景
用户在输入时,往往需要根据输入内容匹配,按照热度排序推荐一些完整的内容,来减少用户输入,提升体验。我思考了一种少量数据的简单实现方式。使用redis的key来进行模糊匹配,然后根据热度进行排序输出;
实现思路
考虑热度是有时间效应,一个key,value不好办;然后想到了将时间和热度合并成一个,有了思路就可以考虑具体实现了。
将时间和热度转为int型,然后合并成一个long,就解决问题了。int最大值4294967295,热度达不到这么大,时间转换为例如:2022051217,以小时隔断,离最大值也差几千年,完全用不到这么久。完美解决。
先看看效果
redis中添加了如下数据
@Autowired
private RedissonClient redisson;
@PostConstruct
public void test() {
redisson.getAtomicLong("java开发").set(0);
redisson.getAtomicLong("javaScript").set(0);
redisson.getAtomicLong("java培训").set(0);
redisson.getAtomicLong("java面试题").set(0);
redisson.getAtomicLong("java开发工具").set(0);
redisson.getAtomicLong("java编程规范").set(0);
}
然后打开postMan或者ApiPost测试,输入”开发“
给”java开发“热度加1
再来输入”开发“看看效果
到这里就简单实现了这个功能,根据时间降低热度以后在做
接口代码
@RestController
@RequestMapping("/word")
public class WordTestController {
@Autowired
private RedissonClient redisson;
@PostMapping("/matching")
public List<WordEntity> matching(@RequestParam String text) {
Iterator<String> keys = redisson.getKeys().getKeysByPattern("*" + text + "*").iterator();
MutableList<WordEntity> result = Lists.mutable.of();
while(keys.hasNext()) {
String word = keys.next();
result.add(new WordEntity(word, redisson.getAtomicLong(word).get()));
}
Collections.sort(result);
return result;
}
@PostMapping("/addHot")
public int addHot(@RequestParam String word) {
int []hotAndTime = DataConversion.separateLong2int(redisson.getAtomicLong(word).get());
long newHotAndTime = DataConversion.combineTimeAndHot(System.currentTimeMillis(), hotAndTime[1] + 1);
redisson.getAtomicLong(word).set(newHotAndTime);
return hotAndTime[1] + 1;
}
}
实体类
public class WordEntity implements Comparable<WordEntity> {
/**
* 单词
*/
private String name;
/**
* 热度
*/
private int hot;
/**
* 最新更新时间
*/
private int time;
public WordEntity(String name, long hotAndTime) {
this.name = name;
setHotAndTime(hotAndTime);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHot() {
return hot;
}
public void setHot(int hot) {
this.hot = hot;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public void setHotAndTime(long hotAndTime) {
int data[] = DataConversion.separateLong2int(hotAndTime);
this.hot = data[1];
this.time = data[0];
}
@Override
public int compareTo(WordEntity o) {
Long t1 = DataConversion.combineIntToLong(this.time, this.hot);
Long t2 = DataConversion.combineIntToLong(o.time, o.hot);
return t2.compareTo(t1);
}
}
数据合并代码
public class DataConversion {
public static long combineTimeAndHot(long time, int hot) {
return combineIntToLong(timeStampToInt(time), hot);
}
/**
* 转为年月日时,例如:2022051216
* @param timeStamp
* @return
*/
public static int timeStampToInt(long timeStamp) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timeStamp);
StringBuilder builder = new StringBuilder();
builder.append(calendar.get(Calendar.YEAR));
int month = calendar.get(Calendar.MONTH) + 1;
if(month < 10) {
builder.append(0);
}
builder.append(month);
int day = calendar.get(Calendar.DAY_OF_MONTH);
if(day < 10) {
builder.append(0);
}
builder.append(day);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
if(hour < 10) {
builder.append(0);
}
builder.append(hour);
return Integer.valueOf(builder.toString());
}
/**
* 将两个int合并成一个long存储
* @param low 低位
* @param high 高位
* @return
*/
public static long combineIntToLong(int low, int high) {
return (long) low | (long) high << 32;
}
/**
* 将一个long存储的数据拆分成两个int,顺序按照合成顺序
* @param val
* @return
*/
public static int[] separateLong2int(long val) {
int[] ret = new int[2];
ret[0] = (int) (0xFFFFFFFFl & val);
ret[1] = (int) (val >> 32);
return ret;
}
}