小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

用Java寫(xiě)了一個(gè)搜索引擎系統(tǒng)

 昵稱10087950 2022-06-16 發(fā)布于江蘇

來(lái)源:https://blog.csdn.net/m0_57315623?type=blog

前言

咱們?nèi)绻梦覀兊男》?wù)器去搞百度,搜狗那種引擎肯定是不行的,內(nèi)屬于全站搜索,我們這里做一個(gè)站內(nèi)搜索。這個(gè)還是可以的,就類(lèi)似于我們對(duì)網(wǎng)站里的資源進(jìn)行搜索。

一.搜索引擎怎么搜索

搜索引擎就像一個(gè)小蜜蜂每天不停的采摘蜂蜜,就是去爬蟲(chóng)各個(gè)網(wǎng)頁(yè),然后通過(guò)爬取之后建立索引,以供于我們?nèi)ニ阉鳌?/p>

這里我們可以使用Python,或者下載文檔壓縮包。這里我們下包把,快多了。本來(lái)想搞一個(gè)英雄聯(lián)盟的,實(shí)在找不見(jiàn),要是后續(xù)有老鐵找到可以分享一下。

建議大家別爬蟲(chóng)(要不然被告了,不過(guò)我們學(xué)校的官網(wǎng)倒是可以隨便爬,我們當(dāng)時(shí)就是拿這個(gè)練手的) 為什么要用索引呢?

因?yàn)榕赖臄?shù)據(jù)太多了,不索引,難道我去遍歷嗎?時(shí)間復(fù)雜度太大了。

這里我們需要建立索引,索引分別為正排索引,和倒排索引。

拿LOL舉個(gè)例子吧,正排就相當(dāng)于,我們提到無(wú)極劍圣的技能就可以聯(lián)想到:

  • Q技能 阿爾法突襲
  • W技能 冥想
  • E技能 無(wú)雙
  • R技能 高原血統(tǒng)

所以這是根據(jù)名字選技能

倒排索引就是LOL里面誰(shuí)有劍:

  1. 蠻王
  2. 無(wú)極劍圣
  3. 劍姬

所以這是根據(jù)特點(diǎn)選擇英雄

二.模塊劃分

1.索引模塊

1)掃描下載到的文檔,分析內(nèi)容,構(gòu)建出,正排索引和倒排索引。并且把索引內(nèi)容保存到文件中。

2)加載制作i好的索引。并提供一些API實(shí)現(xiàn)查正排和查倒排這樣的功能。

2.搜索模塊

1)調(diào)用索引模塊,實(shí)現(xiàn)一個(gè)搜索的完整過(guò)程。

輸入:用戶的查詢?cè)~ 輸出:完整的搜索結(jié)果

3.web模塊

需要實(shí)現(xiàn)一個(gè)簡(jiǎn)單的web程序,能夠通過(guò)網(wǎng)頁(yè)的形式和用戶進(jìn)行交互。包含了前端和后端。

三. 怎么實(shí)現(xiàn)分詞

分詞的原理:

1.基于詞庫(kù)

嘗試把所有的詞都進(jìn)行窮舉,把這些結(jié)果放到詞典文件中。

2.基于統(tǒng)計(jì)

收集到很多的語(yǔ)料庫(kù),進(jìn)行人工標(biāo)注,知道了那些字在一起的概率比較大~

java中能夠?qū)崿F(xiàn)分詞的第三方工具也是有很多的

比如ansj(聽(tīng)說(shuō)唱的兄弟可能聽(tīng)過(guò)ansj,哈哈)這個(gè)就是一個(gè)maven中央倉(cāng)庫(kù)的分詞第三方庫(kù)。

圖片

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

test包里直接操作:我們使用這個(gè)測(cè)試代碼直接搞。試一下這個(gè)包咋用。

圖片
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 = "易大師是一個(gè)有超高機(jī)動(dòng)性的刺客、戰(zhàn)士型英雄,擅長(zhǎng)利用快速的打擊迅速擊潰對(duì)手,易大師一般打野和走單人路,作為無(wú)極劍道的最后傳人,易可以迅速砍出大量傷害,同時(shí)還能利用技能躲避猛烈的攻擊,避開(kāi)敵人的集火。";
        List<Term> terms = ToAnalysis.parse(str).getTerms();
        for (Term term : terms) {
            System.out.println(term.getName());
        }
    }
}

四.文件讀取

把剛剛下載好的文檔的路徑復(fù)制到String中并且用常量標(biāo)記。

這一步是為了用遍歷的方法把所有html文件搞出來(lái),我們這里用了一個(gè)遞歸,如果是絕對(duì)路徑,就填加到文件鏈表,如果不是就遞歸,繼續(xù)添加里面的值。

import java.io.File;
import java.util.ArrayList;


//讀取剛剛文檔
public class Parser {
     private static final  String INPUT_PATH="D:/test/docs/api";
      public  void run(){
          //整個(gè)Parser類(lèi)的入口
          //1.根據(jù)路徑,去枚舉出所有的文件.(html);
          ArrayList<File> fileList=new ArrayList<>();
          enumFile(INPUT_PATH,fileList);
          System.out.println(fileList);
          System.out.println(fileList.size());
          //2.針對(duì)上面羅列出的文件,打開(kāi)文件,讀取文件內(nèi)容,并進(jìn)行解析
          //3.把在內(nèi)存中構(gòu)造好的索引數(shù)據(jù)結(jié)構(gòu),保定到指定的文件中。
      }
      //第一個(gè)參數(shù)表示從哪里開(kāi)始遍歷 //第二個(gè)表示結(jié)果。
      private void enumFile(String inputPath,ArrayList<File>fileList){
         File rootPath=new File(inputPath);
         //listFiles 能夠獲取到一層目錄下的文件
        File[] files= rootPath.listFiles();
         for(File f:files){
             //根據(jù)當(dāng)前f的類(lèi)型判斷是否遞歸。
             //如果f是一個(gè)普通文件,就把f加入到fileList里面
             //如果不是就調(diào)用遞歸
             if(f.isDirectory()){
                 enumFile(f.getAbsolutePath(),fileList);
             }else {
                 fileList.add(f);
             }
         }
      }
    public static void main(String[] args) {
        //通過(guò)main方法來(lái)實(shí)現(xiàn)整個(gè)制作索引的過(guò)程
        Parser parser=new Parser();
        parser.run();
    }
}
圖片

我們嘗試運(yùn)行一下,這里的文件也太多了吧,而且無(wú)論是什么都打印出來(lái)了。所以我們下一步就是把這些文件進(jìn)行篩選,選擇有用的。

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

這個(gè)代碼就是只是針對(duì)末尾為html的文件。下圖就是展示結(jié)果。

圖片

4.1 打開(kāi)文件,解析內(nèi)容。

這里分為三個(gè)分別是解析Title,解析Url,解析內(nèi)容Content

4.1.1解析Title

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

我們用的name.substring(0,f.getName().length()-5);為什么要用總的文件名字長(zhǎng)度減去5呢,因?yàn)?HTML剛好就是五。

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

    }

4.1.2解析Url操作

這里的url就是我們平時(shí)去一個(gè)瀏覽器輸入一個(gè)東西下面會(huì)有一個(gè)url,這個(gè)url就是我們的絕對(duì)路徑經(jīng)過(guò)截取獲得出我們的相對(duì)的目錄,然后與我們的http進(jìn)行拼接,這樣就可以直接得到一個(gè)頁(yè)面。

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解析內(nèi)容

以<>為開(kāi)關(guān)進(jìn)行對(duì)數(shù)據(jù)的讀取,以int類(lèi)型讀取,為什么要用int而不是char呢因?yàn)閕nt類(lèi)型讀完之后就變成-1可以判斷一下是否讀取完畢。具體代碼如下很容易理解。

private  String parseContent(File f) throws IOException {
          //先按照一個(gè)一個(gè)字符來(lái)讀取,以<>作為開(kāi)關(guān)
        try(FileReader fileReader=new FileReader(f)) {
            //加上一個(gè)是否拷貝的開(kāi)關(guān).
            boolean isCopy=true;
            //還需要準(zhǔn)備一個(gè)結(jié)果保存
            StringBuilder content=new StringBuilder();
            while (true){
                //此處的read的返回值是int,不是char
                //如果讀到文件末尾,就會(huì)返回-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=false;
                            continue;
                        }
                        //其他字符直接拷貝
                        if(c=='\n'||c=='\r'){
                            c=' ';
                        }
                        content.append(c);
                    }else{
                        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(){
          //整個(gè)Parser類(lèi)的入口
          //1.根據(jù)路徑,去枚舉出所有的文件.(html);
          ArrayList<File> fileList=new ArrayList<>();
          enumFile(INPUT_PATH,fileList);
          System.out.println(fileList);
          System.out.println(fileList.size());
          //2.針對(duì)上面羅列出的文件,打開(kāi)文件,讀取文件內(nèi)容,并進(jìn)行解析
          for (File f:fileList){
              System.out.println("開(kāi)始解析"+f.getAbsolutePath());
              parseHTML(f);
          }
          //3.把在內(nèi)存中構(gòu)造好的索引數(shù)據(jù)結(jié)構(gòu),保定到指定的文件中。
      }


    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 {
          //先按照一個(gè)一個(gè)字符來(lái)讀取,以<>作為開(kāi)關(guān)
        try(FileReader fileReader=new FileReader(f)) {
            //加上一個(gè)是否拷貝的開(kāi)關(guān).
            boolean isCopy=true;
            //還需要準(zhǔn)備一個(gè)結(jié)果保存
            StringBuilder content=new StringBuilder();
            while (true){
                //此處的read的返回值是int,不是char
                //如果讀到文件末尾,就會(huì)返回-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=false;
                            continue;
                        }
                        //其他字符直接拷貝
                        if(c=='\n'||c=='\r'){
                            c=' ';
                        }
                        content.append(c);
                    }else{
                        if(c=='>'){
                            isCopy=true;
                        }
                    }
            }

            return  content.toString();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return "";
    }
    private void parseHTML (File f){
        //解析出標(biāo)題
          String title=parseTitle(f);
        //解析出對(duì)應(yīng)的url
          String url=parseUrl(f);
        //解析出對(duì)應(yīng)的正文
        try {
            String content=parseContent(f);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
      //第一個(gè)參數(shù)表示從哪里開(kāi)始遍歷 //第二個(gè)表示結(jié)果。
      private void enumFile(String inputPath,ArrayList<File>fileList){
         File rootPath=new File(inputPath);
         //listFiles 能夠獲取到一層目錄下的文件
        File[] files= rootPath.listFiles();
         for(File f:files){
             //根據(jù)當(dāng)前f的類(lèi)型判斷是否遞歸。
             //如果f是一個(gè)普通文件,就把f加入到fileList里面
             //如果不是就調(diào)用遞歸
             if(f.isDirectory()){
                 enumFile(f.getAbsolutePath(),fileList);
             }else {
                 if(f.getAbsolutePath().endsWith(".html"))
                 fileList.add(f);
             }
         }
      }
    public static void main(String[] args) {
        //通過(guò)main方法來(lái)實(shí)現(xiàn)整個(gè)制作索引的過(guò)程
        Parser parser=new Parser();
        parser.run();
    }
}

圖片

說(shuō)個(gè)題外話,鳥(niǎo)哥是個(gè)比較喜歡折騰的程序員,業(yè)余喜歡開(kāi)發(fā)自己網(wǎng)站、小程序、App等,這些東西統(tǒng)統(tǒng)離不開(kāi)服務(wù)器!最近就圍繞服務(wù)器的主題創(chuàng)建了一個(gè)微信群,喜歡玩服務(wù)器或者想自己開(kāi)發(fā)一款產(chǎn)品的讀者可以進(jìn)來(lái),相互學(xué)習(xí)交流!群通知中給大家分享了一套搭建服務(wù)器的視頻教程哦。非常適合新手學(xué)習(xí)!我也會(huì)時(shí)不時(shí)的帶大家擼點(diǎn)和服務(wù)器相關(guān)的優(yōu)惠券!不感興趣,不喜歡折騰的就沒(méi)必要湊著鬧了!


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多