对于一个网站来说,无论是商城网站还是门户网站,搜索框都是有一个比较重要的地位,它的存在可以说是

为了让用户更快、更方便的去找到自己想要的东西。对于经常逛这个网站的用户,当然也会想知道在这里比较“火”

的东西是什么,这个时候我们搜索框上的热词就起作用了。其实我觉得这一块的完善会对这个网站带来许多益处。

  可能现在比较普遍的做法是把这些相应的信息存到我们的关系型数据库中,如sql server 和 oracle。方便起见

的话,可能每搜索一次就往表里插一次数据,用的时候要先统计数据,统计完后再排序,最后才展示。这种情况下,

如果搜索量很大的话,表的膨胀速度就会非常快,如果sql没写好,查询的时候估计会。。相比Redis,同等条件下,

Redis的速率肯定是会较优,毕竟是从内存中拿出来的。

  下面我们就用.NET Core和StackExchange.Redis来做一下这个简单的案例。

  案例用到的一些相关技术和说明:

技术 说明 
.NET Core 网站嘛,你懂的。有事没事用Core写写Demo,免得跟不上发展的脚步。
Redis 存储搜索词,用了主从的模式,主写从读
Jquery-ui 主要是用了里面的autocomplete

  开始正题之前,我们要确定用Redis中的那种数据结构,五种之中比较合适的应该是SortedSet,我们可以用成员来

作为搜索词,成员分数来作为搜索词的搜索次数,这样就可以很方便的来操作相关的数据了。

  下面开始正题:

  我们在开始的时候需要初始化一下数据。这里就直接在第一次运行的时候初始化。用上流水线的技术,速度还是

很可观的。初始化了70个搜索关键词(NBA球星),然后用随机数作为关键字的下标,去随机给这个关键字加1分。这

个分数就是这个关键字被搜索的次数。下面来看看初始化的相关代码:

  1. public IActionResult Index()
  2. {
  3. //keys
  4. IList<string> keys = new List<string>()
  5. {
  6. "kobe","johnson","jabbar","west","o'neal","baylor","mccann","worthy","gasol","chamberlain",
  7. "fisher","odom","bynum","horry","rambis","riley","clarkson","Williams","young","Russell",
  8. "ingram","randle","nance","brown","deng","yi","ariza","artest","walton","vujacic",
  9. "james","paul","curry","park","yao","kevin","wade","rose","popovich","leonard",
  10. "aldridge","ginobili","duncan","lavine","rubio","garnett","wiggins","westbrook","durant","ibaka",
  11. "nowitzki","pierce","crawford","love","smith","iguodala","barnes","green","thompson","harden",
  12. "lillard","mccollum","lin","jackson","nash","stoudemire","whiteside","dragic","Howard","batum"
  13. };
  14.  
  15. //init
  16. Random random = new Random();
  17. var tran = _redis.GetTransaction();
  18. for (int i = ; i < 1; i++)
  19. {
  20. tran.SortedSetIncrementAsync(_searchKey, keys[random.Next(, )], );
  21. }
  22. tran.ExecuteAsync();
  23.  
  24. return View();
  25. }

  这里是在加载这个页面的时候就把这些热搜词存进Redis中,这样我们才能有数据来演示啊。这里还用到了一个

非事务型的流水线。就是把要操作的指令存放到一个队列中,最后把这个队列扔到服务端去执行,这样就有效的减少

了不必要的网络传输,同时也提高了执行速度。

  好了,初始数据有了,下面要做的就是用户在搜索的时候,根据用户的输入去匹配搜索次数多的关键字,展示最

Hot的10个,当然这个展示的个数是随我们定的,最后可以考虑把这个放到我们的配置文件中去,甚至是放到数据库中,

为的是灵活和方便维护。下面是我们在后台的处理逻辑:

  1. public IActionResult GetHotKey(string key="")
  2. {
  3. if (string.IsNullOrEmpty(key))
  4. {//default
  5. var res = _redis.ZRevRange(_searchKey, , );
  6. var list = (from i in res select i.ToString());
  7. return Json(list);
  8. }
  9. else
  10. {//by user input
  11. var res = _redis.ZRevRange(_searchKey, , -);
  12. var list = (from i in res select i.ToString()).Where(x => x.Contains(key)).Take().ToList();
  13. return Json(list);
  14. }
  15. }

  对于查询的处理是非常的简单的,用户不小心输入空格的时候就展示最热的10个关键词,如果用户有输入的话,就把

关键词中包含用户输入的展示出来。那么我们在页面上要做些什么呢?下面就是我们演示用的搜索框。

  1. <div class="row">
  2. <div class="col-md-6 col-md-offset-4" style="padding-top:50px;">
  3. <input id="key" name="key" placeholder="search" class="form-control col-md-4">
  4. <button class="btn btn-primary" type="button" id="searchSubmit">Search</button>
  5. <div id="result"></div>
  6. </div>
  7. </div>

  相应的js是写到 scripts 这个section中的,js的话是比较简单的就是用ajax去请求我们要展示的数据。更多的应该是

jquery-ui的api问题,大家也可以换用自己比较熟悉的组件,举一反三即可。下面是autocomplete的api  ,如果有需要可

以去看一下。

  1. @section scripts{
  2. <script type="text/javascript">
  3. $(function () {
  4. //show hot keyword
  5. $("#key").autocomplete({
  6. source: function (request, response) {
  7. $.ajax({
  8. url: "@Url.Action("GetHotKey", "Auto")",
  9. dataType: "json",
  10. data: {
  11. key: request.term
  12. },
  13. success: function (data) {
  14. response(data);
  15. }
  16. });
  17. },
  18. });
  19. </script>
  20. }
  到这里,用户搜索前的操作,我们是做好了,下面先来看一下效果。

  那么用户点击了搜索之后我们要做些什么处理呢?无论是新的关键字还是已有的关键字,我们都是要做处理的,当然redis

中zincrby命令来处理这个是十分合适的,存在的就把分数加1,不存在就创建一个分数为1的成员。下面是搜索时的后台逻辑处理:

  1. [HttpPost]
  2. public IActionResult SetHotKey(string key)
  3. {
  4. if (!string.IsNullOrWhiteSpace(key))
  5. {
  6. _redis.ZIncrby(_searchKey,key);
  7. //other
  8. //...
  9. return Json(new { code = "", msg = "OK" });
  10. }
  11. else
  12. {
  13. return Json(new { code = "", msg = "keyword can not be empty!" });
  14. }
  15. }

  限制了用户不能搜索空关键字,在把这个关键字存储或者分数加一之后,就是展示我们的搜索的结果。这个搜索的结果一般

是从solr等全文检索的地方查出来的,不是我们讲的重点,所以就忽略了。然后我们还要加一段js去处理我们搜索的时候应该做的

操作。当然,都是些比较简单的操作。

  1. //search
  2. $("#searchSubmit").click(function () {
  3. $.ajax({
  4. url: "@Url.Action("SetHotKey", "Auto")",
  5. dataType: "json",
  6. type: "POST",
  7. data: { key: $("#key").val() },
  8. success: function (data) {
  9. if (data.code == "000") {
  10. $("<p>search successful!</p>").appendTo("#result");
  11. } else {
  12. $("<p>"+data.msg+"</p>").appendTo("#result");
  13. }
  14. }
  15. });
  16. });
下面是效果图: 

  在演示的时候,我们搜索了“我爱你”和“我不信”,在Redis的客户端我们找出搜索次数最少的6个,然后就可以看到我们那两

个关键字最的分数都是1。确定是刚插入的数据。

  到这里,我们做的这个热搜词可以说是大功告成了。当然这可以说是最最最简单的一个雏形。我们还可以适当的添加一些

东西让这个功能变得更加完善。比如我可以在搜索展示的时候显示一下搜索的次数等。

最后是完整的控制器和页面代码:

  1. using AutoCompleteDemo.Common;
  2. using Microsoft.AspNetCore.Mvc;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6.  
  7. namespace AutoCompleteDemo.Controllers
  8. {
  9. public class AutoController : Controller
  10. {
  11. private readonly IRedis _redis;
  12. private readonly string _searchKey = "search";
  13. public AutoController(IRedis redis)
  14. {
  15. _redis = redis;
  16. }
  17.  
  18. public IActionResult Index()
  19. {
  20. //keys
  21. IList<string> keys = new List<string>()
  22. {
  23. "kobe","johnson","jabbar","west","o'neal","baylor","mccann","worthy","gasol","chamberlain",
  24. "fisher","odom","bynum","horry","rambis","riley","clarkson","Williams","young","Russell",
  25. "ingram","randle","nance","brown","deng","yi","ariza","artest","walton","vujacic",
  26. "james","paul","curry","park","yao","kevin","wade","rose","popovich","leonard",
  27. "aldridge","ginobili","duncan","lavine","rubio","garnett","wiggins","westbrook","durant","ibaka",
  28. "nowitzki","pierce","crawford","love","smith","iguodala","barnes","green","thompson","harden",
  29. "lillard","mccollum","lin","jackson","nash","stoudemire","whiteside","dragic","Howard","batum"
  30. };
  31.  
  32. //init
  33. Random random = new Random();
  34. var tran = _redis.GetTransaction();
  35. for (int i = ; i < ; i++)
  36. {
  37. tran.SortedSetIncrementAsync(_searchKey, keys[random.Next(, )], );
  38. }
  39. tran.ExecuteAsync();
  40.  
  41. return View();
  42. }
  43.  
  44. public IActionResult GetHotKey(string key="")
  45. {
  46. if (string.IsNullOrEmpty(key))
  47. {//default
  48. var res = _redis.ZRevRange(_searchKey, , );
  49. var list = (from i in res select i.ToString());
  50. return Json(list);
  51. }
  52. else
  53. {//by user input
  54. var res = _redis.ZRevRange(_searchKey, , -);
  55. var list = (from i in res select i.ToString()).Where(x => x.Contains(key)).Take().ToList();
  56. return Json(list);
  57. }
  58. }
  59.  
  60. [HttpPost]
  61. public IActionResult SetHotKey(string key)
  62. {
  63. if (!string.IsNullOrWhiteSpace(key))
  64. {
  65. _redis.ZIncrby(_searchKey,key);
  66. //other
  67. //...
  68. return Json(new { code = "", msg = "OK" });
  69. }
  70. else
  71. {
  72. return Json(new { code = "", msg = "keyword can not be empty!" });
  73. }
  74. }
  75. }
  76. }

AutoController

  1. @{
  2. ViewData["Title"] = "Auto Complete";
  3. }
  4. <div class="row">
  5. <div class="col-md-6 col-md-offset-4" style="padding-top:50px;">
  6. <input id="key" name="key" placeholder="search" class="form-control col-md-4">
  7. <button class="btn btn-primary" type="button" id="searchSubmit">Search</button>
  8. <div id="result"></div>
  9. </div>
  10. </div>
  11. @section scripts{
  12. <script type="text/javascript">
  13. $(function () {
  14. //show hot keyword
  15. $("#key").autocomplete({
  16. source: function (request, response) {
  17. $.ajax({
  18. url: "@Url.Action("GetHotKey", "Auto")",
  19. dataType: "json",
  20. data: {
  21. key: request.term
  22. },
  23. success: function (data) {
  24. response(data);
  25. }
  26. });
  27. },
  28. });
  29.  
  30. //search
  31. $("#searchSubmit").click(function () {
  32. $.ajax({
  33. url: "@Url.Action("SetHotKey", "Auto")",
  34. dataType: "json",
  35. type: "POST",
  36. data: { key: $("#key").val() },
  37. success: function (data) {
  38. if (data.code == "000") {
  39. $("<p>search successful!</p>").appendTo("#result");
  40. } else {
  41. $("<p>"+data.msg+"</p>").appendTo("#result");
  42. }
  43. }
  44. });
  45. });
  46. });
  47. </script>
  48. }

Index.cshtml

Redis简单案例(一) 网站搜索的热搜词的更多相关文章

  1. Redis简单案例(二) 网站最近的访问用户

    我们有时会在网站中看到最后的访问用户.最近的活跃用户等等诸如此类的一些信息.本文就以最后的访问用户为例, 用Redis来实现这个小功能.在这之前,我们可以先简单了解一下在oracle.sqlserve ...

  2. SpringDataRedis操作Redis简单案例

    Jedis Jedis是Redis官方推出的一款面向Java的客户端,提供了很多接口供Java语言调用.可以在Redis官网下载,当然还有一些开源爱好者提供的客户端,如Jredis.SRP等等,推荐使 ...

  3. SpringBoot基础学习(一) SpringBoot概念、简单案例实现、单元测试及热部署讲解

    SpringBoot概念 Spring优缺点分析 Spring优点 Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE)的轻量级代替品,无需开发重量级的 ...

  4. SparkStreaming实时日志分析--实时热搜词

    Overview 整个项目的整体架构如下: 关于SparkStreaming的部分: Flume传数据到SparkStreaming:为了简单使用的是push-based的方式.这种方式可能会丢失数据 ...

  5. 纯前端实现词云展示+附微博热搜词云Demo代码

    前言 最近工作中做了几个数据可视化大屏项目,其中也有用到了词云展示,以前做词云都是用python库来生成图片显示的,这次用了纯前端的实现(Ctrl+V真好用),同时顺手做个微博热搜的词云然后记录一下~ ...

  6. Redis简单案例(四) Session的管理

    负载均衡,这应该是一个永恒的话题,也是一个十分重要的话题.毕竟当网站成长到一定程度,访问量自然也是会跟着增长,这个时候, 一般都会对其进行负载均衡等相应的调整.现如今最常见的应该就是使用Nginx来进 ...

  7. Redis简单案例(三) 连续登陆活动的简单实现

    连续登陆活动,或许大家都不会陌生,简单理解就是用户连续登陆了多少天之后,系统就会送一些礼品给相应的用户.最常见的 莫过于游戏和商城这些.游戏就送游戏币之类的东西,商城就送一些礼券.正值国庆,应该也有不 ...

  8. Redis 实战 —— 11. 实现简单的社交网站

    简介 前面介绍了广告定向的实现,它是一个查询密集型 (query-intensive) 程序,所以每个发给它的请求都会引起大量计算.本文将实现一个简单的社交网站,则会尽可能地减少用户在查看页面时系统所 ...

  9. Spring Data Solr操作solr的简单案例

    Spring Data Solr简介 虽然支持任何编程语言的能力具有很大的市场价值,你可能感兴趣的问题是:我如何将Solr的应用集成到Spring中?可以,Spring Data Solr就是为了方便 ...

随机推荐

  1. 【SSM框架】Spring + Springmvc + Mybatis 基本框架搭建集成教程

    本文将讲解SSM框架的基本搭建集成,并有一个简单demo案例 说明:1.本文暂未使用maven集成,jar包需要手动导入. 2.本文为基础教程,大神切勿见笑. 3.如果对您学习有帮助,欢迎各种转载,注 ...

  2. 利用Oracle RUEI+EM12c进行应用的“端到端”性能诊断

    概述 我们知道,影响一个B/S应用性能的因素,粗略地说,有以下几个大的环节: 1. 客户端环节 2. 网络环节(可能包括WAN和LAN) 3. 应用及中间层环节 4. 数据库层环节 能够对各个环节的问 ...

  3. Android探索之AIDL实现进程间通信

    前言: 前面总结了程序间共享数据,可以使用ContentProvider也可以使用SharedPreference,那么进程间怎么共享内存呢?Android系统中的进程之间不能共享内存,因此,需要提供 ...

  4. 从netty-example分析Netty组件

    分析netty从源码开始 准备工作: 1.下载源代码:https://github.com/netty/netty.git 我下载的版本为4.1 2. eclipse导入maven工程. netty提 ...

  5. Win10 UWP开发系列——开源控件库:UWPCommunityToolkit

    在开发应用的过程中,不可避免的会使用第三方类库.之前用过一个WinRTXamlToolkit.UWP,现在微软官方发布了一个新的开源控件库—— UWPCommunityToolkit 项目代码托管在G ...

  6. 值得注意的ibatis动态sql语法格式

    一.Ibatis常用动态sql语法,简单粗暴用一例子 <select id="iBatisSelectList" parameterClass="java.util ...

  7. 说说BPM数据表和日志表中几个状态字段的详细解释

    有个客户说需要根据这些字段的值作为判断条件做一些定制化需求,所以需要知道这些字段的名词解释,以及里面存储的值具体代表什么意思 我只好为你们整理奉上这些了! Open Work Sheet  0 Sav ...

  8. Kafka:主要参数详解(转)

    原文地址:http://kafka.apache.org/documentation.html ############################# System ############### ...

  9. Object是什么

    Object是什么 .Net程序员们每天都在和Object在打交道如果你问一个.Net程序员什么是Object,他可能会信誓旦旦的告诉你"Object还不简单吗,就是所有类型的基类" ...

  10. Visual Studio Code v0.9.1 发布

    微软的跨平台编辑器 Visual Studio Code v0.9.1 已经发布,官方博客上发布文章Visual Studio Code – October Update (0.9.1):http:/ ...