主要邏輯:
1, 決定一個包含大小寫字母、資料的字串LS,長度為L = 26+26+10 = 62
2, 初始化L**N個整數,並作為一個序列push到redis裡
3, 當需要轉換一個長URL時,先從以上的序列中隨機pop出一個整數I
4, 對整數I取模(除數為L),餘數對應到LS的一個字母,取完模後再除以L取整,當結果等於0時停止除模,否則結果繼續取模。
5, 將所有餘數對應的字母按順序排列得到一個簡短的字符串SS
6, 將長URL的md5哈希值作為KEY,將字符串SS作為VALUE,寫入redis
7, 將字串SS作為KEY, 將長URL作為VALUE,寫入redis
8, 將前綴(短url域名)加上字符串SS,作為短URL結果返回
9, 當用戶使用短url訪問時,將短URL中的字串SS取出,並作為KEY從redis中取出長URL,跳轉長URL
注意:
當redis中序列數字快使用完時,要及時增加(可以寫個腳本隨時監控,數量少於10%時就自動增加數量),切忌不能存已經用過的數字
#encoding=utf-8 import string import redis import hashlib LETTERS = string.digits + string.ascii_letters LETTERS_NUM = len(LETTERS) COUNTER_KEY = 'url:counter' def init(rd,num): for i in xrange(LETTERS_NUM * num): rd.sadd('url:id:set',i) #通过urlid取得短url对应的字符串 def get_url(urlid): result = [] q = urlid/LETTERS_NUM r = urlid%LETTERS_NUM result.append(LETTERS[r]) while q: r = q%LETTERS_NUM q = q/LETTERS_NUM result = [LETTERS[r]] + result return ''.join(result) #得到短url字符串 def parse_url(rd, longurl): ret = longurl if (longurl.startswith("http://") or longurl.startswith("https://")) and len(longurl)>7: m = hashlib.md5() m.update(longurl) urlkey = m.digest() old_param = rd.get(urlkey) if old_param: ret = old_param else: urlid = int(rd.spop('url:id:set')) param = get_url(urlid) rd.incr(COUNTER_KEY, 1) rd.set(param,longurl) rd.set(urlkey,param) ret = param print "short url:",ret return ret if __name__ == "__main__": url = "http://www.google.com/" rd = redis.Redis('127.0.0.1',6379,db=0) init(rd,3) parse_url(rd,url)