搜索引擎——反向索引原理揭秘及手写ik分词器
原創(chuàng)不易,轉(zhuǎn)載請(qǐng)標(biāo)明地址,或者直接附上我的博客首頁https://georgedage.blog.csdn.net/
上篇博客我們說到,數(shù)據(jù)庫為什么不適合搜索引擎的底層存儲(chǔ)?,那么什么適合呢?
elasticsearch / solr
那么為什么搜索引擎適合呢?搜索引擎有什么優(yōu)點(diǎn)呢?下面我們根據(jù)提出問題,由淺及深的進(jìn)行探討!!!
一、首先分析問題
我們查詢時(shí),輸入的是蒼老師,想要得到標(biāo)題或內(nèi)容中包含“蒼老師”的新聞列表。怎么辦?
有同學(xué)會(huì)提出,如果標(biāo)題、內(nèi)容列上都有一個(gè)這樣的索引,里面能快速找到與蒼老師關(guān)鍵字對(duì)應(yīng)的文章id,再根據(jù)文章id就可以快速找到文章了。
二、那么你認(rèn)為這個(gè)索引是什么樣的結(jié)構(gòu)呢
在這里,詞到文章的索引,我們就稱之為倒排索引!!! 也就是搜索引擎的精髓所在。
三、為什么稱它為倒排索引?
其實(shí)說個(gè)秘密,哈哈,也不算秘密,倒排索引英文全名:Inverted Index,然后被國人翻譯失敗了,翻譯成倒排索引,其實(shí)它真正的名字應(yīng)該是反向索引。
那么反向索引還是索引嗎?,從這個(gè)詞上,你或許就能猜到。反向索引本質(zhì)上其實(shí)還是索引,并無特別。
就上面兩個(gè)圖,我們能否將其合并。也就是說
四、上面的兩個(gè)索引可以合并在一起嗎
?
答案很顯然,當(dāng)然是可以的。
我們自己內(nèi)心提出問題,為什么要這樣做,為什么博主我會(huì)說到給兩個(gè)索引合并在一起。這樣做有什么好處?
這個(gè)做一個(gè)小問題,大家可以思考思考!
五、反向索引的記錄數(shù)會(huì)不會(huì)很大
》如果是英文,最大是多少?
》如果是中文,最大是多少?
找了一份資料,資料顯示:
所以,我們給出結(jié)論:量不會(huì)很大,100萬以內(nèi);通過這個(gè)索引找文章會(huì)很快。
六、如何建立一個(gè)這樣的索引
數(shù)據(jù)示例
新聞id:1
新聞標(biāo)題:georgedage與喬治一起帶球
新聞內(nèi)容:2025年2月21日,georgedage來到了洛杉磯參加喬治的告別演出,并與喬治進(jìn)行打球。
》怎樣為上面的新聞文章建立反向索引? 一句話怎么分成多個(gè)詞?人能分,計(jì)算機(jī)能不能分?
?
這里我們就引入第二件要說的分詞器,也就是我們安裝es的時(shí)候,提到會(huì)安裝ik分詞器。分詞器的原理很簡單,這里就是為了告訴大家,你也可以手寫分詞器!!!
七、分詞器原理揭秘——如何建立一個(gè)這樣的索引
》如果是英文文章,好不好分?
It’sone thing to find the 10 best documents to match your query
英文好分(有空格),中文則不好分。但一定得要分,否則無法建立反向索引。就必須寫一套專門]的程序來做這個(gè)事情:分詞器
八、分詞器和自然語言之間的關(guān)系
一般來說,每門語言都有其對(duì)應(yīng)的分詞器,畢竟整個(gè)地球上,大家的語言并不相同。
九、如果要開發(fā)一個(gè)中文分詞器,你覺得該怎么實(shí)現(xiàn)對(duì)一句話進(jìn)行分詞?
?
》為什么我們不會(huì)分出:張三、說的、的確、確實(shí)、實(shí)在、在理?
因?yàn)槲覀兊拇竽X可以進(jìn)行歧義分析。
中文分詞器原理:有個(gè)詞的字典,對(duì)語句前后字進(jìn)行組合,與字典匹配,歧義分析
?
十、接下來就是我們的重頭戲,手寫中文分詞器
項(xiàng)目結(jié)構(gòu):
Tokenizer
package com.jd.search;import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.*;public class Tokenizer {private Map<Character,Object> dictionary;public Tokenizer(String dictionaryFilePath) throws IOException{dictionary = new TreeMap<Character, Object>();//紅黑樹的實(shí)現(xiàn)//從文件加載字典到treeMapthis.loadDictionary(dictionaryFilePath);}private void loadDictionary(String dictionaryFilePath) throws IOException {BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(dictionaryFilePath)));String line = null;while((line = reader.readLine()) != null){line = line.trim();if (line.length() == 0){continue;}char c;Map<Character,Object> child = this.dictionary;//組成以這個(gè)字符開頭的詞的樹for (int i = 0; i < line.length(); i++) {c = line.charAt(i);Map<Character,Object> ccMap = (Map<Character, Object>) child.get(c);if (ccMap == null){ccMap = new HashMap<Character, Object>();child.put(c,ccMap);}child = ccMap;}child.put(' ',null);}}public List<String> participle(String text) {if (text == null){return null;}text = text.trim();if (text.length() == 0){return null;}List<String> tokens = new ArrayList<String>();char c;for (int i = 0; i < text.length();) {StringBuilder token = new StringBuilder();Map<Character,Object> child = this.dictionary;boolean matchToken = false;for (int j = i; j < text.length(); j++) {c = text.charAt(j);Map<Character,Object> ccMap = (Map<Character, Object>) child.get(c);if (ccMap == null){if (child.containsKey(' ')){matchToken = true;i = j;}break;}else {token.append(c);child = ccMap;}}if (matchToken){tokens.add(token.toString());}else {if (child.containsKey(' ')){tokens.add(token.toString());break;}else {tokens.add("" + text.charAt(i));i++;}}}return tokens;}public static void main(String[] args) throws IOException {Tokenizer tk = new Tokenizer(Tokenizer.class.getResource("/dictionary.txt").getPath());List<String> tokens = tk.participle("喬治大哥是一個(gè)很優(yōu)秀的博主");for (String s:tokens) {System.out.println(s);}}}dictionary.txt
喬治大哥 是 一個(gè) 很 優(yōu)秀 的 博主結(jié)果展示:
?
最后?
有什么想聊的,歡迎留言!歡迎吐槽!哈哈
總結(jié)
以上是生活随笔為你收集整理的搜索引擎——反向索引原理揭秘及手写ik分词器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库为什么不适合搜索引擎的底层存储?
- 下一篇: 你所不知道的getResource()在