基于 Redis 的实时搜索

本贴最后更新于 3247 天前,其中的信息可能已经事过境迁

一直想把前期做的一种完全基于redis的实时搜索功能的实现方式总结一下,但是一直没有合适的时间,今天终于可以坐下来把整个思路理一下了。
还是先看下整体效果,如下图所示。

search

该搜索是整个瑞知社区的一个功能项,瑞知社区类似于知乎,一个垂直问答社区,为了提高用户体验,所以希望在搜索功能上可以体验更好,可以逐字匹配搜索,可以按照拼音(不是拼音首字母)模糊搜索。由于该项目没有考虑使用关系型数据库,所以决定把所有的索引数据都放在内存中,获取查找目标过程完全基于内存,这样速度更快。

下面说说整个过程的实现思路,还有很多不完善的地方,敬请指教!

搜索的过程简单点说就是建立索引和按照索引取值的过程,对需要搜索的目标数据进行索引,然后将索引结果放入redis中,索引结果的数据结构可以根据实际情况来决定,比如我这里没有用到关系数据库,全部使用的是redis来存储,包括搜索目标数据,所以索引的数据结构是搜索关键词作为key,value中存入的是搜索目标在redis中存入时的key值;如果你使用的关系型数据库,比如mysql,那么这里的value可能存的就是对应数据库中记录的id值。当用户输入关键词进行搜索的时候,首先会对用户输入的关键词进行分词,再根据分词结果查询索引,命中目标后,根据索引获取最终的查询目标数据。

以上就是整个搜索的大致流程,下面我们来把他剖开来分析,看看每个过程如何实现。 

建立普通关键词索引

当用户提出一个问题,或者回答问题时,系统都会实时的建立索引(这里可以考虑使用异步建立索引,因为查询新内容不是实时的),索引的数据结构为Sorted Set,score值全部设为1,这样索引排序时就可以按照字母表顺序自然排序。key为分词后的值(使用的分词器是lucene中的IKAnalyzer),value保存的是对应搜索目标实体redis中存储的key值;
如果同种类型的多个关键词分词后有重复的分词值,就将实体key值存在同一个分词集合中,如,某2个问题进行分词后,都包含【争夺】这个分词值,那么这2个问题的实体key值都会作为index:question:[争夺]的value值。如下图所示:

general

建立逐字匹配索引

对于逐字匹配搜索的需求,我们的索引在建立时,也需要区别对待,当我们输入关键词时,并不希望输入完整的关键词后才能检索出相关内容,而是输入部分关键词时立刻出现相关结果,也即是瞬时响应效果。如下图所示:

prefix

那就要求我们在建立索引时,需要对每个分词后的值再按字或者字母建立索引值,这种索引我们称之为逐字匹配索引,或者前缀匹配索引,用Sorted Set来存储(key为index:prefix:key),其值为分词按字截取后的值,存储时其score值设为相同值1,那么所有的值会按照字母表的顺序进行排列,这样就使得逐字匹配索引中相近分词值会集中排列;当你搜索关键词时会搜出一定范围内(该范围的值会直接影响性能)的所有相似索引值。前缀匹配索引数据结构如下图所示:

prefix00

对于中文,前缀匹配索引数据结构如下图所示

prefixcn

建立中文拼音索引

对于中文用户,希望通过汉语拼音直接搜索,那就需要在对中文分词结果索引的同时,进行汉语拼音的转译,然后将转译后的汉语拼音作为key值,所有同音词的中文分词都作为value,存储在set中,这种方式可以确保检索出汉语拼音对应的所有中文分词。数据结构如下图所示:

pinyin

从以上我们可以看出,在建立索引数据时,我们对同一个分词进行了三种索引。

搜索过程

当用户在输入每个关键词的每个字时,首先对输入的关键词进行分词操作,然后会同时检索前缀和中文拼音索引,获取该关键词以及相关类似的关键词,然后除掉重复的关键词,最后根据搜索目标的类型,构建【普通关键词索引】的key值,求并集获取结果。

我们以一个例子来说明整个过程,比如我们输入的关键词是“南京”,经过检索前缀和中文拼音索引后,返回的关键词如下图所示:

result00

然后根据搜索目标类型,构建的【普通关键词索引】的key值如下图所示:

result01

这样,就可以根据question类型的索引key值找到对应的question实体的对应key,求并集,最终返回json数据给前端即可。整个流程就是这样。
最终结果如下图所示:

result

关于分页

对于已经排好序的结果集,使用Sorted Set的zrevrange命令即可按照scrore的值逆序排序。

关于性能

性能方面,普通关键词索引+前缀匹配索引+拼音索引的总和为60万+,而所有问题和回答有100万+,在我的mbp(8g,core i7)上面搜索体验还是很流畅的 。

关于优化

在前缀匹配时,是根据指定获取一定范围内的相似结果,这个范围值对性能影响很大 ;

是不是需要对关键词同时建立三种索引 ;

在搜索的准确性上,需要对分词器进行优化 ;

灵活设定结果集的排序字段 。

  • 实时搜索
    1 引用 • 1 回帖
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 248 回帖
  • 索引
    24 引用 • 28 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • relyn

    能否提供相关的代码~~~最近刚好要做这块

推荐标签 标签

  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 618 关注
  • Sublime

    Sublime Text 是一款可以用来写代码、写文章的文本编辑器。支持代码高亮、自动完成,还支持通过插件进行扩展。

    10 引用 • 5 回帖 • 1 关注
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    151 引用 • 257 回帖 • 1 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖 • 1 关注
  • webpack

    webpack 是一个用于前端开发的模块加载器和打包工具,它能把各种资源,例如 JS、CSS(less/sass)、图片等都作为模块来使用和处理。

    42 引用 • 130 回帖 • 253 关注
  • Follow
    4 引用 • 12 回帖 • 10 关注
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖 • 9 关注
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用 • 1 关注
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    32 引用 • 99 回帖
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 37 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖 • 1 关注
  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 565 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    173 引用 • 414 回帖 • 363 关注
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 656 关注
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    22 引用 • 148 回帖 • 10 关注
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    315 引用 • 547 回帖
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    8 引用 • 26 回帖 • 1 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 1 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • 七牛云

    七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化 PaaS 服务。围绕富媒体场景,七牛先后推出了对象存储,融合 CDN 加速,数据通用处理,内容反垃圾服务,以及直播云服务等。

    29 引用 • 230 回帖 • 124 关注
  • Access
    1 引用 • 3 回帖
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    56 引用 • 85 回帖
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    35 引用 • 468 回帖 • 762 关注
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 521 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖 • 3 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    108 引用 • 153 回帖
  • OpenResty

    OpenResty 是一个基于 NGINX 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

    17 引用 • 51 关注