撸了个搜索引擎系统,爽!

举报
民工哥 发表于 2022/04/16 02:26:16 2022/04/16
【摘要】 点击下方“Java编程鸭”关注并标星 更多精彩 第一时间直达 咋们如果用我们的小服务器去搞百度,搜狗那种引擎肯定是不行的,内属于全站搜索,我们这里做一个站内搜索。这个还是可以的,就类似于我们对网站里的资源进行搜索。 一.搜索引擎怎么搜索 搜索引擎就像一个小蜜蜂每天不停的采摘蜂蜜,就是去爬虫各个网页,然后通过爬取之后建立...

点击下方“Java编程鸭”关注并标星

更多精彩 第一时间直达

 
 

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

一.搜索引擎怎么搜索

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

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

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

为什么要用索引呢?

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

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

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

  • Q技能 阿尔法突袭

  • W技能 冥想

  • E技能 无双

  • R技能 高原血统

故根据名字选技能

3ef177dfdc7fffc6192fa38a23b9fb43.png

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

  1. 蛮王

  2. 无极剑圣

  3. 剑姬

故根据特点选择英雄

二.模块划分

1.索引模块

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

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

2.搜索模块

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

  • 输入:用户的查询词

  • 输出:完整的搜索结果

3.web模块

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

包含了前端和后端。

三. 怎么实现分词

分词的原理

1.基于词库

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

2.基于统计

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

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

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

20e180f247903e1e63f538024c2e1d65.png

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

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

17ad3f9b241fc148625b63a72faf2cc3.png

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

四.文件读取

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

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


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

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


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

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

6369e91755a15623efe167ec5298323c.png

4.1 打开文件,解析内容。

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

4.1.1解析Title

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

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


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

4.1.2解析Url操作

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


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

4.1.3解析内容

<>为开关进行对数据的读取,以int类型读取,为什么要用int而不是char呢因为int类型读完之后就变成-1可以判断一下是否读取完毕。

具体代码如下很容易理解。


   
  1. private  String parseContent(File f) throws IOException {
  2.           //先按照一个一个字符来读取,以<>作为开关
  3.         try(FileReader fileReader=new FileReader(f)) {
  4.             //加上一个是否拷贝的开关.
  5.             boolean isCopy=true;
  6.             //还需要准备一个结果保存
  7.             StringBuilder content=new StringBuilder();
  8.             while (true){
  9.                 //此处的read的返回值是int,不是char
  10.                 //如果读到文件末尾,就会返回-1,这是用int的好处;
  11.                 int  ret = 0;
  12.                 try {
  13.                     ret = fileReader.read();
  14.                 } catch (IOException e) {
  15.                     e.printStackTrace();
  16.                 }
  17.                 if(ret==-1) {
  18.                         break;
  19.                     }
  20.                     char c=(char) ret;
  21.                     if(isCopy){
  22.                         if(c=='<'){
  23.                             isCopy=false;
  24.                             continue;
  25.                         }
  26.                         //其他字符直接拷贝
  27.                         if(c=='\n'||c=='\r'){
  28.                             c=' ';
  29.                         }
  30.                         content.append(c);
  31.                     }else{
  32.                         if(c=='>'){
  33.                             isCopy=true;
  34.                         }
  35.                     }
  36.             }
  37.             return  content.toString();
  38.         } catch (FileNotFoundException e) {
  39.             e.printStackTrace();
  40.         }
  41.         return "";
  42.     }

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


   
  1. import java.io.File;
  2. import java.io.FileNotFoundException;
  3. import java.io.FileReader;
  4. import java.io.IOException;
  5. import java.util.ArrayList;
  6. //读取刚刚文档
  7. public class Parser {
  8.      private static final  String INPUT_PATH="D:/test/docs/api";
  9.       public  void run(){
  10.           //整个Parser类的入口
  11.           //1.根据路径,去枚举出所有的文件.(html);
  12.           ArrayList<File> fileList=new ArrayList<>();
  13.           enumFile(INPUT_PATH,fileList);
  14.           System.out.println(fileList);
  15.           System.out.println(fileList.size());
  16.           //2.针对上面罗列出的文件,打开文件,读取文件内容,并进行解析
  17.           for (File f:fileList){
  18.               System.out.println("开始解析"+f.getAbsolutePath());
  19.               parseHTML(f);
  20.           }
  21.           //3.把在内存中构造好的索引数据结构,保定到指定的文件中。
  22.       }
  23.     private  String parseTitle(File f) {
  24.           String name= f.getName();
  25.          return name.substring(0,f.getName().length()-5);
  26.     }
  27.     private  String parseUrl(File f) {
  28.       String part1="https://docs.oracle.com/javase/8/docs/api/";
  29.          String part2=f.getAbsolutePath().substring(INPUT_PATH.length());
  30.           return part1+part2;
  31.     }
  32.     private  String parseContent(File f) throws IOException {
  33.           //先按照一个一个字符来读取,以<>作为开关
  34.         try(FileReader fileReader=new FileReader(f)) {
  35.             //加上一个是否拷贝的开关.
  36.             boolean isCopy=true;
  37.             //还需要准备一个结果保存
  38.             StringBuilder content=new StringBuilder();
  39.             while (true){
  40.                 //此处的read的返回值是int,不是char
  41.                 //如果读到文件末尾,就会返回-1,这是用int的好处;
  42.                 int  ret = 0;
  43.                 try {
  44.                     ret = fileReader.read();
  45.                 } catch (IOException e) {
  46.                     e.printStackTrace();
  47.                 }
  48.                 if(ret==-1) {
  49.                         break;
  50.                     }
  51.                     char c=(char) ret;
  52.                     if(isCopy){
  53.                         if(c=='<'){
  54.                             isCopy=false;
  55.                             continue;
  56.                         }
  57.                         //其他字符直接拷贝
  58.                         if(c=='\n'||c=='\r'){
  59.                             c=' ';
  60.                         }
  61.                         content.append(c);
  62.                     }else{
  63.                         if(c=='>'){
  64.                             isCopy=true;
  65.                         }
  66.                     }
  67.             }
  68.             return  content.toString();
  69.         } catch (FileNotFoundException e) {
  70.             e.printStackTrace();
  71.         }
  72.         return "";
  73.     }
  74.     private void parseHTML (File f){
  75.         //解析出标题
  76.           String title=parseTitle(f);
  77.         //解析出对应的url
  78.           String url=parseUrl(f);
  79.         //解析出对应的正文
  80.         try {
  81.             String content=parseContent(f);
  82.         } catch (IOException e) {
  83.             e.printStackTrace();
  84.         }
  85.     }
  86.       //第一个参数表示从哪里开始遍历 //第二个表示结果。
  87.       private void enumFile(String inputPath,ArrayList<File>fileList){
  88.          File rootPath=new File(inputPath);
  89.          //listFiles 能够获取到一层目录下的文件
  90.         File[] files= rootPath.listFiles();
  91.          for(File f:files){
  92.              //根据当前f的类型判断是否递归。
  93.              //如果f是一个普通文件,就把f加入到fileList里面
  94.              //如果不是就调用递归
  95.              if(f.isDirectory()){
  96.                  enumFile(f.getAbsolutePath(),fileList);
  97.              }else {
  98.                  if(f.getAbsolutePath().endsWith(".html"))
  99.                  fileList.add(f);
  100.              }
  101.          }
  102.       }
  103.     public static void main(String[] args) {
  104.         //通过main方法来实现整个制作索引的过程
  105.         Parser parser=new Parser();
  106.         parser.run();
  107.     }
  108. }

来源:blog.csdn.net/m0_57315623/

article/details/123829698

END


   
  1. 看完本文有收获?请转发分享给更多人
  2. 关注「Java编程鸭」,提升Java技能
  3. 关注Java编程鸭微信公众号,后台回复:码农大礼包 可以获取最新整理的技术资料一份。涵盖Java 框架学习、架构师学习等!
  4. 文章有帮助的话,在看,转发吧。
  5. 谢谢支持哟 (*^__^*)

文章来源: mingongge.blog.csdn.net,作者:民工哥,版权归原作者所有,如需转载,请联系作者。

原文链接:mingongge.blog.csdn.net/article/details/124185601

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。