`

如何用redis实现“搜索历史”和“自动补全”搜索框

阅读更多

搜索框的附加功能

 

在日常的web开发中,经常有搜索框功--在一批数据中检索自己需要的数据。现在的百度以及各大电商的搜索框都做得很人性化,主要体现在两个方面:

 

一、搜索框的搜索历史:为了方便用户下次搜索,搜索框通常会提供搜索历史功能 即:记录下用户的搜索历史,用户下次点击搜索框就会立即展示你最近的搜索记录列表。如果用户经常搜索的关键字,下次不用手动输入,直接选择即可。



 

用户的搜索历史相当关键,这是电商网站做智能推荐的基石。比如上述搜索列表,反映出三类信息:羽毛球相关、java、汽车周边。根据一系列智能算法 很快就能推算出该用户喜欢的商品。

 

这个功能即可以方便用户减少输入,又可以衍生出一些新服务,可谓一箭双雕。

 

二、搜索框的“自动匹配”:当用户输入关键词的头一个或几个字 就会出现一个自动匹配列表,用户直接选择自己想要搜索的关键字即可,不用输入完整的关键词。



 

 

上面这个截图来自百度搜索框的自动匹配,同时整合了搜索历史的功能,其中蓝色的关键词是用户的搜索历史

 

 “搜索历史自动匹配功能的本质是向前面页面返回一个关键字列表 要实现一个体验好的搜索框,关键就是快速响应页面的获取“关键字列表”请求;否则如果太慢 用户都输入完成了,“关键字列表”还没有刷新出来,这个功能就没有意义了。

 

百度搜索框 把这两个功能都做到了极致,而且的用户量很庞大,关键词的存储量就更庞大了。百度的具体实现笔者不是很清楚,猜测是通过ES+各种Hash分组实现的。庆幸的是我们不必去实现一个百度,在一个普通的系统里没有太大的用户量和关键词(相对于百度),要实现这两个功能 使用redis就可以完全满足需求了。

 

采用redislist实现搜索历史

 

采用redislist存储每个用户的搜索历史列表,存储规则:最近搜索过的关键词的放在最前面(这里有两层含义:最近搜索新关键词、最近搜索老关键词),并且每个用户只保留最近访问过的5个关键词(5个太少,这里只是举例,可以根据自己业务调整)。List对应的key规则为:recent_search_{userId},redis中存储示意图如下:



 

 

本示例采用javaJedis进行代码实现,要实现这个功能只需要两个方法即可:一个是更新搜索历史方法(对应下列updateList方法);一个是匹配“搜索历史”方法(对应下列getAutoMatchs),具体实现如下:

/**
 * Created by gantianxing on 2017/11/16.
 */
@Component
public class RecentSearchService {
    @Resource
    private Jedis redis;
 
    /**
     * 更新搜索历史列表
     * @param userId 用户id
     * @param searchkey 本次搜索关键词
     */
    public void updateList(Integer userId,String searchkey){
        String key = "recent_search_"+userId;
        //为了保证事务和性能,采用pipeline
        Pipeline pipeline = redis.pipelined();
        pipeline.lrem(key,1,searchkey);//如果该关键词已存在先删除
        pipeline.lpush(key, searchkey);//把该关键词放在最顶部(左边)
        pipeline.ltrim(key, 0, 4);//裁剪list 保留最近的5个关键词
        pipeline.sync();//批量提交命令
    }
 
    /**
     * 从搜索历史列表中获取匹配的列表
     * @param userId
     * @param pre
     * @return
     */
    public List<String> getAutoMatchs(Integer userId,String pre){
        String key = "recent_search_"+userId;
        List<String> all = redis.lrange(key,0,-1);//获取该用户对应的“搜索历史列表”
        if(all == null){
            return null;
        }
        if(pre!=null && pre.length()>0){
            List<String> matchList = new ArrayList<>();
            for(String one:all){
                //前缀匹配
                if(one.startsWith(pre)){
                    matchList.add(one);
                }
            }
            return matchList;//返回匹配到的“搜索历史列表”
        }else {
            return all;//用户还没有输入,就返回所有的“搜索历史列表”
        }
    }
}
 

 

可以看到整个存储和查询都是在redis中进行,性能和效率是mysql等传统数据库无法比拟的。

 

采用redislist实现自动匹配

 

搜索历史的实现过程中已经实现了自动匹配 getAutoMatchs方法,这里只需把每个用户的搜索历史列表替换成“关键词词库”。“关键词词库”怎么来,通过一些分词工具分词,然后再归类后通过hash规则放到不同的服务器,百度词库的实现应该采用类似的技术手段。

 

如果只是一个普通的一个小系统,可以通过手动导入一些与自己系统相关的词库到redis即可。假设现在我们已经把词库导入到redislist中了(对应keyall_key_words,稍微更下getAutoMatchs方法 就可以实现默认的自动匹配”:

/**
     * 从词库列表中获取匹配的列表
     * @param pre
     * @return
     */
    public List<String> getDefaultAutoMatchs(String pre){
        String key = "all_key_words";
        List<String> all = redis.lrange(key,0,-1);//获取“关键词词库列表”
        if(all == null){
            return null;
        }
        if(pre!=null && pre.length()>0){
            List<String> matchList = new ArrayList<>();
            for(String one:all){
                //前缀匹配
                if(one.startsWith(pre)){
                    matchList.add(one);
                }
            }
            return matchList;//返回匹配到的“关键词词库列表”
        }else {
            return all;//用户还没有输入,就返回所有的“关键词词库列表”
        }
    }
 

 

实现起来很简单,但是如果采用list存储“关键词词库列表”,需要注意的是all_key_words对应的“关键词词库列表”中的关键词数量不能太多(如果采用这种方式,建议词库中的数量不要超过100)。如果太多会导致匹配过程相当缓慢,严重影响该功能的性能。

 

如何优化呢?有两种办法:一、对词库进行分组,把一个list变为多个list,在匹配之前首先确定关键词所在的分组;二、采用rediszset数据结构存储“关键词词库”,zset中每项成员名的存储内容为关键词,成员值 score都设置为0,此时zset的排序会按照成员名进行。其实还可以把两种方案合并使用,效果会更好一些 即:首先对词库进行分组,每个分组采用rediszset数据结构存储。

 

为什么要使用zset数据结构,因为zset采用了跳表结构设计,可以快速的进行范围查询检索。但实用zset存储在进行检索时想对比较复杂:

1、先生成前缀关键字对应的起始值。

2、通过zadd命令把起始值插入到zset中。

3、通过zrank命令计算这两个位置的indexstart_indexend_index

4、通过zrem删除步骤2中插入的起始值(它们的作用仅仅为了找到start_indexend_index)。

5、最后通过zrange命令取出这个start_index end_index之间的所有 关键字即可。

这里就不再展示但实现,可以根据这个逻辑自行编码。

 

小结

 

现在的各大电商网站都有搜索框,而且“搜索历史”和“自动匹配功能”几乎都是标配。另外由于redis中会对搜索记录进行裁剪,一般会在用户搜索时还会进行日志上报,把用户的搜索记录流水全部记录到日志服务器,再通过日志整理汇集到hadoop等大数据平台。最后通过各种算法计算,为用户进行精准推荐,这些数据都是智能推荐的基础。

 

为自己的系统做一个好的搜索框,在增加用户体验的同时,还可以做一些附件的推荐类产品。建议有类似场景的系统,都可以尝试下。

 

 

  • 大小: 12.1 KB
  • 大小: 4.3 KB
  • 大小: 20.5 KB
2
1
分享到:
评论
1 楼 masuweng 2017-11-18  
        谢谢

相关推荐

    自动搜索(如百度搜索)asp.net应用

    自动搜索,也称为自动补全或预测搜索,它为用户提供了一个方便、高效的搜索体验,通过用户输入的部分关键词就能预测并显示可能的完整搜索词。在本案例中,我们将探讨如何在ASP.NET应用中实现类似百度首页的自动搜索...

    autosuggest_v21.3

    1. 搜索引擎:Google、Bing等搜索引擎的搜索框中广泛使用自动补全,帮助用户快速找到目标信息。 2. 输入法:如百度输入法、搜狗输入法等,通过自动补全提供候选词,提高打字效率。 3. 社交媒体:Twitter、微信等...

    基于ASPNET搜索引擎设计与实现(20210809124818).pdf

    3.3 用户体验优化:提供模糊匹配、自动补全、相关搜索等功能,提升用户交互体验。 四、性能优化与扩展性 4.1 并发处理:ASP.NET支持多线程和异步编程,通过Task Parallel Library(TPL)处理高并发请求。 4.2 ...

    搜所的实现

    9. **搜索建议与自动补全**:为了提供更好的用户体验,许多搜索系统还会提供搜索建议和自动补全功能,这通常基于历史查询数据、热门词汇或实时搜索热度。 通过以上步骤,我们可以构建一个基本的搜索功能。然而,...

    autocompletex:lix剂的redis自动完成

    2. **Redis数据库**:Redis提供了丰富的数据结构(如字符串、哈希、列表、集合和有序集合),适合存储临时数据和实现高性能的读写操作。它的订阅/发布功能也使其成为实时数据流处理的良好选择。 3. **自动完成原理*...

    仿google自动提示

    标题中的“仿google自动提示”指的是模仿谷歌搜索引擎的自动补全功能,这是一种常见的用户体验优化技术。在用户输入搜索关键词时,系统会根据已输入的部分文字预测用户可能想要搜索的完整词汇或短语,并将这些预测...

    实现类似于google搜索提示的功能

    这种功能通常被称为自动补全或预测搜索。以下是一些实现这一功能的关键知识点和方法: 1. **前端技术**: - **HTML/CSS/JavaScript**:这是构建任何Web应用的基础,JavaScript是实现动态搜索提示的核心,可以监听...

    Springboot校园拼车微信小程序(源码+数据库)091617

    下面将详细阐述这个项目中的核心技术和实现功能。 1. **Spring Boot**:作为后端开发框架,Spring Boot简化了Spring应用程序的初始搭建以及配置过程,提供了自动配置、起步依赖等特性,使得开发者可以快速地构建...

    按照名字找地址按照地址找名字工程

    - 设计直观的搜索框,支持模糊匹配和自动补全功能。 - 显示结果列表,可按相关性或字母顺序排序。 - 提供地图视图,让用户直观看到地址位置。 9. 版本控制: "调试ok_ATTACH 版本"可能表示项目经过调试并达到...

    运维实践指南

    此外,还包括对Bash快捷键的说明,比如用`Ctrl + r`实现命令的反向搜索,以及如何使用Bang(!)命令重新执行历史命令。 #### Linux工具 Linux工具部分可能会介绍一些高效的命令行工具,如文本处理工具`sed`和`awk`,...

    SearchEngineWeb:这是一个搜索引擎 Web 应用程序

    - **搜索建议与自动补全**: 为了提升用户体验,项目可能实现了搜索建议功能,根据用户输入的部分关键字实时提供可能的完整查询建议。 - **排序算法**: 搜索结果通常按相关性排序,项目可能涉及多种排序算法,如...

    search

    - **自动补全**:预测并提供用户可能的搜索词,提高输入效率。 - **即时搜索**:用户输入时即显示部分结果,提供实时反馈。 - **个性化搜索**:根据用户的历史行为和偏好调整搜索结果。 6. 分布式搜索: - **...

Global site tag (gtag.js) - Google Analytics