Redis簡單案例(一) 網站搜索的熱搜詞

  對於一個網站來講,不管是商城網站仍是門戶網站,搜索框都是有一個比較重要的地位,它的存在能夠說是javascript

爲了讓用戶更快、更方便的去找到本身想要的東西。對於常常逛這個網站的用戶,固然也會想知道在這裏比較「火」html

的東西是什麼,這個時候咱們搜索框上的熱詞就起做用了。其實我以爲這一塊的完善會對這個網站帶來許多益處。java

  可能如今比較廣泛的作法是把這些相應的信息存到咱們的關係型數據庫中,如sql server 和 oracle。方便起見jquery

的話,可能每搜索一次就往表裏插一次數據,用的時候要先統計數據,統計完後再排序,最後才展現。這種狀況下,ajax

若是搜索量很大的話,表的膨脹速度就會很是快,若是sql沒寫好,查詢的時候估計會。。相比Redis,同等條件下,redis

Redis的速率確定是會較優,畢竟是從內存中拿出來的。sql

 

  下面咱們就用.NET Core和StackExchange.Redis來作一下這個簡單的案例。

  案例用到的一些相關技術和說明:數據庫

技術 說明 
.NET Core 網站嘛,你懂的。有事沒事用Core寫寫Demo,省得跟不上發展的腳步。
Redis 存儲搜索詞,用了主從的模式,主寫從讀
Jquery-ui 主要是用了裏面的autocomplete

  開始正題以前,咱們要肯定用Redis中的那種數據結構,五種之中比較合適的應該是SortedSet,咱們能夠用成員來json

做爲搜索詞,成員分數來做爲搜索詞的搜索次數,這樣就能夠很方便的來操做相關的數據了。api

  下面開始正題:

  咱們在開始的時候須要初始化一下數據。這裏就直接在第一次運行的時候初始化。用上流水線的技術,速度仍是

很可觀的。初始化了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 = 0; i < 1000000; i++)
19             {
20                 tran.SortedSetIncrementAsync(_searchKey, keys[random.Next(0, 70)], 1);
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, 0, 9);
 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, 0, -1);
12                 var list = (from i in res select i.ToString()).Where(x => x.Contains(key)).Take(10).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 = "000", msg = "OK" });
10             }
11             else
12             {
13                 return Json(new { code = "999", 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 = 0; i < 2000000; i++)
36             {
37                 tran.SortedSetIncrementAsync(_searchKey, keys[random.Next(0, 70)], 1);
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, 0, 9);
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, 0, -1);
55                 var list = (from i in res select i.ToString()).Where(x => x.Contains(key)).Take(10).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 = "000", msg = "OK" });
69             }
70             else
71             {
72                 return Json(new { code = "999", 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
相關文章
相關標籤/搜索