基于 Redis 的实时搜索

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

一直想把前期做的一种完全基于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 引用 • 247 回帖 • 169 关注
  • 索引
    23 引用 • 28 回帖

相关帖子

欢迎来到这里!

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

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

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

推荐标签 标签

  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 617 关注
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    35 引用 • 200 回帖 • 28 关注
  • 禅道

    禅道是一款国产的开源项目管理软件,她的核心管理思想基于敏捷方法 scrum,内置了产品管理和项目管理,同时又根据国内研发现状补充了测试管理、计划管理、发布管理、文档管理、事务管理等功能,在一个软件中就可以将软件研发中的需求、任务、bug、用例、计划、发布等要素有序的跟踪管理起来,完整地覆盖了项目管理的核心流程。

    5 引用 • 15 回帖 • 215 关注
  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 21 关注
  • 创业

    你比 99% 的人都优秀么?

    82 引用 • 1398 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 92 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    76 引用 • 37 回帖 • 1 关注
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    116 引用 • 99 回帖 • 270 关注
  • MyBatis

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

    170 引用 • 414 回帖 • 423 关注
  • Gzip

    gzip (GNU zip)是 GNU 自由软件的文件压缩程序。我们在 Linux 中经常会用到后缀为 .gz 的文件,它们就是 Gzip 格式的。现今已经成为互联网上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

    9 引用 • 12 回帖 • 111 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    76 引用 • 421 回帖 • 1 关注
  • CodeMirror
    1 引用 • 2 回帖 • 121 关注
  • Oracle

    Oracle(甲骨文)公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩。1989 年正式进入中国市场。2013 年,甲骨文已超越 IBM,成为继 Microsoft 后全球第二大软件公司。

    103 引用 • 126 回帖 • 446 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    6618 引用 • 29680 回帖 • 251 关注
  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 689 关注
  • FlowUs

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

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

    1 引用 • 1 关注
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    40 引用 • 40 回帖
  • Redis

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

    284 引用 • 247 回帖 • 169 关注
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖 • 215 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 369 关注
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    16 引用 • 53 回帖 • 125 关注
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 509 关注
  • jsDelivr

    jsDelivr 是一个开源的 CDN 服务,可为 npm 包、GitHub 仓库提供免费、快速并且可靠的全球 CDN 加速服务。

    5 引用 • 31 回帖 • 48 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    492 引用 • 1383 回帖 • 366 关注
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖 • 10 关注