Redis简单案例(⼀)⽹站搜索的热搜词
对于⼀个⽹站来说,⽆论是商城⽹站还是门户⽹站,搜索框都是有⼀个⽐较重要的地位,它的存在可以说是
为了让⽤户更快、更⽅便的去到⾃⼰想要的东西。对于经常逛这个⽹站的⽤户,当然也会想知道在这⾥⽐较“⽕”
的东西是什么,这个时候我们搜索框上的热词就起作⽤了。其实我觉得这⼀块的完善会对这个⽹站带来许多益处。
可能现在⽐较普遍的做法是把这些相应的信息存到我们的关系型数据库中,如sql server 和 oracle。⽅便起见
的话,可能每搜索⼀次就往表⾥插⼀次数据,⽤的时候要先统计数据,统计完后再排序,最后才展⽰。这种情况下,
如果搜索量很⼤的话,表的膨胀速度就会⾮常快,如果sql没写好,查询的时候估计会。。相⽐Redis,同等条件下,Redis的速率肯定是会较优,毕竟是从内存中拿出来的。
下⾯我们就⽤.NET Core和StackExchange.Redis来做⼀下这个简单的案例。
案例⽤到的⼀些相关技术和说明:
技术说明
.NET Core⽹站嘛,你懂的。有事没事⽤Core写写Demo,免得跟不上发展的脚步。
Redis存储搜索词,⽤了主从的模式,主写从读
Jquery-ui主要是⽤了⾥⾯的autocomplete
开始正题之前,我们要确定⽤Redis中的那种数据结构,五种之中⽐较合适的应该是SortedSet,我们可以⽤成员来作为搜索词,成员分数来作为搜索词的搜索次数,这样就可以很⽅便的来操作相关的数据了。
下⾯开始正题:
我们在开始的时候需要初始化⼀下数据。这⾥就直接在第⼀次运⾏的时候初始化。⽤上流⽔线的技术,速度还是
很可观的。初始化了70个搜索关键词(NBA球星),然后⽤随机数作为关键字的下标,去随机给这个关键字加1分。这
个分数就是这个关键字被搜索的次数。下⾯来看看初始化的相关代码:
1public 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"lil
lard","mccollum","lin","jackson","nash","stoudemire","whiteside","dragic","Howard","batum"
13 };
14
15//init
16 Random random = new Random();
17var tran = _redis.GetTransaction();
18for (int i = 0; i < 1000000; i++)
19 {
20 tran.SortedSetIncrementAsync(_searchKey, keys[random.Next(0, 70)], 1);
21 }
22 tran.ExecuteAsync();
23
24return View();
25 }
这⾥是在加载这个页⾯的时候就把这些热搜词存进Redis中,这样我们才能有数据来演⽰啊。这⾥还⽤到了⼀个
⾮事务型的流⽔线。就是把要操作的指令存放到⼀个队列中,最后把这个队列扔到服务端去执⾏,这样就有效的减少
了不必要的⽹络传输,同时也提⾼了执⾏速度。
好了,初始数据有了,下⾯要做的就是⽤户在搜索的时候,根据⽤户的输⼊去匹配搜索次数多的关键字,展⽰最Hot的10个,当然这个展⽰的个数是随我们定的,最后可以考虑把这个放到我们的配置⽂件中去,甚⾄是放到数据库中,为的是灵活和⽅便维护。下⾯是我们在后台的处理逻辑:
1public IActionResult GetHotKey(string key="")
2 {
3if (string.IsNullOrEmpty(key))
4 {//default
5var res = _redis.ZRevRange(_searchKey, 0, 9);
6var list = (from i in res select i.ToString());
7return Json(list);
8 }
9else
10 {//by user input
11var res = _redis.ZRevRange(_searchKey, 0, -1);
12var list = (from i in res select i.ToString()).Where(x => x.Contains(key)).Take(10).ToList();
13return Json(list);
14 }
15 }
对于查询的处理是⾮常的简单的,⽤户不⼩⼼输⼊空格的时候就展⽰最热的10个关键词,如果⽤户有输⼊的话,就把
关键词中包含⽤户输⼊的展⽰出来。那么我们在页⾯上要做些什么呢?下⾯就是我们演⽰⽤的搜索框。
1<div class="row">
2<div class="col-md-6 col-md-offset-4" >
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的 ,如果有需要可
以去看⼀下。
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:
12 },
13 success: function (data) {
14 response(data);
15 }
16 });
17 },
18 });
19 </script>
20 }
到这⾥,⽤户搜索前的操作,我们是做好了,下⾯先来看⼀下效果。
那么⽤户点击了搜索之后我们要做些什么处理呢?⽆论是新的关键字还是已有的关键字,我们都是要做处理的,当然redis
中zincrby命令来处理这个是⼗分合适的,存在的就把分数加1,不存在就创建⼀个分数为1的成员。下⾯是搜索时的后台逻辑处理:
1 [HttpPost]
2public IActionResult SetHotKey(string key)
3 {
4if (!string.IsNullOrWhiteSpace(key))
5 {
6 _redis.ZIncrby(_searchKey,key);
7//other
8//...
9return Json(new { code = "000", msg = "OK" });
10 }
11else
12 {
13return Json(new { code = "999", msg = "keyword can not be empty!" });
14 }
15 }
限制了⽤户不能搜索空关键字,在把这个关键字存储或者分数加⼀之后,就是展⽰我们的搜索的结果。这个搜索的结果⼀般是从solr等全⽂检索的地⽅查出来的,不是我们讲的重点,所以就忽略了。然后我们还要加⼀段js去处理我们搜索的时候应该做的操作。当然,都是些⽐较简单的操作。
redis五种数据结构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) {
9if (de == "000") {
10 $("<p>search successful!</p>").appendTo("#result");
11 } else {
12 $("<p>"+data.msg+"</p>").appendTo("#result");
13 }
14 }
15 });
16 });
下⾯是效果图:
在演⽰的时候,我们搜索了“我爱你”和“我不信”,在Redis的客户端我们出搜索次数最少的6个,然后就可以看到我们那两个关键字最的分数都是1。确定是刚插⼊的数据。
到这⾥,我们做的这个热搜词可以说是⼤功告成了。当然这可以说是最最最简单的⼀个雏形。我们还可以适当的添加⼀些东西让这个功能变得更加完善。⽐如我可以在搜索展⽰的时候显⽰⼀下搜索的次数等。
最后是完整的控制器和页⾯代码:
1using AutoCompleteDemo.Common;
2using Microsoft.AspNetCore.Mvc;
3using System;
4using System.Collections.Generic;
5using System.Linq;
6
7namespace AutoCompleteDemo.Controllers
8 {
9public class AutoController : Controller
10 {
11private readonly IRedis _redis;
12private readonly string _searchKey = "search";
13public AutoController(IRedis redis)
14 {
15 _redis = redis;
16 }
17
18public 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();
34var tran = _redis.GetTransaction();
35for (int i = 0; i < 2000000; i++)
36 {
37 tran.SortedSetIncrementAsync(_searchKey, keys[random.Next(0, 70)], 1);
38 }
39 tran.ExecuteAsync();
40
41return View();
42 }
43
44public IActionResult GetHotKey(string key="")
45 {
46if (string.IsNullOrEmpty(key))
47 {//default
48var res = _redis.ZRevRange(_searchKey, 0, 9);
49var list = (from i in res select i.ToString());
50return Json(list);
51 }
52else
53 {//by user input
54var res = _redis.ZRevRange(_searchKey, 0, -1);
55var list = (from i in res select i.ToString()).Where(x => x.Contains(key)).Take(10).ToList();
56return Json(list);
57 }
58 }
59
60 [HttpPost]
61public IActionResult SetHotKey(string key)
62 {
63if (!string.IsNullOrWhiteSpace(key))
64 {
65 _redis.ZIncrby(_searchKey,key);
66//other
67//...
68return Json(new { code = "000", msg = "OK" });
69 }
70else
71 {
72return 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" >
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:
22 },
23 success: function (data) {
24 response(data);
25 }
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论