python字典实现关键字检索_如何实现搜索框的关键词提示功能
我們都使用過主流的搜索引擎,谷歌、 bing,當(dāng)然還有搜狗、百度之類。當(dāng)你搜索某一關(guān)鍵詞時,它會貼心在下拉框補(bǔ)全一些熱門關(guān)鍵詞,像下圖這樣:
搜索關(guān)鍵詞提示
你點擊某一關(guān)鍵詞,頁面就直接跳轉(zhuǎn)到結(jié)果頁面,這種顯示搜索關(guān)鍵詞提示功能,一定程度上節(jié)省用戶的搜索時間。
能節(jié)省時間的東西就有價值,值得我們學(xué)習(xí)和使用。
但是,在公司內(nèi)部的很多系統(tǒng)中,搜索框中都沒有這個功能。如果你能實現(xiàn)這個功能,那么你的用戶在使用時肯定會眼前一亮,頓生好感,領(lǐng)導(dǎo)看到后也會給你點贊。
這個功能實現(xiàn)非常簡單,前端每輸入一個字符,都去后端查詢前輟相同的關(guān)鍵詞返回到下拉列表中即可。前端的實現(xiàn)網(wǎng)上一搜一大堆,比如搜索關(guān)鍵字「搜索框自動補(bǔ)全」就有很多結(jié)果,這里就不說了。這里主要說下后端如何實現(xiàn)。
如果關(guān)鍵詞數(shù)量并不大,我們可以使用最簡單的字符串匹配算法,如 BF 算法,就是遍歷所有關(guān)鍵詞,找出前輟和輸入的字符串匹配的并返回給前端即可,Python 語言還提供了字符串的 startswith 這種方法,實現(xiàn)起來就更簡單了,簡單就意味著不容易出錯,沒有 bug,在關(guān)鍵詞少的情況下,可以優(yōu)先選擇這種方法。
如果關(guān)鍵詞量較大,就需要考慮性能問題了,前輟樹( Trie 樹)就是高效解決這種問題的數(shù)據(jù)結(jié)構(gòu)。先看一下前輟樹的圖:
trie樹
這棵前輟樹根節(jié)點不存放數(shù)據(jù),其他節(jié)點保存了 hello,her,hi,how,see,so 等關(guān)鍵詞信息,如果查 he 前輟的單詞可以很快返回 hello,her。
這種樹的子節(jié)點數(shù)據(jù)并不固定,一般的算法教程在實現(xiàn)時都通過固定每個節(jié)點的指針數(shù)量來降低實現(xiàn)難度,比如使用一個下標(biāo)與字符一一映射的數(shù)組灰存儲子節(jié)點的指針,如下圖所示:
一種實現(xiàn)方式
這種結(jié)構(gòu)效率非常高,但是比較浪費空間,如果關(guān)鍵詞有中文或者標(biāo)點,更是無法復(fù)用。
好在 Python 語言有字典這種高效的數(shù)據(jù)結(jié)構(gòu),實現(xiàn)起來易如反掌:鍵可以作為父節(jié)點,值作為子節(jié)點,值又是一個字典,包含所有的子節(jié)點信息,這種字典里又有字典這種嵌套的方式實現(xiàn)的前輟樹也叫字典樹。先直觀的感受下:
{'中': {-1: True, '國': {-1: True, '人': {-1: True}}, '華': {'人': {'民': {'共': {'和': {'國': {-1: True}}}}}}}}
這里 -1 是 True 表示到這里已經(jīng)是一個完整的候選詞了,上述字典樹代表以下關(guān)鍵詞:
中
中國
中國人
中華人民共和國
Trie 樹的 Python 實現(xiàn):
前輟樹(Trie 樹)主要有三個操作,第一個是就是一個將關(guān)鍵詞插入到 Trie 樹,第二個是在 Trie 樹中查詢一個關(guān)鍵詞,第三個是返回 Trie 樹中給定前輟的所有關(guān)鍵詞。實現(xiàn)起來并不難,下面是我的一種實現(xiàn)方法:
# encoding = utf-8
class Trie(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.root = {}
self.end = -1
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: void
"""
curNode = self.root
for c in word:
if not c in curNode:
curNode[c] = {}
curNode = curNode[c]
curNode[self.end] = True
def search(self, word):
"""
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
curNode = self.root
for c in word:
if not c in curNode:
return False
curNode = curNode[c]
# Doesn't end here
if not self.end in curNode:
return False
return True
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
:type prefix: str
:rtype: bool
"""
curNode = self.root
for c in prefix:
if not c in curNode:
return False
curNode = curNode[c]
return True
def get_start(self,prefix):
'''
給出一個前輟,打印出所有匹配的字符串
:param prefix:
:return:
'''
def get_key(pre,pre_node):
result = []
if pre_node.get(self.end):
result.append(pre)
for key in pre_node.keys():
if key != self.end:
result.extend(get_key(pre+key,pre_node.get(key)))
return result
if not self.startsWith(prefix):
return []
else:
node = self.root
for p in prefix:
node = node.get(p)
else:
return get_key(prefix,node)
if __name__ == "__main__":
trie = Trie()
trie.insert("Python")
trie.insert("Python 算法")
trie.insert("Python web")
trie.insert("Python web 開發(fā)")
trie.insert("Python web 開發(fā) 視頻教程")
trie.insert("Python 算法 源碼")
trie.insert("Perl 算法 源碼")
print(trie.search("Perl"))
print(trie.search("Perl 算法 源碼"))
print((trie.get_start('P')))
print((trie.get_start('Python web')))
print((trie.get_start('Python 算')))
print((trie.get_start('P')))
print((trie.get_start('Python web')))
print((trie.get_start('Python 算')))
代碼運行結(jié)果如下:
False
True
['Python', 'Python 算法', 'Python 算法 源碼', 'Python web', 'Python web 開發(fā)', 'Python web 開發(fā) 視頻教程', 'Perl 算法 源碼']
['Python web', 'Python web 開發(fā)', 'Python web 開發(fā) 視頻教程']
['Python 算法', 'Python 算法 源碼']
Trie 的時間復(fù)雜度
如果要在一組關(guān)鍵詞中,頻繁地查詢某些關(guān)鍵詞,用 Trie 樹會非常高效。構(gòu)建 Trie 樹的過程,需要掃描所有的關(guān)鍵詞,時間復(fù)雜度是 O(n)(n 表示所有關(guān)鍵詞的長度和)。但是一旦構(gòu)建成功之后,后續(xù)的查詢操作會非常高效。
每次查詢時,如果要查詢的關(guān)鍵詞長度是 k,那我們只需要最多比對 k 個節(jié)點,就能完成查詢操作。跟原本那組關(guān)鍵詞的長度和個數(shù)沒有任何關(guān)系。所以說,構(gòu)建好 Trie 樹后,在其中查找關(guān)鍵詞的時間復(fù)雜度是 O(k),k 表示要查找的關(guān)鍵詞的長度。
不想造輪子,學(xué)習(xí)下 marisa-trie
自己造輪子還要思考,編碼,驗證,但這是學(xué)習(xí)提升的最佳方式。如果急于應(yīng)用沒有時間造輪子,至少要學(xué)會如何使用輪子,下面的前輟樹的輪子是一個日本人寫的,大家可以學(xué)習(xí)應(yīng)用下。
寫在最后
上述只實現(xiàn)了搜索框智能提示的一小步,實際使用中,你可能還會遇到以下問題:
1、如果候選詞過多,應(yīng)該如何選擇性的顯示哪些關(guān)鍵詞呢?
2、如果用戶輸入錯誤,如何仍按正確的拼寫來顯示候選關(guān)鍵詞呢?
第一個問題比如好解決,我們可以按搜索的頻度或關(guān)鍵詞的搜索結(jié)果數(shù)來為每個關(guān)鍵詞自動生成一個權(quán)重數(shù),按權(quán)重從大到小選擇性的顯示前 n 條即可。
第二個問題涉及動態(tài)規(guī)劃,大家可以先思考,如果有時間,會再寫一篇文章。
其實 Trie 樹在自動補(bǔ)全的需求上都可以大顯身手,如輸入法自動補(bǔ)全功能、IDE 代碼編輯器自動補(bǔ)全功能、瀏覽器網(wǎng)址輸入的自動補(bǔ)全功能等。
(完)
歡迎訂閱微信公眾號 somenzz,和你一起學(xué)習(xí) Python。
總結(jié)
以上是生活随笔為你收集整理的python字典实现关键字检索_如何实现搜索框的关键词提示功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 12306订票候补是个坑_加30元就能抢
- 下一篇: python生成词云很慢吗_词云制作没那