日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
使用倒排索引極速提高字符串搜索效率

 在Python中,如果要判斷一個字符串是否在另一個字符串里面,我們可以使用in關(guān)鍵字,例如:

 
 
 
 
  1. >>> a = '你說我是買蘋果電腦,還是買windows電腦呢?'
  2. >>> if '蘋果' in a:
  3. ...  print('蘋果這個詞在a字符串里面')
  4. ...
  5. 蘋果這個詞在a字符串里面

如果有多個句子和多個關(guān)鍵字,那么可以使用for循環(huán)來實(shí)現(xiàn):

 
 
 
 
  1. sentences = ['你說我是買蘋果電腦,還是買windows電腦呢?', 
  2.              '人生苦短我用Python', 
  3.              '你TM一天到晚只知道得瑟',
  4.              '不不不,我不是說你,我是說在座的各位都是垃圾。'
  5.              '我cnm你個大sb'
  6.             ]
  7. keywords = ['垃圾', 'cnm', 'sb', 'TM']
  8. for sentence in sentences:
  9.     for keyword in keywords:
  10.         if keyword in sentence:
  11.             print(f'句子: 【{sentence}】包含臟話:【{keyword}】')

運(yùn)行效果如下圖所示:

現(xiàn)在如果有100000000個句子,有1000個關(guān)鍵字,那么你需要對比1000億次才能全部查詢完成。這個時間代價太大了,如果Python一秒鐘能運(yùn)行500萬次查詢(實(shí)際上沒有這么快),那么1000億次查詢需要20000秒,接近6小時。而且,由于in關(guān)鍵字的時間復(fù)雜度為O(n),如果有大量長句子,查詢時間會更長。

例如,我們要從下面的句子里面尋找cnm。

 
 
 
 
  1. sentences = ['你說我是買蘋果電腦,還是買windows電腦呢?', 
  2.              '人生苦短我用Python', 
  3.              '你TM一天到晚只知道得瑟',
  4.              '不不不,我不是說你,我是說在座的各位都是垃圾。',
  5.              '我cnm你個大sb',
  6.              '各位同學(xué),Good Morning!',
  7.              '網(wǎng)絡(luò)這個單詞,它的英文為Network',
  8.              '我不想聽到有人說cnm!'
  9.             ]

如果使用常規(guī)方法,那么我們的做法是:

  1. cnm在你說我是買蘋果電腦,還是買windows電腦呢?中嗎?不在!
  2. cnm在人生苦短我用Python嗎?不在!
  3. ……
  4. ……
  5. cnm在我cnm你個大sb嗎?在!
  6. cnm在各位同學(xué),Good Morning!嗎?不在!
  7. CMN在網(wǎng)絡(luò)這個單詞,它的英文為Network嗎?不在!
  8. cnm在我不想聽到有人說cnm!嗎?在!

于是就知道了,cnm在sentences列表下標(biāo)為4和7的這兩個句子中。

下面,我們換一個看起來更笨的辦法:

要找到cnm在哪幾句里面,可以變成:尋找C、N、M這三個字母在哪幾句里面。然后,再找到同時有這三個字母的句子:

  1. C在4, 7句
  2. N在4,6,7句
  3. M在2, 4,5,7句

所以,{4, 7} 與 {4, 6, 7} 與 {4, 5, 7}做交集,得到{4, 7}說明cnm這個詞很有可能是在第4句和第7句。

為什么說很可能呢?因?yàn)榧偃缭偬砑右痪湓挘航裉煳覀儗W(xué)習(xí)三個單詞:Cat, Network, Morning。這一句也會被認(rèn)為包含cnm這個詞,但實(shí)際上它只是同時包含了C、N、M三個字母而已。

接下來,有人會問了:原來直接查詢cnm的時候,只需要查詢8次就可以了?,F(xiàn)在你分別查詢C N M要查詢24次。你是修復(fù)了查詢時間太短的bug嗎?

回答這個問題之前,我們再來看另一個問題。

Python里面,當(dāng)我要判斷字母C是不是在句子我不想聽到有人說cnm!里面時,Python是如何工作的?

實(shí)際上,它的工作原理可以寫成:

 
 
 
 
  1. sentence = '我不想聽到有人說cnm!'
  2. for char in sentence:
  3.     if char == 'C':
  4.         print('C在這個字符串中')
  5.         break

如果要判斷C、N、M是不是都在這個字符串我不想聽到有人說cnm!中,同一個字符串會被遍歷3次。有沒有辦法減少這種看起來多余的遍歷操作呢?

如果我們把我不想聽到有人說cnm!這個句子轉(zhuǎn)成字典會怎么樣:

 
 
 
 
  1. sentence = '我不想聽到有人說cnm!'
  2. sentence_dict = {char: 1 for char in sentence}
  3. for letter in 'cnm':
  4.     if letter in sentence_dict:
  5.         print(f'字母{letter}在句子中!')

這樣一來,只需要在生成字典的時候遍歷句子一次,減少了2次冗余遍歷。并且,判斷一個元素是否在字典里面,時間復(fù)雜度為O(1),速度非??臁?/p>

我不想聽到有人說cnm!生成的字典為{'我': 1, '不': 1, '想': 1, '聽': 1, '到': 1, '有': 1, '人': 1, '說': 1, 'C': 1, 'N': 1, 'M': 1, '!': 1}。那么如果要把列表里面的所有句子都這樣處理,又怎么存放呢?此時,字典的Key就是每一個字符,而Value可以是每一句話在原來列表中的索引:

 
 
 
 
  1. sentences = ['你說我是買蘋果電腦,還是買windows電腦呢?', 
  2.              '人生苦短我用Python', 
  3.              '你TM一天到晚只知道得瑟',
  4.              '不不不,我不是說你,我是說在座的各位都是垃圾。',
  5.              '我cnm你個大sb',
  6.              '各位同學(xué),Good Morning!',
  7.              '網(wǎng)絡(luò)這個單詞,它的英文為Network',
  8.              '我不想聽到有人說cnm!']
  9. index_dict = {}
  10. for index, line in enumerate(sentences):
  11.     print(index, line)
  12.     for char in line:
  13.         if not char.strip():
  14.             continue
  15.         if char in index_dict:
  16.             index_dict[char].add(index)
  17.         else:
  18.             index_dict[char] = {index}

生成的字典為:

 
 
 
 
  1. {'B': {4},
  2.  'C': {4, 7},
  3.  'G': {5},
  4.  'M': {2, 4, 5, 7},
  5.  'N': {4, 6, 7},
  6.  'P': {1},
  7.  'S': {4},
  8.  'T': {2},
  9.  'd': {0, 5},
  10.  'e': {6},
  11.  'g': {5},
  12.  'h': {1},
  13.  'i': {0, 5},
  14.  'k': {6},
  15.  'n': {0, 1, 5},
  16.  'o': {0, 1, 5, 6},
  17.  'r': {5, 6},
  18.  's': {0},
  19.  't': {1, 6},
  20.  'w': {0, 6},
  21.  'y': {1},
  22.  '。': {3},
  23.  '一': {2},
  24.  '不': {3, 7},
  25.  '個': {4, 6},
  26.  '為': {6},
  27.  '買': {0},
  28.  '人': {1, 7},
  29.  '位': {3, 5},
  30.  '你': {0, 2, 3, 4},
  31.  '到': {2, 7},
  32.  '單': {6},
  33.  '只': {2},
  34.  '各': {3, 5},
  35.  '同': {5},
  36.  '聽': {7},
  37.  '呢': {0},
  38.  '在': {3},
  39.  '圾': {3},
  40.  '垃': {3},
  41.  '大': {4},
  42.  '天': {2},
  43.  '學(xué)': {5},
  44.  '它': {6},
  45.  '座': {3},
  46.  '得': {2},
  47.  '想': {7},
  48.  '我': {0, 1, 3, 4, 7},
  49.  '文': {6},
  50.  '是': {0, 3},
  51.  '晚': {2},
  52.  '有': {7},
  53.  '果': {0},
  54.  '瑟': {2},
  55.  '生': {1},
  56.  '用': {1},
  57.  '電': {0},
  58.  '的': {3, 6},
  59.  '知': {2},
  60.  '短': {1},
  61.  '絡(luò)': {6},
  62.  '網(wǎng)': {6},
  63.  '腦': {0},
  64.  '苦': {1},
  65.  '英': {6},
  66.  '蘋': {0},
  67.  '詞': {6},
  68.  '說': {0, 3, 7},
  69.  '還': {0},
  70.  '這': {6},
  71.  '道': {2},
  72.  '都': {3},
  73.  '!': {5, 7},
  74.  ',': {0, 3, 5, 6},
  75.  '?': {0}}

生成的字典這么長,看起來非??膳?。但是別慌,畢竟不是你人肉尋找。對Python來說,字典里面無論有多少個Key,它的查詢時間都是一樣的。

現(xiàn)在,我們要尋找C、N、M,于是代碼可以寫為:

 
 
 
 
  1. index_list = []
  2. for letter in 'cnm':
  3.     index_list.append(index_dict.get(letter, {}))
  4. common_index = set.intersection(*index_list)  # 對包含各個字母的索引做交集,得到同時包含3個字母的句子
  5. print(f'這幾個句子里面同時含有`C`、`N`、`M`:{common_index}')
  6. for index in common_index:
  7.     print(sentences[index])

運(yùn)行結(jié)果如下:

所以,對于一組需要被查詢的關(guān)鍵字,也可以這樣搜索:

 
 
 
 
  1. keywords = ['垃圾', 'cnm', 'sb', 'TM']
  2. for word in keywords:
  3.     index_list = []
  4.     for letter in word:
  5.         index_list.append(index_dict.get(letter, {}))
  6.     common_index = set.intersection(*index_list)
  7.     print(f'>>這幾個句子里面同時含有:{word}')
  8.     for index in common_index:
  9.         print(sentences[index])

運(yùn)行效果如下圖所示:

看完這篇文章以后,你已經(jīng)學(xué)會了倒排索引(Inverted-index)。這是Google搜索的核心算法之一。

可以看出,對于少量數(shù)據(jù)的搜索,倒排索引并不會比常規(guī)方法節(jié)約多少時間。但是當(dāng)你有100000000條句子,1000個關(guān)鍵詞的時候,用倒排索引實(shí)現(xiàn)搜索,所需要的時間只有常規(guī)方法的1/10甚至更少。

最后回到前面遇到的一個問題,當(dāng)句子里面同時含有字母C、N、M,雖然這三個字母并不是組合在一起的,也會被搜索出來。這就涉及到搜索引擎的另一個核心技術(shù)——分詞了。對于英文而言,使用空格來切分單詞就好了。但是對于中文來說,不同的漢字組合在一起構(gòu)成的詞語,字?jǐn)?shù)是不一樣的。甚至有些專有名詞,可能七八個字,但是也要作為整體來搜索。

分詞的具體做法,又是另外一個故事了。

本文轉(zhuǎn)載自微信公眾號「未聞Code」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系未聞Code公眾號。


本文題目:使用倒排索引極速提高字符串搜索效率
當(dāng)前路徑:http://www.dlmjj.cn/article/djdsdis.html