Python Web項(xiàng)目開發(fā)-Python Flask開發(fā)-Python高級(jí)功能開發(fā)_第1頁
Python Web項(xiàng)目開發(fā)-Python Flask開發(fā)-Python高級(jí)功能開發(fā)_第2頁
Python Web項(xiàng)目開發(fā)-Python Flask開發(fā)-Python高級(jí)功能開發(fā)_第3頁
Python Web項(xiàng)目開發(fā)-Python Flask開發(fā)-Python高級(jí)功能開發(fā)_第4頁
Python Web項(xiàng)目開發(fā)-Python Flask開發(fā)-Python高級(jí)功能開發(fā)_第5頁
已閱讀5頁,還剩77頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

高級(jí)功能開發(fā)目錄CONTENTS一二三四利用Redis緩存數(shù)據(jù)Redis數(shù)據(jù)類型Redis常用命令接口與能測(cè)試Requests接口測(cè)試庫基于接口地能測(cè)試全文搜索功能全文搜索簡(jiǎn)介文分詞處理全文搜索代碼實(shí)現(xiàn)首頁靜態(tài)化處理靜態(tài)化地價(jià)值首頁靜態(tài)化策略靜態(tài)化代碼實(shí)現(xiàn)Redis持久化Redis可視化工具靜態(tài)化代碼優(yōu)化Python操作RedisRedis使用倒排索引原理利用Redis緩存數(shù)據(jù)Redis數(shù)據(jù)類型Redis常用命令PART一子目錄Redis持久化Redis可視化工具Python操作RedisRedis使用熟練使用Redis命令及Python地Redis框架。熟練應(yīng)用緩存技術(shù)為系統(tǒng)設(shè)計(jì)緩存策略并利用代碼實(shí)現(xiàn)。對(duì)頁面靜態(tài)化地一些處理方式與策略有深入理解。理解全文搜索地實(shí)現(xiàn)原理并應(yīng)用于蝸牛筆記。熟練使用Python地requests庫與多線程技術(shù)對(duì)系統(tǒng)行接口與能測(cè)試。課程目地Redis是一個(gè)開源地使用ANSIC語言編寫,遵守BSD協(xié)議,支持網(wǎng)絡(luò),可基于內(nèi)存亦可持久化地日志型,Key-Value數(shù)據(jù)庫,并提供多種語言地API。它通常被稱為數(shù)據(jù)結(jié)構(gòu)服務(wù)器,因?yàn)橹悼梢允亲址?String),哈希(Hash),列表(List),集合(Sets)與有序集合(SortedSets)等類型。其字符串類型,列表,與集合與Python地?cái)?shù)據(jù)類型是完全一樣地,特也基本相同。而有序集合則是經(jīng)過排序地集合類型。除些以外,哈希類型則是與Python地字典類型對(duì)應(yīng),其值本身也是由Key-Value構(gòu)成鍵值對(duì)。在所有地Redis地?cái)?shù)據(jù)類型,字符串是構(gòu)成所有類型地基礎(chǔ)。Redis數(shù)據(jù)類型Redis各數(shù)據(jù)類型地用法及注意事項(xiàng)。Redis數(shù)據(jù)類型數(shù)據(jù)類型KeyValue注意事項(xiàng)字符串(String)username蝸牛學(xué)院Redis沒有數(shù)字類型,歸為字符串類型password一二三四五七哈希(Hash)articleKey:articleidValue:一二三Hash類型地值本身又是一個(gè)鍵值對(duì)地字典類型Key:headlineValue:Redis緩存策略詳解mentKey:contentValue:后臺(tái)架構(gòu)地能優(yōu)化列表(List)headlineFlask地路由規(guī)則解析列表地值可以重復(fù),也可以存JSON數(shù)據(jù)jQuery與VUE地應(yīng)用場(chǎng)景RESTful地接口規(guī)范研究集合(Sets)phone一三八一二三四五六七八集合地用法與列表類似,只是存地值不允許重復(fù)一八八九八七四五六一三一五五七八四五六三二一有序集合(SortedSets)phone一三八一二三四五六七八有序集合也稱ZSet,當(dāng)值寫入后將會(huì)行排序后保存一五五七八四五六三二一一八八九八七四五六一三另外,Redis緩存數(shù)據(jù)庫跟MySQL數(shù)據(jù)庫類似,一個(gè)服務(wù)器上可以保存多個(gè)數(shù)據(jù)庫,并且可以使用select命令切換到不同地?cái)?shù)據(jù)庫。一個(gè)Redis數(shù)據(jù)庫可以保存多條Key,每條Key可以對(duì)應(yīng)多條數(shù)據(jù)。下圖對(duì)Redis地常用數(shù)據(jù)類型與命令行了演示。Redis數(shù)據(jù)類型當(dāng)Redis服務(wù)器啟動(dòng)后,再啟動(dòng)其客戶端即可執(zhí)行Redis常見地命令。下表列舉了常用地與Key有關(guān)地操作命令。Redis常用命令命令描述用法DEL(一)刪除給定地一個(gè)或多個(gè)Key(二)不存在地Key將被忽略DELkey[key...]

EXISTS(一)檢查給定Key是否存在EXISTSkeyEXPIRE

(一)為給定Key設(shè)置生存時(shí)間(二)對(duì)一個(gè)已經(jīng)指定生存時(shí)間地Key設(shè)置執(zhí)行EXPIRE,新地值會(huì)代替舊地值EXPIREkeyseconds

KEYS

查找所有符合給定模式pattern地Key,例如:(一)KEYS*匹配所有key(二)KEYSh?llo匹配hello,hallo,hxllo等(三)KEYSh*llo匹配hllo,heeeeello等(四)KEYSh[ae]llo匹配hello與halloKEYSpattern

MIGRATE

(一)原子地將Key從當(dāng)前實(shí)例傳送到目地實(shí)例指定地?cái)?shù)據(jù)庫上(二)原數(shù)據(jù)庫Key刪除,新數(shù)據(jù)庫Key增加(三)阻塞行遷移地兩個(gè)實(shí)例,直到遷移成功,遷移失敗,等待超時(shí)三個(gè)之一發(fā)生MIGRATEhostportkeydestination-dbtimeout[COPY][REPLACE]當(dāng)Redis服務(wù)器啟動(dòng)后,再啟動(dòng)其客戶端即可執(zhí)行Redis常見地命令。下表列舉了常用地與Key有關(guān)地操作命令。Redis常用命令命令描述用法MOVE

(一)將當(dāng)前數(shù)據(jù)庫地Key移動(dòng)到給定數(shù)據(jù)(二)執(zhí)行成功地條件為當(dāng)前數(shù)據(jù)庫有Key,而給定數(shù)據(jù)庫沒有KeyMOVEkeydb

PERSIST(一)移除給定Key地生存時(shí)間,將Key變?yōu)槌志脭?shù)據(jù)PERSISTkeyRANDOMKEY(一)從當(dāng)前數(shù)據(jù)庫隨機(jī)返回且不刪除一個(gè)Key,RANDOMKEYRENAME

(一)將Key地鍵名修改為新鍵名(三)新鍵名已存在,RENAME將覆蓋舊值RENAMEkeynewkey

TYPE(一)返回Key鎖存儲(chǔ)地值地類型TYPEkey下表列舉了針對(duì)字符串類型地常用操作命令。Redis常用命令命令描述用法SET(一)將字符串值Value關(guān)聯(lián)到Key(二)Key已關(guān)聯(lián)則覆蓋,無視類型(三)原本Key帶有生存時(shí)間TTL,那么TTL被清除SETkeyvalue[EXseconds][PXmilliseconds][NX|XX]GET

(一)返回Key關(guān)聯(lián)地字符串值(二)Key不存在返回nil(三)Key存儲(chǔ)地不是字符串,返回錯(cuò)誤,因?yàn)镚ET只用于處理字符串GETkey

MSET

(一)同時(shí)設(shè)置一個(gè)或多個(gè)Key-Value鍵值對(duì)(二)某個(gè)給定Key已經(jīng)存在,那么MSET新值會(huì)覆蓋舊值(三)如果上面地覆蓋不是希望地,那么使用MSETNX命令,所有Key都不存在才會(huì)行覆蓋(四)MSET是一個(gè)原子操作,所有Key都會(huì)在同一時(shí)間被設(shè)置,不會(huì)存在有些更新有些沒更新地情況MSETkeyvalue[keyvalue...]

MGET

(一)返回一個(gè)或多個(gè)給定Key對(duì)應(yīng)地Value(二)某個(gè)Key不存在那么這個(gè)Key返回nilMGETkey[key...]

下表列舉了針對(duì)字符串類型地常用操作命令。Redis常用命令命令描述用法SETEX

(一)將Value關(guān)聯(lián)到Key(二)設(shè)置Key生存時(shí)間為seconds,單位為秒(三)如果Key對(duì)應(yīng)地Value已經(jīng)存在,則覆蓋舊值(四)SET也可以設(shè)置失效時(shí)間,但是不同在于SETNX是一個(gè)原子操作,即關(guān)聯(lián)值與設(shè)置生存時(shí)間同一時(shí)間完成SETEXkeysecondsvalue

SETNX

(一)當(dāng)Key不存在時(shí)將Key地值設(shè)為Value(二)若給定地Key已存在,SEXNX不做任何動(dòng)作SETNXkeyvalue

INCR(一)Key存儲(chǔ)地?cái)?shù)字值+一,返回增加之后地值(二)Key不存在,那么Key地值被初始化為零再執(zhí)行INCR(三)如果值包含錯(cuò)誤類型或者字符串不能被表示為數(shù)字,那么返回錯(cuò)誤(四)值限制在六四位有符號(hào)數(shù)字表示之內(nèi)INCRkey

DECR(一)Key存儲(chǔ)地?cái)?shù)字值-一(二)其余同INCRDECRkeyINCRBY(一)將key所存儲(chǔ)地值加上增量返回增加之后地值(二)其余同INCRINCRBYkeyincrementDECRBY

(一)將key所存儲(chǔ)地值減去減量decrement(二)其余同INCRDECRBYkeydecrement下表列舉了針對(duì)哈希類型地常用操作命令。Redis常用命令命令描述用法HSET

(一)將哈希表Key地域Field地值設(shè)為Value(二)Key不存在,一個(gè)新地Hash表被創(chuàng)建(三)Field已經(jīng)存在,舊地值被覆蓋HSETkeyfieldvalueHGET(一)返回哈希表Key給定域Field地值HGETkeyfieldHDEL

(一)刪除哈希表Key地一個(gè)或多個(gè)指定域(二)不存在地域?qū)⒈缓雎訦DELkeyfiled[field...]HEXISTS

(一)查看哈希表Key,給定域Field是否存在,存在返回一,不存在返回零HEXISTSkeyfield

HGETALL(一)返回哈希表Key,所有地域與值HGETALLkey

HINCRBY

(一)為哈希表Key地域Field加上增量Increment(二)其余同INCR命令HINCRYBYkeyfiledincrement

HKEYS(一)返回哈希表Key地所有域

HKEYSkeyHLEN(一)返回哈希表Key域地?cái)?shù)量HLENkey

HMGET

(一)返回哈希表Key,一個(gè)或多個(gè)給定域地值(二)如果給定地域不存在于哈希表,那么返回一個(gè)nil值HMGETkeyfield[field...]HMSET

(一)將多個(gè)Field-Value對(duì)設(shè)置到哈希表Key(二)會(huì)覆蓋哈希表已存在地域(三)Key不存在,那么一個(gè)空哈希表會(huì)被創(chuàng)建并執(zhí)行HMSET操作HMSETkeyfieldvalue[fieldvalue...]

HVALS(一)返回哈希表Key所有地域與值HVALSkey列舉了針對(duì)列表類型地常用操作命令。Redis常用命令命令描述用法LPUSH

(一)將一個(gè)或多個(gè)值Value插入到列表Key地表頭(二)如果有多個(gè)Value值,那么各個(gè)Value值按從左到右地順序依次插入表頭(三)Key不存在,一個(gè)空列表會(huì)被創(chuàng)建并執(zhí)行LPUSH操作(四)Key存在但不是列表類型,返回錯(cuò)誤LPUSHkeyvalue[value...

LPUSHX

(一)將值Value插入到列表Key地表頭,當(dāng)且僅當(dāng)Key存在且為一個(gè)列表(二)當(dāng)Key不存在時(shí),LPUSHX命令什么都不做

LPUSHXkeyvalue

LPOP(一)移除并返回列表Key地頭元素LPOPkeyLRANGE

(一)返回列表Key指定區(qū)間內(nèi)地元素,區(qū)間以偏移量Start與Stop指定(二)Start與Stop都以零為底開始計(jì)數(shù)(三)可使用負(fù)數(shù)下標(biāo),-一表示列表最后一個(gè)元素,-二表示列表倒數(shù)第二個(gè)元素,以此類推(四)Start大于列表最大下標(biāo),返回空列表(五)Stop大于列表最大下標(biāo),Stop=列表最大下標(biāo)LRANGEkeystartstop

LREM

(一)根據(jù)Count地值,移除列表與Value相等地元素(二)Count>零表示從頭到尾搜索,移除與Value相等地元素,數(shù)量為Count(三)Count<零表示從從尾到頭搜索,移除與Value相等地元素,數(shù)量為Count(四)Count=零表示移除表所有與Value相等地元素LREMkeycountvalue

LSET

(一)將列表Key下標(biāo)為Index地元素值設(shè)為Value(二)Index參數(shù)超出范圍,或?qū)σ粋€(gè)空列表行LSET時(shí),返回錯(cuò)誤LSETkeyindexvalue

列舉了針對(duì)列表類型地常用操作命令。Redis常用命令命令描述用法LINDEX(一)返回列表Key,下標(biāo)為Index地元素LINDEXkeyindexLINSERT

一)將值Value插入列表Key,位于Pivot前面或者后面(二)Pivot不存在于列表Key時(shí),不執(zhí)行任何操作(三)Key不存在,不執(zhí)行任何操作LINSERTkeyBEFORE|AFTERpivotvalue

LLEN

(一)返回列表Key地長(zhǎng)度(二)Key不存在,返回零LLENkey

LTRIM

(一)對(duì)一個(gè)列表行修剪,讓列表只返回指定區(qū)間內(nèi)地元素,不存在指定區(qū)間內(nèi)地都將被移除LTRIMkeystartstop

RPOP(一)移除并返回列表Key地尾元素RPOPkeyRPOPLPUSH

(在一個(gè)原子時(shí)間內(nèi),執(zhí)行兩個(gè)動(dòng)作:(一)將列表Source最后一個(gè)元素彈出并返回給客戶端(二)將Source彈出地元素插入到列表Desination,作為Destination列表地頭元素RPOPLPUSHsourcedestination

RPUSH

(一)將一個(gè)或多個(gè)值Value插入到列表Key地表尾

RPUSHkeyvalue[value...]RPUSHX

(一)將Value插入到列表Key地表尾,當(dāng)且僅當(dāng)Key存在并且是一個(gè)列表(二)Key不存在,RPUSHX什么都不做RPUSHXkeyvalue

Redis其它常用命令列表Redis常用命令SADD

(一)將一個(gè)或多個(gè)member元素加入到key,已存在在集合地member將被忽略(二)假如key不存在,則只創(chuàng)建一個(gè)只包含member元素做成員地集合(三)當(dāng)key不是集合類型時(shí),將返回一個(gè)錯(cuò)誤

SADDkeynumber[member...]

SCARD(一)返回key對(duì)應(yīng)地集合地元素?cái)?shù)量

SCARDkeySREM

(一)移除集合key地一個(gè)或多個(gè)member元素,不存在地member將被忽略SREMkeymember[member...]SMEMBERS

(一)返回集合key地所有成員(二)不存在地key被視為空集SMEMBERSkey

ZADD

(一)將一個(gè)或多個(gè)member元素及其score值加入有序集key(二)如果member已經(jīng)是有序集地成員,那么更新member對(duì)應(yīng)地score并重新插入member保證member在正確地位置上(三)score可以是整數(shù)值或雙精度浮點(diǎn)數(shù)ZADDkeyscoremember[[scoremember][scoremember]...]

ZCARD(一)返回有序集key地元素個(gè)數(shù)ZCARDkey

ZCOUNT

(一)返回有序集key,score值>=min且<=max地成員地?cái)?shù)量ZCOUNTkeyminmax

ZRANGE

(一)返回有序集key指定區(qū)間內(nèi)地成員,成員位置按score從小到大排序(二)具有相同score值地成員按字典序排列(三)需要成員按score從大到小排列,使用ZREVRANGE命令(四)下標(biāo)參數(shù)start與stop都以零為底,也可以用負(fù)數(shù),-一表示最后一個(gè)成員,-二表示倒數(shù)第二個(gè)成員(五)可通過WITHSCORES選項(xiàng)讓成員與它地score值一并返回ZRANGEkeystartstop[WITHSCORES]

Redis其它常用命令列表Redis常用命令ZRANK

(一)返回有序集key成員member地排名,有序集成員按score值從小到大排列(二)排名以零為底,即score最小地成員排名為零(三)ZREVRANK命令可將成員按score值從大到小排名ZRANKkeynumber

ZREM

(一)移除有序集key地一個(gè)或多個(gè)成員,不存在地成員將被忽略(二)當(dāng)key存在但不是有序集時(shí),返回錯(cuò)誤

ZREMkeymember[member...]

SELECT

(一)切換到指定數(shù)據(jù)庫,數(shù)據(jù)庫索引index用數(shù)字指定,以零作為起始索引值(二)默認(rèn)使用零號(hào)數(shù)據(jù)庫SELECTindex

DBSIZE(一)返回當(dāng)前數(shù)據(jù)庫地Key地?cái)?shù)量DBSIZESHUTDOWN

(一)停止所有客戶端(二)如果至少有一個(gè)保存點(diǎn)在等待,執(zhí)行SAVE命令(三)如果AOF選項(xiàng)被打開,更新AOF文件(四)關(guān)閉Redis服務(wù)器SHUTDOWN[SAVE|NOSAVE]

FLUSHDB(一)清空當(dāng)前數(shù)據(jù)庫地所有KeyFLUSHDBFLUSHALL(一)清空整個(gè)Redis服務(wù)器地?cái)?shù)據(jù)(刪除所有數(shù)據(jù)庫地所有Key)FLUSHALL目前Redis提供了RDB與AOF兩種主要地持久化方案,用戶可以基于這兩種持久化方案來配置以下四種策略。(一)RDB持久化方式能夠在指定地時(shí)間間隔內(nèi)對(duì)數(shù)據(jù)行快照存儲(chǔ),這也是Redis默認(rèn)地持久化策略。(二)AOF持久化方式記錄每次對(duì)服務(wù)器寫地操作,當(dāng)服務(wù)器重啟地時(shí)候會(huì)重新執(zhí)行這些命令來恢復(fù)原始地?cái)?shù)據(jù)。AOF命令以Redis協(xié)議追加保存每次寫地操作到文件末尾。由于用戶執(zhí)行地命令可能存在重復(fù),所以可以直接修改AOF文件,刪除一些重復(fù)地命令。(三)同時(shí)開啟兩種持久化方式。在這種情況下,當(dāng)Redis重啟地時(shí)候會(huì)優(yōu)先載入AOF文件來恢復(fù)原始地?cái)?shù)據(jù)。因?yàn)樵谕ǔG闆r下,AOF文件保存地?cái)?shù)據(jù)集要比RDB文件保存地?cái)?shù)據(jù)集要完整。(四)不使用任何持久化方式,在配置文件將其完全關(guān)閉。這樣可以更多地提升能,但是針對(duì)一些重要地?cái)?shù)據(jù),不建議禁用持久化。Redis持久化要配置Redis地持久化策略,只需要編輯Redis目錄下地redis.windows.conf文件,修改相應(yīng)配置信息并重啟Redis服務(wù)器。例如,下面地配置項(xiàng)表明使用RDB行持久化,在六零秒地時(shí)間內(nèi)只要修改過一次,則觸發(fā)Redis將數(shù)據(jù)保存到硬盤。Redis持久化save六零一#六零秒內(nèi)只要修改過一次Key,則行持久化保存

appendonlyno#默認(rèn)AOF模式關(guān)閉,設(shè)為yes即可打開修改完配置文件并使用RDB方式,在六零秒地時(shí)間內(nèi),修改或新建一次Key地值,則就會(huì)行一次持久化,并在Redis目錄下生成一個(gè)dump.rdb地文件。下一次啟動(dòng)Redis服務(wù)器時(shí),會(huì)將該文件地?cái)?shù)據(jù)加載到內(nèi)存,實(shí)現(xiàn)了數(shù)據(jù)地持久化保存。但是設(shè)置六零秒修改一次只是為了更快速地完成實(shí)驗(yàn),實(shí)際地應(yīng)用過程,不建議頻繁地行持久化,這樣會(huì)降低能。由于Redis地客戶端是一個(gè)純命令行地工具,無法很直觀地對(duì)數(shù)據(jù)庫地行查看。所以可以安裝RedisDesktopManager工具,這樣就可以行可視化操作了。Redis可視化工具RedisDesktopManager運(yùn)行界面↓從圖可以看到,mykey是Redis地哈希類型地Key,其值對(duì)應(yīng)地也是Key-Value構(gòu)成,而其地Value可以存儲(chǔ)任意格式地字符串。例如,其info存儲(chǔ)地是一個(gè)字典類型地?cái)?shù)據(jù),而branch存儲(chǔ)地?cái)?shù)據(jù)格式是列表。事實(shí)上,只是肉眼上看起來是字典與列表而已,本質(zhì)存儲(chǔ)地都是一個(gè)字符串,只是格式上與字典與列表一樣而已,相當(dāng)于在其值地前后加上了雙引號(hào)。但是在Python,可以通過全局函數(shù)eval來運(yùn)行這些字符串,可以直接將其轉(zhuǎn)換為Python對(duì)應(yīng)地?cái)?shù)據(jù)類型。Redis可視化工具事實(shí)上,Redis本身是一個(gè)標(biāo)準(zhǔn)地網(wǎng)絡(luò)服務(wù)器,只要遵循Redis地通信接口規(guī)范,任何一門編程語言都可以很容易地連接到Redis服務(wù)器上并執(zhí)行命令。下面地代碼利用Python通過Socket連接到Redis服務(wù)器,并發(fā)送了一批滿足Redis協(xié)議規(guī)范地字符串,為Redis設(shè)置了一個(gè)變量phone并通過get命令取得其值。Python操作Redisimportsocket#引入Python地socket類

s=socket.socket()s.connect(('一二七.零.零.一',六三七九))#與Redis建立連接,并基于協(xié)議規(guī)則發(fā)送數(shù)據(jù)包s.send(b'*三\r\n')#*三表示發(fā)送地命令包含三個(gè)字符串s.send(b'$三\r\n')#$三表示接下來地字符串有三個(gè)字符s.send(b'set\r\n')s.send(b'$五\r\n')s.send(b'phone\r\n')s.send(b'$一一\r\n')#$一一表示接下來發(fā)地字符串有一一個(gè)字符s.send(b'一八八一二三四五六七八\r\n')r=s.recv(一零二四)#一條完整地命令發(fā)送完后接收Redis服務(wù)器響應(yīng)print(r.decode())#輸出+OK表示命令成功執(zhí)行

s.send(b'*二\r\n')s.send(b'$三\r\n')s.send(b'get\r\n')s.send(b'$五\r\n')s.send(b'phone\r\n')r=s.recv(一零二四)print(r.decode())#通過get命令讀取變量phone地值基于上述代碼地實(shí)現(xiàn)原理,目前地絕大部分編程語言都封裝了專門用于操作Redis地庫。Python地Redis庫便是對(duì)上述協(xié)議地封裝,用于方便地通過Python來操作Redis。下述代碼演示了通過Python來操作Redis地一些常見用法。Python操作Redisimportredis#指定Redis服務(wù)器地IP地址,端口號(hào)與數(shù)據(jù)庫行連接red=redis.Redis(host='一二七.零.零.一',port=六三七九,db=零)#使用連接池行連接,推薦使用此方式pool=redis.ConnectionPool(host='一二七.零.零.一',port=六三七九,decode_responses=True,db=零)red=redis.Redis(connection_pool=pool)下述代碼演示了通過Python來操作Redis地一些常見用法。Python操作Redis#普通字符串類型地值處理red.set('myname','qiang')#為myname設(shè)值red.mset({'age':'二零','addr':'上海'})#同時(shí)設(shè)置兩個(gè)字符串print(red.get('myname'))#獲取Key為myname值print(red.get('addr'))#獲取Key為addr地值print(red.exists('myname'))#判斷Key:myname是否存在#常用針對(duì)數(shù)據(jù)庫地操作print(red.dbsize())#列出當(dāng)前數(shù)據(jù)庫地Key地?cái)?shù)量print(red.lastsave())#獲取最后一次持久化地時(shí)間print(red.__dict__)#打印red對(duì)象地信息下述代碼演示了通過Python來操作Redis地一些常見用法。Python操作Redis#HASH值地處理#一次為mykey地哈希類型設(shè)置多個(gè)值red.hmset(name='mykey',mapping={'addr':'成都孵化園','tel':'零二八-一二三四五六七八','employee':二零零})red.hset(name='mykey',key='name',value='蝸牛學(xué)院')#新增一條哈希值到mykeyred.hsetnx(name='mykey',key='name',value='蝸牛學(xué)院二')#在mykey不存在name時(shí)新增dict=red.hgetall('mykey')#獲取mykey地所有值print(dict)#打印dict地值print(type(dict))#dict地類型為<class'dict'>print(red.hget(name="mykey",key="addr"))#讀取mykeyaddr字段地值print(red.hexists(name='mykey',key='name'))#判斷mykey是否存在name字段下述代碼演示了通過Python來操作Redis地一些常見用法。Python操作Redis#列表地處理(注意列表不能去重,如果需要去重可以使用集合)#同時(shí)為列表phone設(shè)置多個(gè)值,使用rpush表示在后面追加red.rpush('phonelist','一三八一二三四五六七八','一五八一二三四五六七八','一八八一二三四五六七八','一九九一二三四五六七八')red.lpush('phonelist','一五五四五六七八九二五')#在列表地開頭插入一個(gè)新值len=red.llen('phonelist')#遍歷并打印列表地所有值#foriinrange(len):#print(red.lindex('phonelist',i))#利用集合類型保存電話號(hào)碼,可以自動(dòng)去重red.sadd('phoneset','一三八一二三四五六七八','一五八一二三四五六七八','一八八一二三四五六七八','一九九一二三四五六七八')red.sadd('phoneset','一三八一二三四五六七八','一五八一二三四五六七八','一八八一二三四五六七八','一九九一二三四五六七八')#即使添加多次,仍然只會(huì)保存不重復(fù)地值phoneset=red.smembers('phoneset')#以Python地集合類型返回所有值forphoneinphoneset:print(phone)在前面章節(jié),對(duì)于用戶注冊(cè)與登錄均使用了驗(yàn)證碼,但是在服務(wù)器端是通過Session變量來保存驗(yàn)證碼地。但是Session變量并不能有效控制驗(yàn)證碼地過期時(shí)間,所以使用Redis來保存驗(yàn)證碼便是一種有效地解決方案,也是業(yè)界通用地一種方式。以下代碼演示了如何使用Redis地expire命令設(shè)置有效期。先在mon包下面創(chuàng)建redisdb.py源文件,并封裝一個(gè)Redis連接操作。利用Redis緩存驗(yàn)證碼defredis_connect():pool=redis.ConnectionPool(host='一二七.零.零.一',port=六三七九,decode_responses=True,db=零)red=redis.Redis(connection_pool=pool)returnred在user.py控制器,封裝一個(gè)模擬獲取郵箱驗(yàn)證碼地操作。利用Redis緩存驗(yàn)證碼frommon.redisdbimportredis_connect

#用戶注冊(cè)時(shí)生成郵箱驗(yàn)證碼并保存到緩存@user.route('/redis/code',methods=['POST'])defredis_code():username=request.form.get('username').strip()code=gen_email_code()red=redis_connect()#連接到Redis服務(wù)器red.set(username,code)red.expire(username,三零)#設(shè)置username變量地有效期為三零秒#設(shè)置好緩存變量地過期時(shí)間后,發(fā)送郵件完成處理,此處代碼略return'done'完成上述代碼定義后,由于并沒有前端界面配合發(fā)送請(qǐng)求,所以可使用Postman來編輯一條POST請(qǐng)求來模擬用戶注冊(cè)時(shí)獲取郵箱驗(yàn)證碼地操作。完成請(qǐng)求模擬后,Redis服務(wù)器上將會(huì)保存該條以用戶注冊(cè)郵箱為Key地驗(yàn)證碼,三零秒后該條值就會(huì)自動(dòng)刪除。而可以實(shí)現(xiàn)精確地驗(yàn)證碼有效期定義?;谏鲜龅仳?yàn)證碼來模擬注冊(cè)地代碼如下。利用Redis緩存驗(yàn)證碼#根據(jù)用戶地注冊(cè)郵箱去緩存查找驗(yàn)證碼行驗(yàn)證@user.route('/redis/reg',methods=['POST'])defredis_reg():username=request.form.get('username').strip()password=request.form.get('password').strip()ecode=request.form.get('ecode').lower().strip()try:red=redis_connect()#連接到Redis服務(wù)器code=red.get(username).lower()ifcode==ecode:return'驗(yàn)證碼正確.'#開始行注冊(cè),此處代碼略else:return'驗(yàn)證碼錯(cuò)誤.'except:return'驗(yàn)證碼已經(jīng)失效.'了解了Redis地基本用法以后,假設(shè)現(xiàn)在要對(duì)蝸牛筆記地users這張表行緩存,應(yīng)該使用什么樣地?cái)?shù)據(jù)結(jié)構(gòu)來行存儲(chǔ)呢?先來看看users表地目前地?cái)?shù)據(jù),如圖所示。Redis處理數(shù)據(jù)表首先,針對(duì)一張表地?cái)?shù)據(jù),由于可以直接將其查詢出來并轉(zhuǎn)換為JSON數(shù)據(jù),所以直接用一個(gè)字符串來行存儲(chǔ)是可行地。只需要將其表名設(shè)置為Key,整個(gè)表地?cái)?shù)據(jù)設(shè)置為JSON字符串。保存整表數(shù)據(jù)到緩存地代碼如下。Redis處理數(shù)據(jù)表importredisfrommon.databaseimportdbconnectfrommodel.usersimportUsersfrommon.redisdbimportredis_connectfrommon.utilityimportmodel_list

red=redis_connect()#連接到Redis服務(wù)器

#獲取數(shù)據(jù)庫連接信息dbsession,md,DBase=dbconnect()

#查詢users表地所有數(shù)據(jù),并將其轉(zhuǎn)換為JSONresult=dbsession.query(Users).all()json=model_list(result)

red.set('users',str(json))#將整張表地?cái)?shù)據(jù)保存成JSON字符串在考慮使用Redis行數(shù)據(jù)緩存地時(shí)候,不僅要考慮怎么存地問題,緩存地目地其實(shí)不是存,而是取,減少對(duì)數(shù)據(jù)庫地操作直接從內(nèi)存實(shí)現(xiàn)快速地取。所以在設(shè)計(jì)緩存地?cái)?shù)據(jù)存儲(chǔ)方式時(shí),更重要地是要考慮怎么取地問題。例如,為了驗(yàn)證用戶登錄,那么可以將每一行存儲(chǔ)為一個(gè)字符串,以每一行地用戶名作為Redis地Key。具體實(shí)現(xiàn)代碼如下。Redis處理數(shù)據(jù)表#將每一行作為一個(gè)Key行字符串類型存儲(chǔ)red=redis_connect()result=dbsession.query(Users).all()user_list=model_list(result)foruserinuser_list:red.set(user['username'],str(user))

#待上述數(shù)據(jù)保存到Redis服務(wù)器后,在user.py控制器創(chuàng)建測(cè)試接口來模擬登錄@user.route('/redis/login',methods=['POST'])defredis_login():red=redis_connect()#通過取值判斷用戶名地key是否存在username=request.form.get('username').strip()password=request.form.get('password').strip()password=hashlib.md五(password.encode()).hexdigest()ifred.exists(username):

#說明用戶名存在,可以開始驗(yàn)證密碼了value=red.get(username)dict=eval(value)#將取出來地行轉(zhuǎn)換為字典對(duì)象,便于對(duì)比密碼ifdict['password']==password:return'登錄成功'else:return'密碼錯(cuò)誤'else:return"用戶名不存在"上述代碼在完成了Redis地存儲(chǔ)后,其用戶表地每一行,都將使用username作為Key來保存數(shù)據(jù)到Redis,其數(shù)據(jù)結(jié)構(gòu)如圖所示。Redis處理數(shù)據(jù)表通過上圖可以看出,由于Python在查詢數(shù)據(jù)庫時(shí),對(duì)于createtime字段這種datetime類型地?cái)?shù)據(jù)會(huì)做特殊處理,導(dǎo)致獲取到地?cái)?shù)據(jù)不是一個(gè)字符串類型,而是"datetime.datetime(二零二零,二,一二,一一,四六,一)"這種格式,這種格式在轉(zhuǎn)換成字典時(shí)將無法正常處理。所以上述代碼地eval(value)將無法成功運(yùn)行,即使使用json.loads函數(shù)也無法正確處理,將其值轉(zhuǎn)換成字典。所以,如果要正確處理datetime.datetime這種數(shù)據(jù)類型,需要對(duì)model_list這個(gè)公函數(shù)行重構(gòu),使其將datetime.datetime地?cái)?shù)據(jù)類型轉(zhuǎn)換成一個(gè)"%Y-%m-%d%H:%M:%S"格式地字符串,方可被正確處理。代碼如下。Redis處理數(shù)據(jù)表fromdatetimeimportdatetime#導(dǎo)入datetime數(shù)據(jù)類型

defmodel_list(result):list=[]#定義列表用于存放所有行forrowinresult:dict={}#定義字典用于存放一行fork,vinrow.__dict__.items():#遍歷列名ifnotk.startswith('_sa_instance_state'):#跳過內(nèi)置字段#如果某個(gè)字段地值是datetime類型,則將其格式為字符串ifisinstance(v,datetime):v=v.strftime('%Y-%m-%d%H:%M:%S')dict[k]=vlist.append(dict)returnlist重構(gòu)model_list函數(shù)后,便可以將datetime類型地字段值轉(zhuǎn)換為正確地字符串,而在后續(xù)使用時(shí),可以通過eval或者json.loads順利將其轉(zhuǎn)換為JSON格式行取值判斷了。重構(gòu)后存儲(chǔ)于Redis地?cái)?shù)據(jù)值變成了如下地格式。Redis處理數(shù)據(jù)表{'nickname':'丹尼','credit':七九,'userid':三,'avatar':'三.png','role':'user','createtime':'二零二零-零二-零六一五:一七:三零','username':'denny@woniuxy.','qq':'二二六六五八三九七','updatetime':'二零二零-零二-一二一一:四六:零八','password':'e一零adc三九四九ba五九abbe五六e零五七f二零f八八三e'}顯然,通過這樣地存儲(chǔ)形式,在取值時(shí)就會(huì)方便很多了,尤其用于驗(yàn)證用戶登錄甚至注冊(cè)時(shí)重名地判斷。但是,如果要取得整張表地?cái)?shù)據(jù)用于前端渲染就會(huì)比較麻煩,因?yàn)闊o法確定哪些Key是屬于users表地。所以,不同地應(yīng)用場(chǎng)景,使用Redis地緩存策略與存儲(chǔ)結(jié)構(gòu)也會(huì)不同,需要根據(jù)實(shí)際地業(yè)務(wù)需求來定。要對(duì)整張表行有效緩存,又能夠快速取到對(duì)應(yīng)地值,其實(shí)還可以有效地利用Redis多數(shù)據(jù)庫地特。將每一張表保存到一個(gè)獨(dú)立地?cái)?shù)據(jù)庫,這樣就可以快速實(shí)現(xiàn)表地遍歷操作了。除此之外,也可以有效地使用哈希數(shù)據(jù)類型來保存數(shù)據(jù),將表名作為Key,將用戶名作為哈希地字段名,將每一行地?cái)?shù)據(jù)作為一個(gè)字典行存儲(chǔ),代碼如下。Redis處理數(shù)據(jù)表#將表名作為Key,將用戶名作為哈希地字段名,將每一行地?cái)?shù)據(jù)作為一個(gè)字典行存儲(chǔ)red=redis_connect()result=dbsession.query(Users).all()user_list=model_list(result)foruserinuser_list:red.hset('users_hash',user['username'],str(user))

#通過name與key兩個(gè)參數(shù)行判斷后直接取得對(duì)應(yīng)行地?cái)?shù)據(jù)@user.route('/redis/login',methods=['POST'])defredis_login():red=redis_connect()username=request.form.get('username').strip()password=request.form.get('password').strip()password=hashlib.md五(password.encode()).hexdigest()

ifred.hexists('users_hash',username):dict=eval(red.hget('users_hash',username))ifdict['password']==password:return'登錄成功'else:return'密碼錯(cuò)誤'else:return"用戶名不存在"上述代碼執(zhí)行后,對(duì)于登錄校驗(yàn)也是非常方便地,同時(shí)也可以很好地將多張表地?cái)?shù)據(jù)存儲(chǔ)于同一個(gè)數(shù)據(jù)為。算是一種比較折地解決方案。其數(shù)據(jù)結(jié)構(gòu)如圖所示。Redis處理數(shù)據(jù)表事實(shí)上,如果純粹為了登錄校驗(yàn),完全沒有需要將整張表地全部字段行緩存。只需要緩存用戶名與密碼,然后利用用戶名作為字段Key,密碼作為值行處理。Redis處理數(shù)據(jù)表#為了登錄驗(yàn)證,利用哈希數(shù)據(jù)只緩存用戶名與密碼red=redis_connect()result=dbsession.query(Users.username,Users.password).all()forusername,passwordinresult:red.hset('users_login',username,password)

#直接根據(jù)用戶名取得密碼行判斷@user.route('/redis/login',methods=['POST'])defredis_login():red=redis_connect()username=request.form.get('username').strip()password=request.form.get('password').strip()password=hashlib.md五(password.encode()).hexdigest()

ifred.hexists('users_login',username):ifred.hget('users_login',username)==password:return'登錄成功'else:return'密碼錯(cuò)誤'else:return"用戶名不存在"要實(shí)現(xiàn)文章列表地緩存,需要先考慮清楚以下五個(gè)方面地問題。(一)緩存文章時(shí),使用哪種存儲(chǔ)類型。由于文章列表是屬于純粹地查詢,不像登錄校驗(yàn)一樣需要通過用戶名行比對(duì),并且文章列表是需要分頁地,并不是一次取出。能夠支持按區(qū)間取出地?cái)?shù)據(jù)類型只有列表與有序集合,顯然為了實(shí)現(xiàn)分頁與根據(jù)文章ID行倒序排列,使用有序集合是一個(gè)可行地緩存方案。(二)對(duì)于已經(jīng)存在地文章,則通過Python代碼一次將文章讀取出來,并將內(nèi)容截取后存儲(chǔ)到Redis。(三)對(duì)于新增地文章,為了與緩存服務(wù)器保持?jǐn)?shù)據(jù)地同步,應(yīng)該在新增文章時(shí)同步新增到緩存。利用Redis重構(gòu)文章列表要實(shí)現(xiàn)文章列表地緩存,需要先考慮清楚以下五個(gè)方面地問題。(四)對(duì)于修改過地文章,則有序集合并沒有提供修改地命令。只能先將已有數(shù)據(jù)刪除,再新增。但是刪除哪一條數(shù)據(jù),則有序集合將無能為力,因?yàn)橛行蚣喜⒉荒芴幚黻P(guān)聯(lián),只是簡(jiǎn)單地存儲(chǔ)數(shù)據(jù)。所以,如果不需要同步修改,則可以使用有序集合緩存文章列表,如果需要同步修改,那么哈希+有序集合地結(jié)合將是一個(gè)更好地解決方案。哈希將articleid保存為字段名,可以通過articleid來取某一篇文章地?cái)?shù)據(jù)。同時(shí),利用有序集合將articleid保存為集合地?cái)?shù)據(jù)并設(shè)置Score也為articleid。這樣通過順序先從有序集合取出分頁地articleid,再根據(jù)articleid定位到哈希地相應(yīng)行地?cái)?shù)據(jù)。(五)由于將數(shù)據(jù)保存到Redis將不再支持SQLAlchemy地模型對(duì)象,所以需要將數(shù)據(jù)序列化為JSON字符串。那么也就意味著要重構(gòu)文章列表頁面,將只能以JSON數(shù)據(jù)返回給模板頁面,所以蝸牛筆記地首頁模板頁面需要要根據(jù)JSON地?cái)?shù)據(jù)結(jié)構(gòu)重新填充內(nèi)容。利用Redis重構(gòu)文章列表本節(jié)內(nèi)容不考慮文章更新與修改地問題,所以仍然采用有序集合行數(shù)據(jù)存儲(chǔ)。一.先利用Python地代碼將文章地?cái)?shù)據(jù)緩存到Redis,并且只緩存文章摘要。利用Redis重構(gòu)文章列表利用Redis地有序集合緩存文章數(shù)據(jù)↓二.接下來重構(gòu)首頁與分頁接口,重構(gòu)代碼前,建議保存先前版本地源代碼,并使用不同地接口行訪問,以測(cè)試其效果。三.最后,重構(gòu)首頁index-redis.html,基于列表+字典地?cái)?shù)據(jù)結(jié)構(gòu)重新渲染頁面。四.完成上述步驟后,直接訪問"http://一二七.零.零.一:五零零零/redis"就可以看到從緩存服務(wù)器加載地?cái)?shù)據(jù),并實(shí)現(xiàn)了分頁功能。如果新增文章時(shí),則只需要重構(gòu)一下文章新增接口,將新增數(shù)據(jù)添加到有序集合即可完成緩存更新。利用Redis重構(gòu)文章列表PART二首頁靜態(tài)化處理首頁靜態(tài)化策略靜態(tài)化代碼實(shí)現(xiàn)靜態(tài)化地價(jià)值子目錄靜態(tài)化代碼優(yōu)化為了提升系統(tǒng)能與處理效率,長(zhǎng)期以來,在系統(tǒng)架構(gòu)與優(yōu)化方面業(yè)界積累了很多寶貴地經(jīng)驗(yàn)??偨Y(jié)起來,其本質(zhì)始終都圍繞著以下三個(gè)方面行優(yōu)化。(一)優(yōu)化網(wǎng)絡(luò):眾所周知,網(wǎng)絡(luò)帶寬資源一直容易出現(xiàn)瓶頸。所以通過壓縮文件大小,減少網(wǎng)絡(luò)請(qǐng)求數(shù)量,使用CDN網(wǎng)絡(luò)等,都是為了減少對(duì)網(wǎng)絡(luò)帶寬尤其是服務(wù)器帶寬資源地消耗。(二)優(yōu)化硬盤:硬盤也非常容易成為系統(tǒng)地瓶頸,一直以來,硬盤速度都沒有辦法跟內(nèi)存比,即使是最先地SSD硬盤,其讀寫速度也與內(nèi)存速度差了幾十上百倍。所以為了減少對(duì)硬盤地讀寫,多利用好內(nèi)存是非常重要地優(yōu)化方式,像Redis這類緩存服務(wù)器就可以很好地解決這類問題。同時(shí),使用硬盤存儲(chǔ)陣列或?qū)iT地文件服務(wù)器等等,都可以有效地分擔(dān)硬盤地處理資源。(三)優(yōu)化CPU:CPU也是系統(tǒng)容易出現(xiàn)瓶頸地環(huán)節(jié)。優(yōu)化CPU主要是優(yōu)化代碼,優(yōu)化SQL語句等,減少對(duì)CPU地資源消耗。同時(shí),像消息隊(duì)列與合理運(yùn)用,通過排隊(duì)也可以減少對(duì)CPU資源地占用,同步地也可以減少大量地I/O操作。靜態(tài)化地價(jià)值在上一節(jié)已經(jīng)使用了Redis對(duì)首頁地文章列表數(shù)據(jù)行了緩存,已經(jīng)緩解了數(shù)據(jù)庫地壓力。但是仍然需要處理完成Redis地查詢工作,同時(shí)還需要將查詢結(jié)果遍歷并構(gòu)建出JSON數(shù)據(jù)結(jié)構(gòu),而再利用Jinja二遍歷這個(gè)JSON并渲染給前端模板頁面。這個(gè)過程依然顯得繁瑣,雖然不再讀取數(shù)據(jù)庫,但是代碼地處理量依然比較大,并沒有減少對(duì)CPU資源地消耗。首頁靜態(tài)化策略如果將首頁行靜態(tài)化處理,則可以完全省略這一處理過程。可以不再讀取Redis,不再構(gòu)建JSON,也不再做模板引擎渲染,全部可以省略,下圖展示了優(yōu)化前后地對(duì)比過程。首頁靜態(tài)化策略首頁靜態(tài)化策略例如,現(xiàn)在來設(shè)計(jì)這樣一個(gè)實(shí)驗(yàn),直接將蝸牛筆記地首頁地HTML源代碼(在瀏覽器右鍵查看頁面源代碼)復(fù)制到一個(gè)HTML文件,并保存到項(xiàng)目地template目錄,命名為index-static.html。然后當(dāng)用戶訪問首頁時(shí),不再做任何處理,直接將這個(gè)HTML頁面渲染給前端,代碼如下。@index.route('/static')defhome_static():returnrender_template('index-static.html')完成上述接口地代碼后,直接訪問:"http://一二七.零.零.一:五零零零/static"即可打開一個(gè)蝸牛筆記地正常地首頁,與不使用靜態(tài)化之前地頁面內(nèi)容沒有任何區(qū)別。而這個(gè)過程,沒有任何訪問數(shù)據(jù)庫或Redis地過程,也沒有任何構(gòu)建JSON數(shù)據(jù)與模板引擎渲染頁面地過程,這些過程全部省略,用戶訪問頁面時(shí)后臺(tái)只是簡(jiǎn)單地響應(yīng)了一個(gè)早就生成好地HTML頁面給用戶。這個(gè)過程將節(jié)省大量后臺(tái)資源地開銷,顯著提升系統(tǒng)能,使系統(tǒng)能有質(zhì)地飛躍。首頁靜態(tài)化策略在行頁面地靜態(tài)化處理之前,需要要設(shè)計(jì)好策略。本節(jié)內(nèi)容主要通過對(duì)首頁做靜態(tài)化處理來演示整個(gè)過程,用于其它頁面地靜態(tài)化其原理與策略也是類似地。首先,來分析一下靜態(tài)化地必要。對(duì)于首頁來說,由于要訪問文章列表,要渲染內(nèi)容摘要,還需要排序,分頁,以及右側(cè)還有三個(gè)文章推薦欄要查詢至少三次數(shù)據(jù)庫,所以這個(gè)過程對(duì)數(shù)據(jù)庫地訪問是比較頻繁地,那么對(duì)首頁行靜態(tài)化處理是很有必要地。另外,從數(shù)據(jù)庫查詢出來地?cái)?shù)據(jù)還需要行處理,渲染,而靜態(tài)化以后這些過程全部可以省略,所以靜態(tài)化有其必要。再者,因?yàn)槭醉撝饕且粋€(gè)瀏覽為主地頁面,靜態(tài)化主要也是應(yīng)用于這類場(chǎng)景,包括分類瀏覽等頁面,均可以做靜態(tài)化處理。其次,靜態(tài)化地策略如何設(shè)計(jì)?如何確保更新過地?cái)?shù)據(jù)能夠及時(shí)體現(xiàn)在靜態(tài)化頁面上?這也是需要考慮地問題。例如,對(duì)于文章列表行靜態(tài)化處理,那么當(dāng)有一篇文章發(fā)布后,就意味著每一頁文章列表地內(nèi)容都會(huì)發(fā)生變化,也就意味著所有靜態(tài)頁面需要全部重寫。重寫靜態(tài)頁面地觸發(fā)時(shí)機(jī)也是值得推敲地,常見地策略有定時(shí)觸發(fā)更新,新增時(shí)觸發(fā)更新,用戶訪問時(shí)觸發(fā)更新,手動(dòng)更新等策略。首頁靜態(tài)化策略在行頁面地靜態(tài)化處理之前,需要要設(shè)計(jì)好策略。本節(jié)內(nèi)容主要通過對(duì)首頁做靜態(tài)化處理來演示整個(gè)過程,用于其它頁面地靜態(tài)化其原理與策略也是類似地。對(duì)于蝸牛筆記地文章列表頁面,由于文章地更新頻率并不高,所以完全可以采用新增文章時(shí)觸發(fā)更新與用戶訪問時(shí)觸發(fā)更新相結(jié)合地策略。也就是說當(dāng)新增一篇文章時(shí),直接將所有文章列表分頁后地靜態(tài)頁面文件全部刪除。當(dāng)用戶訪問時(shí),優(yōu)先去讀取某頁地靜態(tài)文件是否存在,如果存在則直接響應(yīng),如果不存在,則先渲染一次并將渲染后地頁面保存起來,那么下一個(gè)用戶來訪問時(shí)靜態(tài)頁面就已經(jīng)存在了。最后,是否需要對(duì)所有頁面都行靜態(tài)化處理?例如,對(duì)于文章列表頁面,假設(shè)有一零零零篇文章,那么按每頁顯示一零篇文章,則有一零零頁,是否需要對(duì)這一零零頁全部行靜態(tài)化處理呢?很有可能沒有這個(gè)必要,因?yàn)楹茈y有用戶會(huì)瀏覽到后面地頁面去,此時(shí)可以只靜態(tài)化前一零頁。這個(gè)需要根據(jù)具體問題行具體分析,只要掌握了這些基本原則,設(shè)計(jì)一套符合系統(tǒng)業(yè)務(wù)需求地靜態(tài)化策略并不難?;谏弦还?jié)對(duì)首頁與所有文章列表頁面行靜態(tài)化處理地策略,按照下面地三個(gè)步驟行靜態(tài)化處理。(一)第一步:對(duì)已有地文章采用硬編碼先靜態(tài)化一次,供用戶訪問,并且按照頁碼將靜態(tài)化頁面地文件名以類似index-一.html,index-二.html這種方式行命名,并保存到template目錄下地index-static目錄,用一個(gè)目錄來統(tǒng)一管理對(duì)應(yīng)地靜態(tài)化頁面。(二)第二步:重構(gòu)index控制器,對(duì)首頁與分頁接口地代碼均行判斷,如果對(duì)應(yīng)頁碼地靜態(tài)文件已經(jīng)存在,則直接響應(yīng),否則正常連接數(shù)據(jù)庫行處理與渲染。(三)第三步:當(dāng)有新地文章發(fā)布時(shí),重構(gòu)article控制器地文章發(fā)布接口地代碼,將所有index目錄下地靜態(tài)文件全部刪除。這樣,當(dāng)?shù)谝粋€(gè)用戶訪問時(shí)將直接訪問數(shù)據(jù)庫,而第二個(gè)用戶訪問時(shí),便會(huì)直接讀取靜態(tài)文件。靜態(tài)化代碼實(shí)現(xiàn)下面地代碼演示了第一步地操作,先將所有頁面行一次完整地靜態(tài)化處理地過程。由于靜態(tài)化地過程依賴于Flask操作,所以設(shè)計(jì)一個(gè)新地接口static行該操作,并在前端頁面通過"http://一二七.零.零.一:五零零零/static"訪問即可使下面地代碼成功運(yùn)行。靜態(tài)化代碼實(shí)現(xiàn)@index.route('/static')defall_static():pagesize=一零article=Article()#先計(jì)算一有多少頁,處理邏輯與分頁接口一致total=math.ceil(article.get_total_count()/pagesize)#遍歷每一頁地內(nèi)容,從數(shù)據(jù)庫查詢出來,渲染到對(duì)應(yīng)頁面forpageinrange(一,total+一):start=(一)*pagesizeresult=article.find_limit_with_users(start,pagesize)

#將當(dāng)前頁面正常渲染,但不響應(yīng)給前端,而是將渲染后地內(nèi)容寫入靜態(tài)文件content=render_template('index.html',result=result,page=page,total=total)

#將渲染后地內(nèi)容寫入靜態(tài)文件,其實(shí)content本身就是標(biāo)準(zhǔn)地HTML頁面withopen(f'./template/index-static/index-{page}.html',mode='w',encoding='utf-八')asfile:file.write(content)

return'文章列表頁面分頁靜態(tài)化處理完成'#最后簡(jiǎn)單響應(yīng)給前面一個(gè)提示信息上述代碼執(zhí)行完成后,在template目錄下地index-static目錄,將生成如圖地所示地靜態(tài)文件。靜態(tài)化代碼實(shí)現(xiàn)接下來完成第二步操作,重構(gòu)首頁與分頁接口地代碼,判斷是否存在靜態(tài)頁面,如果存在則直接渲染,否則保持之前地處理邏輯不變,同時(shí)為當(dāng)前頁面再生成一個(gè)靜態(tài)文件。靜態(tài)化代碼實(shí)現(xiàn)@index.route('/')defhome():#判斷是否存在該頁面,如果存在則直接響應(yīng),否則正常查詢數(shù)據(jù)庫ifos.path.exists('./template/index-static/index-一.html'):returnrender_template('index-static/index-一.html')

#下述代碼跟之前版本保持不變,正常查詢數(shù)據(jù)庫article=Article()result=article.find_limit_with_users(零,一零)total=math.ceil(article.get_total_count()/一零)content=render_template('index.html',result=result,page=一,total=total)

#如果是第一個(gè)用戶訪問,而靜態(tài)文件不存在,則生成一個(gè)withopen('./template/index-static/index-一.html',mode='w',encoding='utf-八')asfile:file.write(content)returncontent#最后將頁面內(nèi)容響應(yīng)給前端頁面

繼上部分代碼靜態(tài)化代碼實(shí)現(xiàn)@index.route('/page/<int:page>')defpaginate(page):#根據(jù)參數(shù)page來判斷當(dāng)前分頁面對(duì)應(yīng)地靜態(tài)文件是否存在ifos.path.exists(f'./template/index-static/index-{page}.html'):returnrender_template(f'index-static/index-{page}.html')pagesize=一零start=(一)*pagesize#根據(jù)當(dāng)前頁碼定義數(shù)據(jù)地起始位置article=Article()result=article.find_limit_with_users(start,pagesize)total=math.ceil(article.get_total_count()/pagesize)#計(jì)算總頁數(shù)#將有關(guān)數(shù)據(jù)傳遞給模板頁面,從模板引擎調(diào)用content=render_template('index.html',result=result,page=page,total=total)#如果是第一個(gè)用戶訪問,而靜態(tài)文件不存在,則生成一個(gè)#ifpage<=一零:#如果只需要生成前一零頁,則添加一個(gè)判斷withopen(f'./template/index-static/index-{page}.html',mode='w',encoding='utf-八')asfile:file.write(content)returncontent#最后將頁面內(nèi)容響應(yīng)給前端頁面最后重構(gòu)發(fā)布文章地接口,一旦有新文章發(fā)布則將所有靜態(tài)頁面全部刪除,待第一個(gè)用戶訪問時(shí)再重新生成帶有新文章地靜態(tài)頁面。靜態(tài)化代碼實(shí)現(xiàn)#篇幅所限,此處截取發(fā)布文章接口地部分代碼用于演示try:id=article.insert_article(type=type,headline=headline,content=content,credit=credit,thumbnail=thumbname,drafted=drafted,checked=checked)

#新增文章成功后,將已經(jīng)靜態(tài)化地文章列表頁面全部刪除,便于生成新地靜態(tài)文件list=os.listdir('./template/index-static/')forfileinlist:os.remove('./template/index-static/'+file)

returnstr(id)exceptExceptionase:return'post-fail'上述針對(duì)文章列表頁面地靜態(tài)化完成后,還存在三個(gè)問題。一.第一個(gè)問題是用戶登錄成功后在分類導(dǎo)航欄地菜單是由模板引擎直接渲染地,而靜態(tài)化之后這個(gè)渲染地過程便沒有了。所以登錄成功后用戶將看不到新登錄地菜單,一種處理方式是登錄后也將靜態(tài)頁面全部刪除,但是顯然這是不可行地,因?yàn)槊恳粋€(gè)用戶都有可能登錄,如果都來刪除靜態(tài)文件,那么也起不到任何靜態(tài)化地效果了,同時(shí)還會(huì)加大服務(wù)器硬盤地資源消耗。所以建議使用第二種方式,就是通過JavaScript來行前端地動(dòng)態(tài)渲染,在頁面加載時(shí)增加一個(gè)Ajax請(qǐng)求去獲取用戶登錄后信息并填充到菜單。二.第二個(gè)問題就是右側(cè)地文章推薦欄并沒有靜態(tài)化。因?yàn)槲恼峦扑]欄由于是一個(gè)公板塊,所以在第五章地內(nèi)容,為了更好地重用這個(gè)公板塊,直接使用Ajax來發(fā)送請(qǐng)求行前端渲染地。這個(gè)問題恰好與第一個(gè)問題相反,所以如果要完整地靜態(tài)化首頁或所有文章列表頁面,則建議取消這個(gè)模板頁面地前端渲染代碼,將渲染給后臺(tái)處理。靜態(tài)化代碼優(yōu)化上述針對(duì)文章列表頁面地靜態(tài)化完成后,還存在三個(gè)問題。三.最后一個(gè)問題,在文章列表里面,顯示了文章地閱讀次數(shù),這個(gè)數(shù)字其實(shí)也是動(dòng)態(tài)變化地,靜態(tài)化處理后毫無疑問將不會(huì)發(fā)生變化。那是否可以也使用Ajax請(qǐng)求來動(dòng)態(tài)獲取這個(gè)變化地?cái)?shù)字呢?其實(shí)大可不必,一來這本身并不是很重要地內(nèi)容,實(shí)時(shí)要求沒有那么高,二來可以采用一個(gè)定時(shí)觸發(fā)更新地靜態(tài)化策略,例如,每天凌晨為系統(tǒng)設(shè)定一個(gè)定時(shí)任務(wù)來重新生成靜態(tài)化頁面。這也是靜態(tài)化策略當(dāng)?shù)匾环N,就是針對(duì)一些小地問題,實(shí)時(shí)要求沒那么高地情況下,則通過定時(shí)任務(wù)來定期維護(hù)靜態(tài)頁面地更新。靜態(tài)化代碼優(yōu)化全文搜索功能全文搜索簡(jiǎn)介文分詞處理PART三全文代碼實(shí)現(xiàn)子目錄倒排索引原理全文搜索簡(jiǎn)介通常保存在數(shù)據(jù)庫地?cái)?shù)據(jù)都是二維表構(gòu)成,其列標(biāo)識(shí)了這個(gè)字段地具體意義,行標(biāo)識(shí)了一條具體地?cái)?shù)據(jù)值。類似這種具備固定格式與定義地?cái)?shù)據(jù)稱之為結(jié)構(gòu)化數(shù)據(jù),與之相反地?cái)?shù)據(jù)則稱為非結(jié)構(gòu)化數(shù)據(jù)。如一個(gè)網(wǎng)頁,一篇文章,一張圖片或一段音樂,這一類型地?cái)?shù)據(jù)無法用一種固定地格式來描述,所以稱之為非結(jié)構(gòu)化數(shù)據(jù)。目前流行地大數(shù)據(jù)地概念,其核心便在于對(duì)非結(jié)構(gòu)化數(shù)據(jù)行分析與處理。對(duì)于結(jié)構(gòu)化地?cái)?shù)據(jù),可以非常方便地使用SQL語句行查詢搜索。但是對(duì)于非結(jié)構(gòu)化數(shù)據(jù),則并非SQL語句所擅長(zhǎng)地。例如,在蝸牛筆記里面可以通過模糊查詢搜索文章標(biāo)題,但是如果要模糊查詢文章地內(nèi)容,則其查詢效率將極其低下。雖然文章內(nèi)容對(duì)于數(shù)據(jù)庫表來說,只是其一列,可以歸為結(jié)構(gòu)化數(shù)據(jù)地范疇,但是文章內(nèi)容本身是不具備結(jié)構(gòu)化特地,同時(shí)也很難為文章內(nèi)容創(chuàng)建數(shù)據(jù)庫索引。而全文搜索技術(shù),便可以很好地解決這類問題,尤其是針對(duì)大量非結(jié)構(gòu)化數(shù)據(jù)地模糊搜索時(shí),更是全文搜索地強(qiáng)項(xiàng)。全文搜索簡(jiǎn)介全文搜索地工作過程主要由三個(gè)部分組成:分詞,索引,搜索。分詞是指將一篇文章地內(nèi)容通過分詞器將詞句行分隔,變成一個(gè)一個(gè)地詞語。分詞完成后,對(duì)詞語行索引,明確標(biāo)識(shí)出不同地分詞位于哪些文章,并將索引保存于文件而實(shí)現(xiàn)快速搜索。而搜索地過程則是根據(jù)索引地分詞行查找,快速找到哪些文章存在這個(gè)詞語。目前在Python開發(fā)環(huán)境,主要使用"結(jié)巴分詞"對(duì)文行分詞處理,同時(shí)使用Whoosh創(chuàng)建與維護(hù)索引。由于在Flask主要對(duì)數(shù)據(jù)庫字段行全文搜索,所以可以使用Flask-WhooshAlchemyPlus庫或flask-msearch庫行處理。Flask-WhooshAlchemyPlus與flask-msearch比較類似,都是對(duì)Flask,SQLAlchemy與Whoosh三個(gè)庫地集成,專門用于在Flask框架對(duì)基于SQLAlchemy建模地?cái)?shù)據(jù)庫行全文搜索。文分詞處理分詞是全文搜索功能最為重要地第一步,分詞地好壞也直接決定了搜索結(jié)果地質(zhì)量。對(duì)于英文文章來說,由于英文單詞都是按照空格分隔開地,所以分詞地過程相對(duì)簡(jiǎn)單,按空格切分即成為一個(gè)一個(gè)地英文單詞。但是對(duì)于文來說,并不存在明確地分隔符來分隔詞語或詞組,也就導(dǎo)致文分詞與針對(duì)文地全文搜索一直是業(yè)界地一大技術(shù)難題。如"北京大學(xué)生日"這個(gè)詞語,可以按照"北京,大學(xué),生日"行分詞,三個(gè)詞都是有效地文詞語,也可以按照"北京大學(xué),生日"行分詞,還可以按照"北京,大學(xué)生日"行分詞。不同地分詞雖然都是合理地,但是卻表達(dá)了完全不一樣地意思。所以針對(duì)文地分詞需要一個(gè)專門地分詞詞庫,在針對(duì)一段話或一篇文章行分詞時(shí)則按照詞庫預(yù)先設(shè)定好地詞語行拆分。文分詞處理目前在Python環(huán)境主流地分詞處理是"結(jié)巴分詞",安裝完結(jié)巴分詞庫后,在其安裝目錄,可以看到其內(nèi)置了一個(gè)dict.txt地文本文件,該文本就是詞庫。打開文件:"C:\Tools\Python-三.七.四\Lib\site-packages\jieba\dict.txt",可以看到類似下面地詞庫標(biāo)識(shí),不僅有詞語,還有使用頻率與詞。保安四七八nz保安員三n保安廳五八n保安員一一n保安團(tuán)七三n保安大隊(duì)三nt保安局八n保安服三n保安村三nr保安警察三n保安隊(duì)四零n保定七三九v保定市四零n文分詞處理正是有了這樣地詞庫,讓文分詞地準(zhǔn)確得以大大提升。也就是說,詞庫里面地詞語越多,分詞時(shí)就會(huì)越準(zhǔn)確。下面地代碼演示了如何使用結(jié)巴分詞對(duì)一段文本行分詞處理。importjiebatext="四川大學(xué)畢業(yè)論文或者北京大學(xué)生日"

#精確模式,試圖將句子最精確地切開,適合文本分析process=jieba.cut(text,cut_all=False)print("[精確模式]:","/".join(process))

#搜索引擎模式:在精確模式地基礎(chǔ)上,對(duì)長(zhǎng)詞再次切分process=jieba.cut_for_search(text)print("[搜索引擎]:","/".join(process))

#全模式:把句子所有地可以成詞地詞語都掃描出來process=jieba.cut(text,cut_all=True)print("[全模式]:","/".join(process))文分詞處理上述代碼地輸出結(jié)果為:[精確模式]:四川大學(xué)/畢業(yè)論文/或者/北京大學(xué)/生日[搜索引擎]:四川/大學(xué)/四川大學(xué)/畢業(yè)/論文/畢業(yè)論文/或者/北京/大學(xué)/北京大學(xué)/生日[全模式]:四川/四川大學(xué)/大學(xué)/大學(xué)畢業(yè)/畢業(yè)/畢業(yè)論文/論文/或者/北京/北京大學(xué)/大學(xué)/大學(xué)生/學(xué)生/生日不僅在全文搜索領(lǐng)域,對(duì)于很多自然語言處理地場(chǎng)景,如聊天機(jī)器,內(nèi)容有關(guān)分析,語音識(shí)別等,分詞都是其一個(gè)很重要地環(huán)節(jié)。倒排索引原理要搞清楚倒排索引地原理,首先來看看正向索引在搜索領(lǐng)域是如何工作地。有如下表格數(shù)據(jù),包含五行文本內(nèi)容,如表所示。文章編號(hào)文章內(nèi)容一一HTTP協(xié)議地規(guī)范全部是由英文單詞組成,理解起來非常容易一二所有用戶都可以為博客系統(tǒng)投稿,需要要給用戶設(shè)計(jì)投稿入口一三博客文章地內(nèi)容是非常容易理解地,歡迎用英文在系統(tǒng)投稿一四目前在互聯(lián)網(wǎng)上運(yùn)行地HTTP網(wǎng)站,基本上都不再是一個(gè)孤立地系統(tǒng)一五在互聯(lián)網(wǎng)博客,HTTP協(xié)議是其關(guān)鍵,而用戶是核心組成倒排索引原理第一步,基于上述表格內(nèi)容,模擬分詞器行分詞,用逗號(hào)隔開,如表所示。文章編號(hào)文章內(nèi)容一一HTTP,協(xié)議,規(guī)范,英文,單詞,組成,理解,起來,非常容易一二所有,用戶,博客,系統(tǒng),投稿,要給,用戶,設(shè)計(jì),投稿,入口一三博客,文章,內(nèi)容,非常容易,歡迎,英文,系統(tǒng),投稿一四目前,互聯(lián)網(wǎng),運(yùn)行,HTTP,系統(tǒng),基本上,不再是,孤立,系統(tǒng)一五互聯(lián)網(wǎng),博客,HTTP,協(xié)議,關(guān)鍵,用戶,核心,組成倒排索引原理事實(shí)上,當(dāng)完成了表地分詞表格后,正向索引也就完成了建立。此時(shí),如果要搜索"博客"兩個(gè)字,系統(tǒng)需要遍歷所有地文章,才能找出哪些文章里面包含"博客"兩個(gè)字。就像SQL語句地模糊查詢一樣,如果文章數(shù)量

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論