用Java写了一个搜索引擎系统

优采云 发布时间: 2022-05-07 19:02

  用Java写了一个搜索引擎系统

  前言

  咱们如果用我们的小服务器去搞百度,搜狗那种引擎肯定是不行的,内属于全站搜索,我们这里做一个站内搜索。这个还是可以的,就类似于我们对网站里的资源进行搜索。

  一.搜索引擎怎么搜索

  搜索引擎就像一个小蜜蜂每天不停的采摘蜂蜜,就是去爬虫各个网页,然后通过爬取之后建立索引,以供于我们去搜索。

  这里我们可以使用Python,或者下载文档压缩包。这里我们下包把,快多了。本来想搞一个英雄联盟的,实在找不见,要是后续有老铁找到可以分享一下。

  建议大家别爬虫(要不然被告了,不过我们学校的官网倒是可以随便爬,我们当时就是拿这个练手的) 为什么要用索引呢?

  因为爬的数据太多了,不索引,难道我去遍历吗?时间复杂度太大了。

  这里我们需要建立索引,索引分别为正排索引,和倒排索引。

  拿LOL举个例子吧,正排就相当于,我们提到无极剑圣的技能就可以联想到:

  所以这是根据名字选技能

  倒排索引就是LOL里面谁有剑:

  所以这是根据特点选择英雄

  二.模块划分

  1.索引模块

  1)扫描下载到的文档,分析内容,构建出,正排索引和倒排索引。并且把索引内容保存到文件中。

  2)加载制作i好的索引。并提供一些API实现查正排和查倒排这样的功能。

  2.搜索模块

  1)调用索引模块,实现一个搜索的完整过程。

  输入:用户的查询词 输出:完整的搜索结果

  3.web模块

  需要实现一个简单的web程序,能够通过网页的形式和用户进行交互。包含了前端和后端。

  三. 怎么实现分词

  分词的原理:

  1.基于词库

  尝试把所有的词都进行穷举,把这些结果放到词典文件中。

  2.基于统计

  收集到很多的语料库,进行人工标注,知道了那些字在一起的概率比较大~

  java中能够实现分词的第三方工具也是有很多的

  比如ansj(听说唱的兄弟可能听过ansj,哈哈)这个就是一个maven中央仓库的分词第三方库。

  

  我们直接下载最新版本然后放入pom.xml里面

  test包里直接操作:我们使用这个测试代码直接搞。试一下这个包咋用。

  

  import org.ansj.domain.Term;import org.ansj.splitWord.analysis.ToAnalysis;import java.util.List;public class TastAnsj { public static void main(String[] args) { String str = "易大师是一个有超高机动性的刺客、战士型英雄,擅长利用快速的打击迅速击溃对手,易大师一般打野和走单人路,作为无极剑道的最后传人,易可以迅速砍出大量伤害,同时还能利用技能躲避猛烈的攻击,避开敌人的集火。"; List terms = ToAnalysis.parse(str).getTerms(); for (Term term : terms) { System.out.println(term.getName()); } }}

  四.文件读取

  把刚刚下载好的文档的路径复制到String中并且用常量标记。

  这一步是为了用遍历的方法把所有html文件搞出来,我们这里用了一个递归,如果是绝对路径,就填加到文件链表,如果不是就递归,继续添加里面的值。

  import java.io.File;import java.util.ArrayList;//读取刚刚文档public class Parser { private static final String INPUT_PATH="D:/test/docs/api"; public void run(){ //整个Parser类的入口 //1.根据路径,去枚举出所有的文件.(html); ArrayList fileList=new ArrayList(); enumFile(INPUT_PATH,fileList); System.out.println(fileList); System.out.println(fileList.size()); //2.针对上面罗列出的文件,打开文件,读取文件内容,并进行解析 //3.把在内存中构造好的索引数据结构,保定到指定的文件中。 } //第一个参数表示从哪里开始遍历 //第二个表示结果。 private void enumFile(String inputPath,ArrayListfileList){ File rootPath=new File(inputPath); //listFiles 能够获取到一层目录下的文件 File[] files= rootPath.listFiles(); for(File f:files){ //根据当前f的类型判断是否递归。 //如果f是一个普通文件,就把f加入到fileList里面 //如果不是就调用递归 if(f.isDirectory()){ enumFile(f.getAbsolutePath(),fileList); }else { fileList.add(f); } } } public static void main(String[] args) { //通过main方法来实现整个制作索引的过程 Parser parser=new Parser(); parser.run(); }}

  

  我们尝试运行一下,这里的文件也太多了吧,而且无论是什么都打印出来了。所以我们下一步就是把这些文件进行筛选,选择有用的。

  else { if(f.getAbsolutePath().endsWith(",html")) fileList.add(f);}

  这个代码就是只是针对末尾为html的文件。下图就是展示结果。

  

  4.1 打开文件,解析内容。

  这里分为三个分别是解析Title,解析Url,解析内容Content

  4.1.1解析Title

  f.getName()是直接读取文件名字的方法。

  我们用的name.substring(0,f.getName().length()-5);为什么要用总的文件名字长度减去5呢,因为.HTML刚好就是五。

  private String parseTitle(File f) { String name= f.getName();         return name.substring(0,f.getName().length()-5); }

  4.1.2解析Url操作

  这里的url就是我们平时去一个浏览器输入一个东西下面会有一个url,这个url就是我们的绝对路径经过截取获得出我们的相对的目录,然后与我们的http进行拼接,这样就可以直接得到一个页面。

  private String parseUrl(File f) { String part1="https://docs.oracle.com/javase/8/docs/api/"; String part2=f.getAbsolutePath().substring(INPUT_PATH.length()); return part1+part2; }

  4.1.3解析内容

  以为开关进行对数据的读取,以int类型读取,为什么要用int而不是char呢因为int类型读完之后就变成-1可以判断一下是否读取完毕。具体代码如下很容易理解。

  private String parseContent(File f) throws IOException { //先按照一个一个字符来读取,以作为开关 try(FileReader fileReader=new FileReader(f)) { //加上一个是否拷贝的开关. boolean isCopy=true; //还需要准备一个结果保存 StringBuilder content=new StringBuilder(); while (true){ //此处的read的返回值是int,不是char //如果读到文件末尾,就会返回-1,这是用int的好处; int ret = 0; try { ret = fileReader.read(); } catch (IOException e) { e.printStackTrace(); } if(ret==-1) { break; } char c=(char) ret; if(isCopy){ if(c==''){ isCopy=true; } }            } return content.toString(); } catch (FileNotFoundException e) { e.printStackTrace(); } return ""; }

  这一模块总的代码块如下:

  import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;import java.util.ArrayList;//读取刚刚文档public class Parser { private static final String INPUT_PATH="D:/test/docs/api"; public void run(){ //整个Parser类的入口 //1.根据路径,去枚举出所有的文件.(html); ArrayList fileList=new ArrayList(); enumFile(INPUT_PATH,fileList); System.out.println(fileList); System.out.println(fileList.size()); //2.针对上面罗列出的文件,打开文件,读取文件内容,并进行解析 for (File f:fileList){ System.out.println("开始解析"+f.getAbsolutePath()); parseHTML(f); } //3.把在内存中构造好的索引数据结构,保定到指定的文件中。 }<br /> private String parseTitle(File f) { String name= f.getName();         return name.substring(0,f.getName().length()-5); } private String parseUrl(File f) { String part1="https://docs.oracle.com/javase/8/docs/api/"; String part2=f.getAbsolutePath().substring(INPUT_PATH.length()); return part1+part2; } private String parseContent(File f) throws IOException { //先按照一个一个字符来读取,以作为开关 try(FileReader fileReader=new FileReader(f)) { //加上一个是否拷贝的开关. boolean isCopy=true; //还需要准备一个结果保存 StringBuilder content=new StringBuilder(); while (true){ //此处的read的返回值是int,不是char //如果读到文件末尾,就会返回-1,这是用int的好处; int ret = 0; try { ret = fileReader.read(); } catch (IOException e) { e.printStackTrace(); } if(ret==-1) { break; } char c=(char) ret; if(isCopy){ if(c==''){ isCopy=true; } }            } return content.toString(); } catch (FileNotFoundException e) { e.printStackTrace(); } return ""; } private void parseHTML (File f){ //解析出标题 String title=parseTitle(f); //解析出对应的url String url=parseUrl(f); //解析出对应的正文 try { String content=parseContent(f); } catch (IOException e) { e.printStackTrace(); } } //第一个参数表示从哪里开始遍历 //第二个表示结果。 private void enumFile(String inputPath,ArrayListfileList){ File rootPath=new File(inputPath); //listFiles 能够获取到一层目录下的文件 File[] files= rootPath.listFiles(); for(File f:files){ //根据当前f的类型判断是否递归。 //如果f是一个普通文件,就把f加入到fileList里面 //如果不是就调用递归 if(f.isDirectory()){ enumFile(f.getAbsolutePath(),fileList); }else { if(f.getAbsolutePath().endsWith(".html")) fileList.add(f); } } } public static void main(String[] args) { //通过main方法来实现整个制作索引的过程 Parser parser=new Parser(); parser.run(); }}

  欢迎加入程序员交流群

  鬼哥我创建了几个技术交流群,大家在群里都是九分聊技术、一分聊风雪~

  如果你没有加群,不妨扫描下方二维码、添加我的微信。我拉大家进群,记得备注:工作城市+昵称+技术方向!

  Ps:如果朋友圈对我设置权限的话,那就不用加我好友了。

  

  <p data-mid="" data-darkmode-bgcolor-16266178294118="rgb(25, 25, 25)" data-darkmode-original-bgcolor-16266178294118="#fff|rgb(255, 255, 255)" data-darkmode-color-16266178294118="rgb(19, 52, 86)" data-darkmode-original-color-16266178294118="#fff|rgb(62, 62, 62)|rgb(19, 52, 86)" data-darkmode-bgimage-16266178294118="1" style="outline: 0px;text-align: center;">往期推荐

  B站,竟然变成了相亲求偶平台!<br data-darkmode-bgcolor-16266178294118="rgb(25, 25, 25)" data-darkmode-original-bgcolor-16266178294118="#fff|rgb(255, 255, 255)" data-darkmode-color-16266178294118="rgb(67, 131, 199)" data-darkmode-original-color-16266178294118="#fff|rgb(62, 62, 62)|rgb(44, 95, 149)" style="outline: 0px;" />

  MySQL夺命15问,你能坚持到第几问?<br style="outline: 0px;" />

  Nginx 轻松搞定跨域问题!<br style="outline: 0px;" />

  换掉 UUID,更快更安全!<br style="outline: 0px;" />

  Java实现10万+并发去重,持续优化!<br data-darkmode-bgcolor-16266178294118="rgb(25, 25, 25)" data-darkmode-original-bgcolor-16266178294118="#fff|rgb(255, 255, 255)" data-darkmode-color-16266178294118="rgb(67, 131, 199)" data-darkmode-original-color-16266178294118="#fff|rgb(62, 62, 62)|rgb(44, 95, 149)" style="outline: 0px;" /><br style="outline: 0px;" />花费数月整理出来的技术资源免费分享给大家扫描下方二维码,回复关键字【技术福利】获取!

喜欢的这里报道<br data-darkmode-bgcolor-16266178294118="rgb(25, 25, 25)" data-darkmode-original-bgcolor-16266178294118="#fff|rgb(255, 255, 255)" data-darkmode-color-16266178294118="rgb(163, 163, 163)" data-darkmode-original-color-16266178294118="#fff|rgb(62, 62, 62)" style="outline: 0px;" />↘↘↘</p>

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线