这篇文章主要介绍“怎么使用java和redis实现一个简单的热搜功能”,在日常操作中,相信很多人在怎么使用java和redis实现一个简单的热搜功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用java和redis实现一个简单的热搜功能”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

具备以下功能:

1:搜索栏展示当前登陆的个人用户的搜索历史记录,删除个人历史记录

2:用户在搜索栏输入某字符,则将该字符记录下来 以zset格式存储的redis中,记录该字符被搜索的个数以及当前的时间戳 (用了DFA算法,感兴趣的自己百度学习吧)

3:每当用户查询了已在redis存在了的字符时,则直接累加个数, 用来获取平台上最热查询的十条数据。 (可以自己写接口或者直接在redis中添加一些预备好的关键词)

4:最后还要做不雅文字过滤功能。这个很重要不说了你懂的。

代码实现热搜与个人搜索记录功能,主要controller层下几个方法就行了 :

1:向redis 添加热搜词汇(添加的时候使用下面不雅文字过滤的方法来过滤下这个词汇,合法再去存储

2:每次点击给相关词热度 +1

3: 根据key搜索相关最热的前十名

4:插入个人搜索记录

5:查询个人搜索记录

首先配置好redis数据源等等基础

最后贴上核心的 服务层的代码 :

packagecom.****.****.****.user;importcom.jianlet.service.user.RedisService;importorg.apache.commons.lang.StringUtils;importorg.springframework.data.redis.core.*;importorg.springframework.stereotype.Service;importjavax.annotation.Resource;importjava.util.*;importjava.util.concurrent.TimeUnit;/***@author:mrwanghc*@date:2020/5/13*@description:*/@Transactional@Service("redisService")publicclassRedisServiceImplimplementsRedisService{//导入数据源@Resource(name="redisSearchTemplate")privateStringRedisTemplateredisSearchTemplate;//新增一条该userid用户在搜索栏的历史记录//searchkey代表输入的关键词@OverridepublicintaddSearchHistoryByUserId(Stringuserid,Stringsearchkey){Stringshistory=RedisKeyUtils.getSearchHistoryKey(userid);booleanb=redisSearchTemplate.hasKey(shistory);if(b){Objecthk=redisSearchTemplate.opsForHash().get(shistory,searchkey);if(hk!=null){return1;}else{redisSearchTemplate.opsForHash().put(shistory,searchkey,"1");}}else{redisSearchTemplate.opsForHash().put(shistory,searchkey,"1");}return1;}//删除个人历史数据@OverridepublicLongdelSearchHistoryByUserId(Stringuserid,Stringsearchkey){Stringshistory=RedisKeyUtils.getSearchHistoryKey(userid);returnredisSearchTemplate.opsForHash().delete(shistory,searchkey);}//获取个人历史数据列表@OverridepublicList<String>getSearchHistoryByUserId(Stringuserid){List<String>stringList=null;Stringshistory=RedisKeyUtils.getSearchHistoryKey(userid);booleanb=redisSearchTemplate.hasKey(shistory);if(b){Cursor<Map.Entry<Object,Object>>cursor=redisSearchTemplate.opsForHash().scan(shistory,ScanOptions.NONE);while(cursor.hasNext()){Map.Entry<Object,Object>map=cursor.next();Stringkey=map.getKey().toString();stringList.add(key);}returnstringList;}returnnull;}//新增一条热词搜索记录,将用户输入的热词存储下来@OverridepublicintincrementScoreByUserId(Stringsearchkey){Longnow=System.currentTimeMillis();ZSetOperationszSetOperations=redisSearchTemplate.opsForZSet();ValueOperations<String,String>valueOperations=redisSearchTemplate.opsForValue();List<String>title=newArrayList<>();title.add(searchkey);for(inti=0,lengh=title.size();i<lengh;i++){Stringtle=title.get(i);try{if(zSetOperations.score("title",tle)<=0){zSetOperations.add("title",tle,0);valueOperations.set(tle,String.valueOf(now));}}catch(Exceptione){zSetOperations.add("title",tle,0);valueOperations.set(tle,String.valueOf(now));}}return1;}//根据searchkey搜索其相关最热的前十名(如果searchkey为null空,则返回redis存储的前十最热词条)@OverridepublicList<String>getHotList(Stringsearchkey){Stringkey=searchkey;Longnow=System.currentTimeMillis();List<String>result=newArrayList<>();ZSetOperationszSetOperations=redisSearchTemplate.opsForZSet();ValueOperations<String,String>valueOperations=redisSearchTemplate.opsForValue();Set<String>value=zSetOperations.reverseRangeByScore("title",0,Double.MAX_VALUE);//key不为空的时候推荐相关的最热前十名if(StringUtils.isNotEmpty(searchkey)){for(Stringval:value){if(StringUtils.containsIgnoreCase(val,key)){if(result.size()>9){//只返回最热的前十名break;}Longtime=Long.valueOf(valueOperations.get(val));if((now-time)<2592000000L){//返回最近一个月的数据result.add(val);}else{//时间超过一个月没搜索就把这个词热度归0zSetOperations.add("title",val,0);}}}}else{for(Stringval:value){if(result.size()>9){//只返回最热的前十名break;}Longtime=Long.valueOf(valueOperations.get(val));if((now-time)<2592000000L){//返回最近一个月的数据result.add(val);}else{//时间超过一个月没搜索就把这个词热度归0zSetOperations.add("title",val,0);}}}returnresult;}//每次点击给相关词searchkey热度+1@OverridepublicintincrementScore(Stringsearchkey){Stringkey=searchkey;Longnow=System.currentTimeMillis();ZSetOperationszSetOperations=redisSearchTemplate.opsForZSet();ValueOperations<String,String>valueOperations=redisSearchTemplate.opsForValue();zSetOperations.incrementScore("title",key,1);valueOperations.getAndSet(key,String.valueOf(now));return1;}}

核心的部分写完了,剩下的需要你自己将如上方法融入到你自己的代码中就行了。

代码实现过滤不雅文字功能,在springboot 里面写一个配置类加上@Configuration注解,在项目启动的时候加载一下,代码如下:

packagecom.***.***.interceptor;importorg.springframework.context.annotation.Configuration;importorg.springframework.core.io.ClassPathResource;importjava.io.*;importjava.util.HashMap;importjava.util.HashSet;importjava.util.Map;importjava.util.Set;//屏蔽敏感词初始化@Configuration@SuppressWarnings({"rawtypes","unchecked"})publicclassSensitiveWordInit{//字符编码privateStringENCODING="UTF-8";//初始化敏感字库publicMapinitKeyWord()throwsIOException{//读取敏感词库,存入Set中Set<String>wordSet=readSensitiveWordFile();//将敏感词库加入到HashMap中//确定有穷自动机DFAreturnaddSensitiveWordToHashMap(wordSet);}//读取敏感词库,存入HashMap中privateSet<String>readSensitiveWordFile()throwsIOException{Set<String>wordSet=null;ClassPathResourceclassPathResource=newClassPathResource("static/censorword.txt");InputStreaminputStream=classPathResource.getInputStream();//敏感词库try{//读取文件输入流InputStreamReaderread=newInputStreamReader(inputStream,ENCODING);//文件是否是文件和是否存在wordSet=newHashSet<String>();//StringBuffersb=newStringBuffer();//BufferedReader是包装类,先把字符读到缓存里,到缓存满了,再读入内存,提高了读的效率。BufferedReaderbr=newBufferedReader(read);Stringtxt=null;//读取文件,将文件内容放入到set中while((txt=br.readLine())!=null){wordSet.add(txt);}br.close();//关闭文件流read.close();}catch(Exceptione){e.printStackTrace();}returnwordSet;}//将HashSet中的敏感词,存入HashMap中privateMapaddSensitiveWordToHashMap(Set<String>wordSet){//初始化敏感词容器,减少扩容操作MapwordMap=newHashMap(wordSet.size());for(Stringword:wordSet){MapnowMap=wordMap;for(inti=0;i<word.length();i++){//转换成char型charkeyChar=word.charAt(i);//获取ObjecttempMap=nowMap.get(keyChar);//如果存在该key,直接赋值if(tempMap!=null){nowMap=(Map)tempMap;}//不存在则,则构建一个map,同时将isEnd设置为0,因为他不是最后一个else{//设置标志位Map<String,String>newMap=newHashMap<String,String>();newMap.put("isEnd","0");//添加到集合nowMap.put(keyChar,newMap);nowMap=newMap;}//最后一个if(i==word.length()-1){nowMap.put("isEnd","1");}}}returnwordMap;}}

然后这是工具类代码 :

packagecom.***.***.interceptor;importjava.io.IOException;importjava.util.HashSet;importjava.util.Iterator;importjava.util.Map;importjava.util.Set;//敏感词过滤器:利用DFA算法进行敏感词过滤publicclassSensitiveFilter{//敏感词过滤器:利用DFA算法进行敏感词过滤privateMapsensitiveWordMap=null;//最小匹配规则publicstaticintminMatchType=1;//最大匹配规则publicstaticintmaxMatchType=2;//单例privatestaticSensitiveFilterinstance=null;//构造函数,初始化敏感词库privateSensitiveFilter()throwsIOException{sensitiveWordMap=newSensitiveWordInit().initKeyWord();}//获取单例publicstaticSensitiveFiltergetInstance()throwsIOException{if(null==instance){instance=newSensitiveFilter();}returninstance;}//获取文字中的敏感词publicSet<String>getSensitiveWord(Stringtxt,intmatchType){Set<String>sensitiveWordList=newHashSet<String>();for(inti=0;i<txt.length();i++){//判断是否包含敏感字符intlength=CheckSensitiveWord(txt,i,matchType);//存在,加入list中if(length>0){sensitiveWordList.add(txt.substring(i,i+length));//减1的原因,是因为for会自增i=i+length-1;}}returnsensitiveWordList;}//替换敏感字字符publicStringreplaceSensitiveWord(Stringtxt,intmatchType,StringreplaceChar){StringresultTxt=txt;//获取所有的敏感词Set<String>set=getSensitiveWord(txt,matchType);Iterator<String>iterator=set.iterator();Stringword=null;StringreplaceString=null;while(iterator.hasNext()){word=iterator.next();replaceString=getReplaceChars(replaceChar,word.length());resultTxt=resultTxt.replaceAll(word,replaceString);}returnresultTxt;}/***获取替换字符串**@paramreplaceChar*@paramlength*@return*/privateStringgetReplaceChars(StringreplaceChar,intlength){StringresultReplace=replaceChar;for(inti=1;i<length;i++){resultReplace+=replaceChar;}returnresultReplace;}/***检查文字中是否包含敏感字符,检查规则如下:<br>*如果存在,则返回敏感词字符的长度,不存在返回0*@paramtxt*@parambeginIndex*@parammatchType*@return*/publicintCheckSensitiveWord(Stringtxt,intbeginIndex,intmatchType){//敏感词结束标识位:用于敏感词只有1位的情况booleanflag=false;//匹配标识数默认为0intmatchFlag=0;MapnowMap=sensitiveWordMap;for(inti=beginIndex;i<txt.length();i++){charword=txt.charAt(i);//获取指定keynowMap=(Map)nowMap.get(word);//存在,则判断是否为最后一个if(nowMap!=null){//找到相应key,匹配标识+1matchFlag++;//如果为最后一个匹配规则,结束循环,返回匹配标识数if("1".equals(nowMap.get("isEnd"))){//结束标志位为trueflag=true;//最小规则,直接返回,最大规则还需继续查找if(SensitiveFilter.minMatchType==matchType){break;}}}//不存在,直接返回else{break;}}if(SensitiveFilter.maxMatchType==matchType){if(matchFlag<2||!flag){//长度必须大于等于1,为词matchFlag=0;}}if(SensitiveFilter.minMatchType==matchType){if(matchFlag<2&&!flag){//长度必须大于等于1,为词matchFlag=0;}}returnmatchFlag;}}

在你代码的controller层直接调用方法判断即可:

//非法敏感词汇判断SensitiveFilterfilter=SensitiveFilter.getInstance();intn=filter.CheckSensitiveWord(searchkey,0,1);if(n>0){//存在非法字符logger.info("这个人输入了非法字符-->{},不知道他到底要查什么~userid-->{}",searchkey,userid);returnnull;}

也可将敏感文字替换*等字符 :

SensitiveFilterfilter=SensitiveFilter.getInstance();Stringtext="敏感文字";Stringx=filter.replaceSensitiveWord(text,1,"*");

最后刚才的 SensitiveWordInit.java 里面用到了 censorword.text 文件,放到你项目里面的 resources 目录下的 static 目录中,这个文件就是不雅文字大全,也需要您与时俱进的更新,项目启动的时候会加载该文件。

到此,关于“怎么使用java和redis实现一个简单的热搜功能”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!