真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

zblog使用redis redis zpop

Redis 實戰(zhàn) —— 10. 實現(xiàn)內(nèi)容搜索、定向廣告和職位搜索

通過改變程序搜索數(shù)據(jù)的方式,并使用 Redis 來減少絕大部分基于單詞或者關鍵字進行的內(nèi)容搜索操作的執(zhí)行時間。 P154

創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務,包含不限于成都做網(wǎng)站、網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設、浮山網(wǎng)絡推廣、小程序開發(fā)、浮山網(wǎng)絡營銷、浮山企業(yè)策劃、浮山品牌公關、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務,您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)公司為所有大學生創(chuàng)業(yè)者提供浮山建站搭建服務,24小時服務熱線:18982081108,官方網(wǎng)址:www.cdcxhl.com

倒排索引 (inverted indexes) 是互聯(lián)網(wǎng)上絕大部分搜索引擎使用的底層結(jié)構(gòu),它類似于書本末尾的索引。倒排索引從每個被索引的文檔里面提取一些單詞,并記錄包含每個單詞的文檔集合。 P154

示例

假設有三個文檔:

我們就能得到下面的倒排索引集合:

檢索的條件 "what", "is" 和 "it" 將對應這個集合: {0,1} ∩ {0,1,2} ∩ {0,1,2} = {0,1}

可以發(fā)現(xiàn) Redis 的集合和有序集合非常適合處理倒排索引。

基本索引操作

從文檔里面提取單詞的過程通常被成為語法分析 (parsing) 和標記化 (tokenization) ,這個過程可以產(chǎn)生一系列用于表示文檔的標記 (token) ,有時又被成為單詞 (word) 。 P155

標記化的一個常見的附加步驟就是移除非用詞 (stop word) 。非用詞就是那些在文檔中頻繁出現(xiàn)卻沒有提供相應信息量的單詞,對這些單詞進行搜索將返回大量無用的結(jié)果。 P155

本書中實現(xiàn)方向索引的邏輯非常簡單:

如果需要支持中文等,就不能簡單進行英文分詞,需要分詞器進行處理。第一次接觸倒排索引是在 Elasticsearch 中,感興趣的可以了解 Elasticsearch 中倒排索引的實現(xiàn)以及 IK 中文分詞器。

基本搜索操作

在索引里面查找一個單詞是非常容易的,只需要獲取單詞集合里面的所有文檔即可。根據(jù)多個單詞查找文檔時,就需要根據(jù)條件處理對應的集合,再從最終集合中獲取所有文檔。 P156

可以使用 Redis 的集合操作完成對不同條件的處理:

通過以上三類命令,我們基本能實現(xiàn)條件大部分的與或非操作。

分析并執(zhí)行搜索

我們使用的查詢語句進行分詞后具有以下特征:

即: "connect +connection chat -proxy -proxies" 表示查詢的文檔需要包含 "connect" 或 "connection" ,同時也要包含 "chat" ,并且不能包含 "proxy" 和 "proxies" 。

實際處理時,先對同義詞組分別取并集,然后與需要查詢的單詞一起取交集,最后與不希望包含的單詞取差集,這樣所得到的集合就是用戶查詢的結(jié)果集。

上述搜索功能以及能夠搜索出用戶查詢的所有文檔唯一標識的集合,現(xiàn)在我們將根據(jù)這個文檔唯一標識集合以及每個文檔的具體信息進行排序分頁。

對于這種情況我們可以使用 Redis 的 SORT 命令對文檔唯一標識集合通過引用每個文檔的具體信息進行排序分頁。 ( 05. Redis 其他命令簡介 )

上面介紹了使用 Redis 進行搜索,并通過引用存儲在 HASH 里面的數(shù)據(jù)對搜索結(jié)果進行排序分頁。接下來將介紹利用集合和有序集合實現(xiàn)基于多個分值的復合排序操作,它能提供比 SORT 命令更高的靈活性。 P162

假設我們目前需要根據(jù)文檔對更新時間和得票數(shù)進行排序,為此我們需要用兩個有序集合存儲相關信息。這兩個有序集合的成員都是文檔唯一標識,成員的分值則分別是文檔的更新時間和得票數(shù)。

設經(jīng)過搜索后滿足搜索條件的文檔唯一標識集合為 filtered_doc_ids ,文檔唯一標識及其更新時間對應的有序集合為 doc_ids_with_update ,文檔唯一 標識及其得票數(shù)對應的有序集合為 doc_ids_with_votes 。那么可以通過 ZINTERSTORE 命令對這三個集合求交集,最后得出的滿足搜索條件的文檔唯一標識及其排序分值對應的有序集合,再使用 ZRANGE , ZREVRANGE 進行分頁獲取即可。 P162

示例: ZINTERSTORE filtered_doc_ids_with_sort_score 3 filtered_doc_ids doc_ids_with_update doc_ids_with_votes WEIGHTS 0 {update_weight} {vote_weight}

其中:

所思

這種利用分值的方法很巧妙,基本可以實現(xiàn)多字段排序,但是優(yōu)先級可能難以掌控,難以做到先按照某一字段排序,再按照另一字段排序的形式。因為每個字段對應的分值的數(shù)量級可能差別比較小,這個時候如果需要有排序字段的優(yōu)先級,那么可能需要對每個權(quán)重進行精巧地設計才行。

上面介紹了使用有序集合對多個數(shù)值字段進行排序,由于有序集合的分值只能是浮點數(shù),所以非數(shù)值字段不能直接用于排序,需要轉(zhuǎn)換成對應的浮點數(shù)。但由于雙精度浮點數(shù)只有 64 個二進制位,實際能使用 63 個二進制位,所以能表示的字符串并不多,只能使用字符串的前幾個字符進行分值估計,不足指定字符數(shù)的需要補齊到指定字符數(shù)。當然如果字符集縮小的話,可以重新進行編碼計算,進而可以對更長的字符串進行分值估計。 P165

當這個分值特別大的時候,可能會引發(fā)最終計算的分值溢出而出錯的問題。

接下來將介紹使用集合和有序集合構(gòu)建出一個幾乎完整的廣告服務平臺 (ad-serving platform) 。 P166

針對廣告的索引操作和針對其他內(nèi)容的索引操作并沒有太大的不同,被索引的的廣告通常都擁有像位置、年齡和性別這類必需的定向參數(shù),并且往往只會返回單個廣告。 P167

廣告的價格 P167

為了盡可能簡化廣告價格的計算方式,將對所有類型的廣告進行轉(zhuǎn)換,使得它們的價格可以基于每千次展示進行計算,產(chǎn)生出一個估算 CPM (estimated CPM, eCPM) 。 P168

將廣告插入倒排索引 P169

我們基本可以復用上面提到的搜索功能,除了會將廣告的關鍵詞插入倒排索引,還會將廣告的定向參數(shù)(位置、年齡和性別等)插入倒排索引中,并記錄廣告的類型、基本價格和 eCPM 價格。 P169

當系統(tǒng)收到廣告定向請求的時候,它要做的就是在匹配用戶定向參數(shù)的一系列廣告里面,找出 eCPM 最高的那一個廣告。同時,程序還會記錄頁面內(nèi)容與廣告內(nèi)容的匹配程度,以及不同匹配程度對廣告點擊通過率的影響等統(tǒng)計數(shù)據(jù)。通過使用這些統(tǒng)計數(shù)據(jù),廣告中與頁面相匹配的那些內(nèi)容就會作為附加值被計入 CPC 和 CPA 的 eCPM 價格,使得那些包含了匹配內(nèi)容的廣告能夠更多地被展示出來。 P170

計算附加值

計算附加值就是基于頁面內(nèi)容和廣告內(nèi)容兩者之間匹配的單詞,計算出應該給廣告的 eCPM 價格加上多少增量。每個單詞都有一個有序集合,成員為廣告 id ,成員的分值為當前單詞對這則廣告的 eCPM 的附加值。 P171

在尋找合適的廣告時,我們首先會過濾出匹配定位位置且至少包含一個頁面單詞的廣告,然后通過計算附加值的方法替代搜索,以便實現(xiàn)每次投放價值最高的廣告,并能夠根據(jù)用戶的行為學習。同時由于每個廣告匹配的內(nèi)容不同,最優(yōu)方式應該是使用加權(quán)平均值來計算單詞部分的附加值,但限于 Redis 本身的命令,我們最終采取 (max + min) / 2 的形式計算單詞部分的附加值(max 表示所有匹配單詞的最大附加值, min 表示所有匹配單詞的最小附加值),采用如下命令即可: ZUNIONSTORE final_score 3 base max min WEIGHTS 1 0.5 0.5 。

從用戶行為中學習 P175

首先需要存儲用戶的瀏覽記錄,包括三部分:(每 100 次就主動更新一次 eCPM ) P175

其次需要存儲用戶的點擊和動作記錄,用于計算 點擊通過率 = 點擊量或動作次數(shù) / 廣告展示次數(shù)。(每次都更新 eCPM) P176

最后就是更新 eCPM ,包括兩部分:

接下來將使用集合和有序集合實現(xiàn)職位搜索功能,并根據(jù)求職者擁有技能來為他們尋找合適的職位。 P180

第一反應肯定是直接對每一個求職者搜索所有的崗位,從而找到求職者合適的崗位。但這種方法效率極低(大部分崗位肯定是技能對不上的),而且無法進行性能擴展。 P181

使用類似上面提到的附加值形式,每次添加一個崗位時,在對應的技能集合中添加這個崗位的 id ( SADD idx:skill:{skill} {job_id} ),再在崗位有序集合中進行添加,成員為崗位 id ,成員的分值為所需的技能數(shù)量 ( ZADD job_required_skill_count {job_id} {required_skill_count} )。搜索的時候就先對求職者所有技能對應的集合使用 ZUNIONSTORE 操作計算每個公司匹配的技能數(shù)量 ( ZUNIONSTORE matched {n} idx:skill:{skill} ... WEIGHTS 1 ... ),然后再與崗位有序集合求交集,并讓公司有序集合的權(quán)重為 -1 ( ZINTERSTORE result 2 job_required_skill_count matched WEIGHTS -1 1 ),最后獲取分值為 0 的所有崗位即可完成搜索。 P181

所思

書上的這個方法比較麻煩,其實可以使用文章最開始的無序倒排索引,崗位相當于要搜索的文檔,崗位所需的技能相當于單詞。

lua腳本~ Redis調(diào)用

參考資料:

redis常見命令

官方調(diào)用lua文檔

redis菜鳥教程

lua菜鳥教程

其他:

一句話,因為要用所以學習簡單粗暴

本次僅學習如何使用redis調(diào)用lua腳本(含springboot調(diào)用方式),lua腳本如何寫以后有時間在玩。

寫redis鎖時經(jīng)常使用的一個腳本:

我這里的客戶端用的 windows 的,將準備好的 lua 腳本放在自己指定的文件夾

報錯了?。?! why ??? 這個符合eval語法吖?

其實,這里面有一個問題就是如果想要直接執(zhí)行文件,就不需要進入 redis-client

當然如果想要在 reids-client 內(nèi)執(zhí)行怎么辦呢?

這里展示部分代碼

將腳本放在 resouces 文件下 lua/unlock.lua

測試代碼:

測試控制臺結(jié)果。當然也需要在redis-client中檢查下是否是正確的結(jié)果

風控系統(tǒng)實踐之感: drools 和 redis

需求:

開發(fā)一個風控系統(tǒng),系統(tǒng)包括, 規(guī)則引擎和計算引擎, 主要的內(nèi)容如下:

1. 規(guī)則的增刪改和實時生效, 規(guī)則的分類執(zhí)行

2. 按照一定的緯度計算累計值,比如按照 IP, 用戶 id, 賬戶 等緯度。

3. 需要支持滑動窗口,滾動窗口,長度窗口等

遇到的問題主要有以下幾點:

1. redis 做流計算太過勉強,一是根據(jù)業(yè)務上的需求,需要統(tǒng)計的key 至少有幾億個,最多也有幾十億個,另外redis 中需要存儲少量的交易的信息。估算下來量也是非常可觀

2. redis 中 hot key 特別明顯,比如按照商戶的緯度去統(tǒng)計,如果不對商戶的key 進行拆封,像盒馬那種流量的商戶,對redis 的壓力是非常大的。

我們采用的是redis 的cluster 模式,這樣的話redis hot key 對redis 影響會更大。對其進行拆分是非常必要的,比如 按照小時拆分。?

3. 流式計算中,一個是亂序?qū)е吕奂拥挠嬎悴粶蚀_(有負值),另外一個是消息延遲. 當時我們嘗試使用flink 中的水印的概念去解決問題,發(fā)現(xiàn)并不適合。這個坑也是我們實踐過后才發(fā)現(xiàn)的。

最痛苦的經(jīng)歷是亂序和延遲消息的解決,現(xiàn)在是采取糾正的方式解決。

規(guī)則引擎

規(guī)則引擎我們選用了drools,簡單的探索了drools core, drools DRL, drools CEP 等,但是回頭看看,針對drools的使用缺點還是很多, 而且很明顯,暫時還沒有替換的打算.?

1. 使用 drools CEP 如何做分布式? 我們發(fā)現(xiàn)drools CEP中的幾種窗口都是內(nèi)存計算的,應用到分布式中就沒有很好的辦法,幾乎做不到,除非drools 也去集成redis等這種分布式緩存。

2. 使用drools 覺得很笨重,因為依賴比較多,二是我們只用到了 drools 中的 if else 等判斷,許多其它的功能基本就用不到,因為 1 中解決不了分布式的問題。所以從這點來說drools 已經(jīng)廢了,根本不用在創(chuàng)建kiesession 這種 重量級的東西。

3. drools中支持的運算符不是特別充分,比如像 log 運算,sum, max, avg 這種的運算等都是不支持的. DRL 語言對業(yè)務人員來說不是非常的友好。

4. 另外drools 中的 連續(xù),非連續(xù)的規(guī)則,沒有看出來如何配置,至少flink cep 是有這樣API的。

綜上所描述,不得不吐槽下 drools真是無語,也許了解的很簡單,還有別的方式,另外drools workbench 也是很無語,很復雜,估計drools 廠商想通過這種方式掙錢。

總體感覺,如果有別的選擇,最好不要選用drools,分布式的問題沒有解決,就等于廢了,因為各種分布式窗口都需要我們自己去實現(xiàn)。怎么辦呢??

規(guī)則引擎最后還是采用了drools,根據(jù)具體的業(yè)務含義創(chuàng)建不同的kiesession,? drools 起到了if else 判斷的作用,至于滾動窗口,長度窗口和滑動窗口都通過redis來做計算。遇到頭疼的問題,是

1. 根據(jù)不同的統(tǒng)計緯度,大概計算了下,需要幾十億個key,在redis 中做計算

2. 滑動窗口暫時靠 redis的zsort 的數(shù)據(jù)結(jié)構(gòu),性能不是非常好

3. 熱點key 的問題,特別對于大商戶的熱點key 的問題,需要做拆分,拆分起來是比較復雜的

4. 消息延遲和消息亂序問題。

所以計算引擎的需求一般是

1. 計算很快,大幾百個規(guī)則,能夠很快的計算出準確的結(jié)果來

2. 計算準確率,當面對亂序和延遲消息的時候,如何計算的更加準確

3. 計算的量的問題,正如前面提到的,幾十億個key,另外還需要存儲一些信息,計算的中間狀態(tài)等,如何在redis 中丟失,就會造成計算不準確。

基于以上的問題,關鍵是如何做的更好,優(yōu)化的更好,說實話,我沒有找到答案,可以做的就是不斷的優(yōu)化redis 計算(暫時不能上大數(shù)據(jù),比如flink, spark 等),減少redis 的操作帶來的網(wǎng)絡開銷。

其實最后還要提一下,如果能采用內(nèi)存計算,不用分布式計算,會不會速度更快點,比如根據(jù)業(yè)務來做分片,這樣在各個實例統(tǒng)計的中間值就不用匯總,那么每個實例只需要內(nèi)存計算就好,不需要訪問redis而帶來的網(wǎng)絡開銷。但是這樣做也會帶來架構(gòu)層面的調(diào)整,比如 如何做 fault tolerance, 如何做 狀態(tài)持久化, 等一系列的問題。?

從使用redis結(jié)果來看,效果也不是那么差,不考慮非常熱點key 的情況下,最高tps 也達到6000多(2 臺機器,16core,32G 內(nèi)存), 一般公司的業(yè)務其實是可以滿足的,對于非常熱點的key,后續(xù)的優(yōu)化是繼續(xù)拆分.

一個好的風控系統(tǒng)是非常難的,做以筆記,以希望不斷成長

Redis數(shù)據(jù)庫適合使用于哪些應用場景

redis開創(chuàng)了一種新的數(shù)據(jù)存儲思路,使用redis,我們不用在面對功能單調(diào)的數(shù)據(jù)庫時,把精力放在如何把大象放進冰箱這樣的問題上,而是利用redis靈活多變的數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)操作,為不同的大象構(gòu)建不同的冰箱。

redis常用數(shù)據(jù)類型

redis最為常用的數(shù)據(jù)類型主要有以下五種:

string

hash

list

set

sorted set

在具體描述這幾種數(shù)據(jù)類型之前,我們先通過一張圖了解下redis內(nèi)部內(nèi)存管理中是如何描述這些不同數(shù)據(jù)類型的:

首先redis內(nèi)部使用一個redisobject對象來表示所有的key和value,redisobject最主要的信息如上圖所示:type代表一

個value對象具體是何種數(shù)據(jù)類型,encoding是不同數(shù)據(jù)類型在redis內(nèi)部的存儲方式,比如:type=string代表value存儲的是

一個普通字符串,那么對應的encoding可以是raw或者是int,如果是int則代表實際redis內(nèi)部是按數(shù)值型類存儲和表示這個字符串的,當然

前提是這個字符串本身可以用數(shù)值表示,比如:"123"

"456"這樣的字符串。

這里需要特殊說明一下vm字段,只有打開了redis的虛擬內(nèi)存功能,此字段才會真正的分配內(nèi)存,該功能默認是關閉狀態(tài)的,該功能會在后面具體描述。通過

上圖我們可以發(fā)現(xiàn)redis使用redisobject來表示所有的key/value數(shù)據(jù)是比較浪費內(nèi)存的,當然這些內(nèi)存管理成本的付出主要也是為了給

redis不同數(shù)據(jù)類型提供一個統(tǒng)一的管理接口,實際作者也提供了多種方法幫助我們盡量節(jié)省內(nèi)存使用,我們隨后會具體討論。

下面我們先來逐一的分析下這五種數(shù)據(jù)類型的使用和內(nèi)部實現(xiàn)方式:

string

常用命令:

set,get,decr,incr,mget 等。

應用場景:

string是最常用的一種數(shù)據(jù)類型,普通的key/value存儲都可以歸為此類,這里就不所做解釋了。

實現(xiàn)方式:

string在redis內(nèi)部存儲默認就是一個字符串,被redisobject所引用,當遇到incr,decr等操作時會轉(zhuǎn)成數(shù)值型進行計算,此時redisobject的encoding字段為int。

hash

常用命令:

hget,hset,hgetall 等。

應用場景:

我們簡單舉個實例來描述下hash的應用場景,比如我們要存儲一個用戶信息對象數(shù)據(jù),包含以下信息:

用戶id為查找的key,存儲的value用戶對象包含姓名,年齡,生日等信息,如果用普通的key/value結(jié)構(gòu)來存儲,主要有以下2種存儲方式:

第一種方式將用戶id作為查找key,把其他信息封裝成一個對象以序列化的方式存儲,這種方式的缺點是,增加了序列化/反序列化的開銷,并且在需要修改其中一項信息時,需要把整個對象取回,并且修改操作需要對并發(fā)進行保護,引入cas等復雜問題。

第二種方法是這個用戶信息對象有多少成員就存成多少個key-value對兒,用用戶id+對應屬性的名稱作為唯一標識來取得對應屬性的值,雖然省去了序列化開銷和并發(fā)問題,但是用戶id為重復存儲,如果存在大量這樣的數(shù)據(jù),內(nèi)存浪費還是非??捎^的。

那么redis提供的hash很好的解決了這個問題,redis的hash實際是內(nèi)部存儲的value為一個hashmap,并提供了直接存取這個map成員的接口,如下圖:

也就是說,key仍然是用戶id,

value是一個map,這個map的key是成員的屬性名,value是屬性值,這樣對數(shù)據(jù)的修改和存取都可以直接通過其內(nèi)部map的key(redis里稱內(nèi)部map的key為field),

也就是通過 key(用戶id) + field(屬性標簽)

就可以操作對應屬性數(shù)據(jù)了,既不需要重復存儲數(shù)據(jù),也不會帶來序列化和并發(fā)修改控制的問題。很好的解決了問題。

這里同時需要注意,redis提供了接口(hgetall)可以直接取到全部的屬性數(shù)據(jù),但是如果內(nèi)部map的成員很多,那么涉及到遍歷整個內(nèi)部map的

操作,由于redis單線程模型的緣故,這個遍歷操作可能會比較耗時,而另其它客戶端的請求完全不響應,這點需要格外注意。

實現(xiàn)方式:

上面已經(jīng)說到redis

hash對應value內(nèi)部實際就是一個hashmap,實際這里會有2種不同實現(xiàn),這個hash的成員比較少時redis為了節(jié)省內(nèi)存會采用類似一維數(shù)組的方式來緊湊存儲,而不會采用真正的hashmap結(jié)構(gòu),對應的value

redisobject的encoding為zipmap,當成員數(shù)量增大時會自動轉(zhuǎn)成真正的hashmap,此時encoding為ht。

list

常用命令:

lpush,rpush,lpop,rpop,lrange等。

應用場景:

redis

list的應用場景非常多,也是redis最重要的數(shù)據(jù)結(jié)構(gòu)之一,比如twitter的關注列表,粉絲列表等都可以用redis的list結(jié)構(gòu)來實現(xiàn),比較好理解,這里不再重復。

實現(xiàn)方式:

redis

list的實現(xiàn)為一個雙向鏈表,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內(nèi)存開銷,redis內(nèi)部的很多實現(xiàn),包括發(fā)送緩沖隊列等也都是用的這個數(shù)據(jù)結(jié)構(gòu)。

set

常用命令:

sadd,spop,smembers,sunion 等。

應用場景:

redis

set對外提供的功能與list類似是一個列表的功能,特殊之處在于set是可以自動排重的,當你需要存儲一個列表數(shù)據(jù),又不希望出現(xiàn)重復數(shù)據(jù)時,set是一個很好的選擇,并且set提供了判斷某個成員是否在一個set集合內(nèi)的重要接口,這個也是list所不能提供的。

實現(xiàn)方式:

set 的內(nèi)部實現(xiàn)是一個

value永遠為null的hashmap,實際就是通過計算hash的方式來快速排重的,這也是set能提供判斷一個成員是否在集合內(nèi)的原因。

sorted set

常用命令:

zadd,zrange,zrem,zcard等

使用場景:

redis sorted set的使用場景與set類似,區(qū)別是set不是自動有序的,而sorted

set可以通過用戶額外提供一個優(yōu)先級(score)的參數(shù)來為成員排序,并且是插入有序的,即自動排序。當你需要一個有序的并且不重復的集合列表,那么可以選擇sorted

set數(shù)據(jù)結(jié)構(gòu),比如twitter 的public


網(wǎng)頁標題:zblog使用redis redis zpop
分享網(wǎng)址:http://weahome.cn/article/ddjseih.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部