Redis网站热搜关键词加载实践,建议收藏
俠夢(mèng)的開(kāi)發(fā)筆記回復(fù)【面試題】獲取2021年最新java面試題合集~
來(lái)源:Catcher8
www.cnblogs.com/catcher1994/p/5877262.html
對(duì)于一個(gè)網(wǎng)站來(lái)說(shuō),無(wú)論是商城網(wǎng)站還是門戶網(wǎng)站,搜索框都是有一個(gè)比較重要的地位,它的存在可以說(shuō)是為了讓用戶更快、更方便的去找到自己想要的東西。對(duì)于經(jīng)常逛這個(gè)網(wǎng)站的用戶,當(dāng)然也會(huì)想知道在這里比較“火”的東西是什么,這個(gè)時(shí)候我們搜索框上的熱詞就起作用了。其實(shí)我覺(jué)得這一塊的完善會(huì)對(duì)這個(gè)網(wǎng)站帶來(lái)許多益處。
可能現(xiàn)在比較普遍的做法是把這些相應(yīng)的信息存到我們的關(guān)系型數(shù)據(jù)庫(kù)中,如sql server 和 oracle。方便起見(jiàn)的話,可能每搜索一次就往表里插一次數(shù)據(jù),用的時(shí)候要先統(tǒng)計(jì)數(shù)據(jù),統(tǒng)計(jì)完后再排序,最后才展示。這種情況下,如果搜索量很大的話,表的膨脹速度就會(huì)非常快,如果sql沒(méi)寫(xiě)好,查詢的時(shí)候估計(jì)會(huì)。。相比Redis,同等條件下,Redis的速率肯定是會(huì)較優(yōu),畢竟是從內(nèi)存中拿出來(lái)的。
?
下面我們就用.NET Core和StackExchange.Redis來(lái)做一下這個(gè)簡(jiǎn)單的案例。
案例用到的一些相關(guān)技術(shù)和說(shuō)明:
| 技術(shù) | 說(shuō)明? |
| .NET Core | 網(wǎng)站嘛,你懂的。有事沒(méi)事用Core寫(xiě)寫(xiě)Demo,免得跟不上發(fā)展的腳步。 |
| Redis | 存儲(chǔ)搜索詞,用了主從的模式,主寫(xiě)從讀 |
| Jquery-ui | 主要是用了里面的autocomplete |
開(kāi)始正題之前,我們要確定用Redis中的那種數(shù)據(jù)結(jié)構(gòu),五種之中比較合適的應(yīng)該是SortedSet,我們可以用成員來(lái)作為搜索詞,成員分?jǐn)?shù)來(lái)作為搜索詞的搜索次數(shù),這樣就可以很方便的來(lái)操作相關(guān)的數(shù)據(jù)了。
下面開(kāi)始正題:
我們?cè)陂_(kāi)始的時(shí)候需要初始化一下數(shù)據(jù)。這里就直接在第一次運(yùn)行的時(shí)候初始化。用上流水線的技術(shù),速度還是很可觀的。初始化了70個(gè)搜索關(guān)鍵詞(NBA球星),然后用隨機(jī)數(shù)作為關(guān)鍵字的下標(biāo),去隨機(jī)給這個(gè)關(guān)鍵字加1分。這個(gè)分?jǐn)?shù)就是這個(gè)關(guān)鍵字被搜索的次數(shù)。下面來(lái)看看初始化的相關(guān)代碼:
public?IActionResult?Index(){//keysIList<string>?keys?=?new?List<string>(){"kobe","johnson","jabbar","west","o'neal","baylor","mccann","worthy","gasol","chamberlain","fisher","odom","bynum","horry","rambis","riley","clarkson","Williams","young","Russell","ingram","randle","nance","brown","deng","yi","ariza","artest","walton","vujacic","james","paul","curry","park","yao","kevin","wade","rose","popovich","leonard","aldridge","ginobili","duncan","lavine","rubio","garnett","wiggins","westbrook","durant","ibaka","nowitzki","pierce","crawford","love","smith","iguodala","barnes","green","thompson","harden","lillard","mccollum","lin","jackson","nash","stoudemire","whiteside","dragic","Howard","batum"};//initRandom?random?=?new?Random();var?tran?=?_redis.GetTransaction();for?(int?i?=?0;?i?<?1000000;?i++){tran.SortedSetIncrementAsync(_searchKey,?keys[random.Next(0,?70)],?1);}tran.ExecuteAsync();return?View();}這里是在加載這個(gè)頁(yè)面的時(shí)候就把這些熱搜詞存進(jìn)Redis中,這樣我們才能有數(shù)據(jù)來(lái)演示啊。這里還用到了一個(gè)非事務(wù)型的流水線。就是把要操作的指令存放到一個(gè)隊(duì)列中,最后把這個(gè)隊(duì)列扔到服務(wù)端去執(zhí)行,這樣就有效的減少了不必要的網(wǎng)絡(luò)傳輸,同時(shí)也提高了執(zhí)行速度。
好了,初始數(shù)據(jù)有了,下面要做的就是用戶在搜索的時(shí)候,根據(jù)用戶的輸入去匹配搜索次數(shù)多的關(guān)鍵字,展示最Hot的10個(gè),當(dāng)然這個(gè)展示的個(gè)數(shù)是隨我們定的,最后可以考慮把這個(gè)放到我們的配置文件中去,甚至是放到數(shù)據(jù)庫(kù)中,
為的是靈活和方便維護(hù)。下面是我們?cè)诤笈_(tái)的處理邏輯:
public?IActionResult?GetHotKey(string?key=""){if?(string.IsNullOrEmpty(key)){//defaultvar?res?=?_redis.ZRevRange(_searchKey,?0,?9);var?list?=?(from?i?in?res?select?i.ToString());return?Json(list);}else{//by?user?inputvar?res?=?_redis.ZRevRange(_searchKey,?0,?-1);var?list?=?(from?i?in?res?select?i.ToString()).Where(x?=>?x.Contains(key)).Take(10).ToList();return?Json(list);}}對(duì)于查詢的處理是非常的簡(jiǎn)單的,用戶不小心輸入空格的時(shí)候就展示最熱的10個(gè)關(guān)鍵詞,如果用戶有輸入的話,就把關(guān)鍵詞中包含用戶輸入的展示出來(lái)。那么我們?cè)陧?yè)面上要做些什么呢?下面就是我們演示用的搜索框。
<div?class="row"><div?class="col-md-6?col-md-offset-4"?style="padding-top:50px;"><input?id="key"?name="key"?placeholder="search"?class="form-control?col-md-4"><button?class="btn?btn-primary"?type="button"?id="searchSubmit">Search</button><div?id="result"></div></div> </div>相應(yīng)的js是寫(xiě)到 scripts 這個(gè)p中的,js的話是比較簡(jiǎn)單的就是用ajax去請(qǐng)求我們要展示的數(shù)據(jù)。更多的應(yīng)該是jquery-ui的api問(wèn)題,大家也可以換用自己比較熟悉的組件,舉一反三即可。下面是autocomplete的api??,如果有需要可以去看一下。
@p?scripts{<script?type="text/javascript">$(function?()?{//show?hot?keyword$("#key").autocomplete({????????????????source:?function?(request,?response)?{$.ajax({url:?"@Url.Action("GetHotKey",?"Auto")",dataType:?"json",data:?{key:?request.term},success:?function?(data)?{response(data);}});},});????????????</script> }到這里,用戶搜索前的操作,我們是做好了,下面先來(lái)看一下效果。
那么用戶點(diǎn)擊了搜索之后我們要做些什么處理呢?無(wú)論是新的關(guān)鍵字還是已有的關(guān)鍵字,我們都是要做處理的,當(dāng)然redis中zincrby命令來(lái)處理這個(gè)是十分合適的,存在的就把分?jǐn)?shù)加1,不存在就創(chuàng)建一個(gè)分?jǐn)?shù)為1的成員。下面是搜索時(shí)的后臺(tái)邏輯處理:
[HttpPost]public?IActionResult?SetHotKey(string?key){if?(!string.IsNullOrWhiteSpace(key)){_redis.ZIncrby(_searchKey,key);//other?//...return?Json(new?{?code?=?"000",?msg?=?"OK"?});}else{return?Json(new?{?code?=?"999",?msg?=?"keyword?can?not?be?empty!"?});}}限制了用戶不能搜索空關(guān)鍵字,在把這個(gè)關(guān)鍵字存儲(chǔ)或者分?jǐn)?shù)加一之后,就是展示我們的搜索的結(jié)果。這個(gè)搜索的結(jié)果一般是從solr等全文檢索的地方查出來(lái)的,不是我們講的重點(diǎn),所以就忽略了。然后我們還要加一段js去處理我們搜索的時(shí)候應(yīng)該做的操作。當(dāng)然,都是些比較簡(jiǎn)單的操作。
//search$("#searchSubmit").click(function?()?{$.ajax({url:?"@Url.Action("SetHotKey",?"Auto")",dataType:?"json",type:?"POST",data:?{?key:?$("#key").val()?},success:?function?(data)?{if?(data.code?==?"000")?{$("<p>search?successful!</p>").appendTo("#result");}?else?{$("<p>"+data.msg+"</p>").appendTo("#result");}}});});下面是效果圖:
在演示的時(shí)候,我們搜索了“我愛(ài)你”和“我不信”,在Redis的客戶端我們找出搜索次數(shù)最少的6個(gè),然后就可以看到我們那兩個(gè)關(guān)鍵字最的分?jǐn)?shù)都是1。確定是剛插入的數(shù)據(jù)。
到這里,我們做的這個(gè)熱搜詞可以說(shuō)是大功告成了。當(dāng)然這可以說(shuō)是最最最簡(jiǎn)單的一個(gè)雛形。我們還可以適當(dāng)?shù)奶砑右恍〇|西讓這個(gè)功能變得更加完善。比如我可以在搜索展示的時(shí)候顯示一下搜索的次數(shù)等。
最后是完整的控制器和頁(yè)面代碼:
using?AutoCompleteDemo.Common; using?Microsoft.AspNetCore.Mvc; using?System; using?System.Collections.Generic; using?System.Linq;namespace?AutoCompleteDemo.Controllers {public?class?AutoController?:?Controller{private?readonly?IRedis?_redis;private?readonly?string?_searchKey?=?"search";????????public?AutoController(IRedis?redis){_redis?=?redis;}public?IActionResult?Index(){//keysIList<string>?keys?=?new?List<string>(){"kobe","johnson","jabbar","west","o'neal","baylor","mccann","worthy","gasol","chamberlain","fisher","odom","bynum","horry","rambis","riley","clarkson","Williams","young","Russell","ingram","randle","nance","brown","deng","yi","ariza","artest","walton","vujacic","james","paul","curry","park","yao","kevin","wade","rose","popovich","leonard","aldridge","ginobili","duncan","lavine","rubio","garnett","wiggins","westbrook","durant","ibaka","nowitzki","pierce","crawford","love","smith","iguodala","barnes","green","thompson","harden","lillard","mccollum","lin","jackson","nash","stoudemire","whiteside","dragic","Howard","batum"};//initRandom?random?=?new?Random();var?tran?=?_redis.GetTransaction();for?(int?i?=?0;?i?<?2000000;?i++){tran.SortedSetIncrementAsync(_searchKey,?keys[random.Next(0,?70)],?1);}tran.ExecuteAsync();return?View();}public?IActionResult?GetHotKey(string?key=""){if?(string.IsNullOrEmpty(key)){//defaultvar?res?=?_redis.ZRevRange(_searchKey,?0,?9);var?list?=?(from?i?in?res?select?i.ToString());return?Json(list);}else{//by?user?inputvar?res?=?_redis.ZRevRange(_searchKey,?0,?-1);var?list?=?(from?i?in?res?select?i.ToString()).Where(x?=>?x.Contains(key)).Take(10).ToList();return?Json(list);}}[HttpPost]public?IActionResult?SetHotKey(string?key){if?(!string.IsNullOrWhiteSpace(key)){_redis.ZIncrby(_searchKey,key);//other?//...return?Json(new?{?code?=?"000",?msg?=?"OK"?});}else{return?Json(new?{?code?=?"999",?msg?=?"keyword?can?not?be?empty!"?});}}} }AutoController @{ViewData["Title"]?=?"Auto?Complete"; } <div?class="row"><div?class="col-md-6?col-md-offset-4"?style="padding-top:50px;"><input?id="key"?name="key"?placeholder="search"?class="form-control?col-md-4"><button?class="btn?btn-primary"?type="button"?id="searchSubmit">Search</button><div?id="result"></div></div> </div> @p?scripts{<script?type="text/javascript">$(function?()?{//show?hot?keyword$("#key").autocomplete({????????????????source:?function?(request,?response)?{????????????????????$.ajax({url:?"@Url.Action("GetHotKey",?"Auto")",dataType:?"json",data:?{key:?request.term},success:?function?(data)?{response(data);}});},});//search$("#searchSubmit").click(function?()?{$.ajax({url:?"@Url.Action("SetHotKey",?"Auto")",dataType:?"json",type:?"POST",data:?{?key:?$("#key").val()?},success:?function?(data)?{if?(data.code?==?"000")?{$("<p>search?successful!</p>").appendTo("#result");}?else?{$("<p>"+data.msg+"</p>").appendTo("#result");}}});});});</script> }Index.cshtml--完--
回復(fù)【干貨】獲取精選干貨視頻教程
回復(fù)【加群】加入疑難問(wèn)題攻堅(jiān)交流群
回復(fù)【mat】獲取內(nèi)存溢出問(wèn)題分析詳細(xì)文檔教程
回復(fù)【賺錢】獲取用java寫(xiě)一個(gè)能賺錢的微信機(jī)器人
回復(fù)【副業(yè)】獲取程序員副業(yè)攻略一份
戳這兒
總結(jié)
以上是生活随笔為你收集整理的Redis网站热搜关键词加载实践,建议收藏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C++学习(三)LHS RHS
- 下一篇: Oracle 数据库一体机:zData