1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 搜索引擎——反向索引原理揭秘及手写ik分词器

搜索引擎——反向索引原理揭秘及手写ik分词器

时间:2020-11-04 02:24:56

相关推荐

搜索引擎——反向索引原理揭秘及手写ik分词器

原创不易,转载请标明地址,或者直接附上我的博客首页https://georgedage./

上篇博客我们说到,数据库为什么不适合搜索引擎的底层存储?,那么什么适合呢?

elasticsearch / solr

那么为什么搜索引擎适合呢?搜索引擎有什么优点呢?下面我们根据提出问题,由浅及深的进行探讨!!!

一、首先分析问题

我们查询时,输入的是苍老师,想要得到标题或内容中包含“苍老师”的新闻列表。怎么办?

有同学会提出,如果标题、内容列上都有一个这样的索引,里面能快速找到与苍老师关键字对应的文章id,再根据文章id就可以快速找到文章了。

二、那么你认为这个索引是什么样的结构呢

在这里,词到文章的索引,我们就称之为倒排索引!!!也就是搜索引擎的精髓所在。

三、为什么称它为倒排索引?

其实说个秘密,哈哈,也不算秘密,倒排索引英文全名:Inverted Index,然后被国人翻译失败了,翻译成倒排索引,其实它真正的名字应该是反向索引。

那么反向索引还是索引吗?,从这个词上,你或许就能猜到。反向索引本质上其实还是索引,并无特别。

就上面两个图,我们能否将其合并。也就是说

四、上面的两个索引可以合并在一起吗

答案很显然,当然是可以的。

我们自己内心提出问题,为什么要这样做,为什么博主我会说到给两个索引合并在一起。这样做有什么好处?

这个做一个小问题,大家可以思考思考!

五、反向索引的记录数会不会很大

》如果是英文,最大是多少?

》如果是中文,最大是多少?

找了一份资料,资料显示:

所以,我们给出结论:量不会很大,100万以内;通过这个索引找文章会很快。

六、如何建立一个这样的索引

数据示例

新闻id:1

新闻标题:georgedage与乔治一起带球

新闻内容:2025年2月21日,georgedage来到了洛杉矶参加乔治的告别演出,并与乔治进行打球。

》怎样为上面的新闻文章建立反向索引? 一句话怎么分成多个词?人能分,计算机能不能分?

这里我们就引入第二件要说的分词器,也就是我们安装es的时候,提到会安装ik分词器。分词器的原理很简单,这里就是为了告诉大家,你也可以手写分词器!!!

七、分词器原理揭秘——如何建立一个这样的索引

》如果是英文文章,好不好分?

It’sone thing to find the 10 best documents to match your query

英文好分(有空格),中文则不好分。但一定得要分,否则无法建立反向索引。就必须写一套专门]的程序来做这个事情:分词器

八、分词器和自然语言之间的关系

一般来说,每门语言都有其对应的分词器,毕竟整个地球上,大家的语言并不相同。

九、如果要开发一个中文分词器,你觉得该怎么实现对一句话进行分词?

》为什么我们不会分出:张三、说的、的确、确实、实在、在理?

因为我们的大脑可以进行歧义分析。

中文分词器原理:有个词的字典,对语句前后字进行组合,与字典匹配,歧义分析

十、接下来就是我们的重头戏,手写中文分词器

项目结构:

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>();//红黑树的实现//从文件加载字典到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;//组成以这个字符开头的词的树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("乔治大哥是一个很优秀的博主");for (String s:tokens) {System.out.println(s);}}}

dictionary.txt

乔治大哥是一个很优秀的博主

结果展示:

最后

有什么想聊的,欢迎留言!欢迎吐槽!哈哈

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。