亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

java實(shí)現(xiàn)簡(jiǎn)單的搜索引擎

 更新時(shí)間:2016年02月01日 15:41:19   作者:xiaojimanman  
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單的搜索引擎的相關(guān)資料,需要的朋友可以參考下

記得java老師曾經(jīng)說過百度的一個(gè)面試題目,大概意思是“有1W條無序的記錄,如何從其中快速的查找到自己想要的記錄”。這個(gè)就相當(dāng)于一個(gè)簡(jiǎn)單的搜索引擎。最近在整理這一年的工作中,自己竟然已經(jīng)把這個(gè)實(shí)現(xiàn)了,今天對(duì)其進(jìn)一步的抽象,和大家分享下。

先寫具體的實(shí)現(xiàn)代碼,具體的實(shí)現(xiàn)思路和邏輯寫在代碼之后。

搜索時(shí)用于排序的Bean

 /**  
 *@Description:   
 */  
package cn.lulei.search.engine.model;  
  
public class SortBean { 
  private String id; 
  private int times; 
   
  public String getId() { 
    return id; 
  } 
  public void setId(String id) { 
    this.id = id; 
  } 
  public int getTimes() { 
    return times; 
  } 
  public void setTimes(int times) { 
    this.times = times; 
  } 
} 

構(gòu)造的搜索數(shù)據(jù)結(jié)構(gòu)以及簡(jiǎn)單的搜索算法

 /**  
 *@Description:   
 */  
package cn.lulei.search.engine;  
 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.HashMap; 
import java.util.HashSet; 
import java.util.List; 
 
import cn.lulei.search.engine.model.SortBean; 
  
public class SerachBase { 
  //details 存儲(chǔ)搜素對(duì)象的詳細(xì)信息,其中key作為區(qū)分Object的唯一標(biāo)識(shí) 
  private HashMap<String, Object> details = new HashMap<String, Object>(); 
  //對(duì)于參與搜索的關(guān)鍵詞,這里采用的稀疏數(shù)組存儲(chǔ),也可以采用HashMap來存儲(chǔ),定義格式如下 
  //private static HashMap<Integer, HashSet<String>> keySearch = new HashMap<Integer, HashSet<String>>(); 
  //HashMap中額key值相當(dāng)于稀疏數(shù)組中的下標(biāo),value相當(dāng)于稀疏數(shù)組在該位置的值 
  private final static int maxLength = Character.MAX_VALUE; 
  @SuppressWarnings("unchecked") 
  private HashSet<String>[] keySearch = new HashSet[maxLength]; 
   
  /** 
   *@Description: 實(shí)現(xiàn)單例模式,采用Initialization on Demand Holder加載 
   *@Version:1.1.0 
   */ 
  private static class lazyLoadSerachBase { 
    private static final SerachBase serachBase = new SerachBase(); 
  } 
   
  /** 
   * 這里把構(gòu)造方法設(shè)置成私有為的是單例模式 
   */ 
  private SerachBase() { 
     
  } 
   
  /** 
   * @return  
   * @Description: 獲取單例 
   */ 
  public static SerachBase getSerachBase() { 
    return lazyLoadSerachBase.serachBase; 
  } 
   
  /** 
   * @param id 
   * @return  
   * @Description: 根據(jù)id獲取詳細(xì) 
   */ 
  public Object getObject(String id) { 
    return details.get(id); 
  } 
   
  /** 
   * @param ids 
   * @return  
   * @Description: 根據(jù)ids獲取詳細(xì),id之間用","隔開 
   */ 
  public List<Object> getObjects(String ids) { 
    if (ids == null || "".equals(ids)) { 
      return null; 
    } 
    List<Object> objs = new ArrayList<Object>(); 
    String[] idArray = ids.split(","); 
    for (String id : idArray) { 
      objs.add(getObject(id)); 
    } 
    return objs; 
  } 
   
  /** 
   * @param key 
   * @return  
   * @Description: 根據(jù)搜索詞查找對(duì)應(yīng)的id,id之間用","分割 
   */ 
  public String getIds(String key) { 
    if (key == null || "".equals(key)) { 
      return null; 
    } 
    //查找 
    //idTimes存儲(chǔ)搜索詞每個(gè)字符在id中是否出現(xiàn) 
    HashMap<String, Integer> idTimes = new HashMap<String, Integer>(); 
    //ids存儲(chǔ)出現(xiàn)搜索詞中的字符的id 
    HashSet<String> ids = new HashSet<String>(); 
     
    //從搜索庫中去查找 
    for (int i = 0; i < key.length(); i++) { 
      int at = key.charAt(i); 
      //搜索詞庫中沒有對(duì)應(yīng)的字符,則進(jìn)行下一個(gè)字符的匹配 
      if (keySearch[at] == null) { 
        continue; 
      } 
      for (Object obj : keySearch[at].toArray()) { 
        String id = (String) obj; 
        int times = 1; 
        if (ids.contains(id)) { 
          times += idTimes.get(id); 
          idTimes.put(id, times); 
        } else { 
          ids.add(id); 
          idTimes.put(id, times); 
        } 
      } 
    } 
     
    //使用數(shù)組排序 
    List<SortBean> sortBeans = new ArrayList<SortBean>(); 
    for (String id : ids) { 
      SortBean sortBean = new SortBean(); 
      sortBeans.add(sortBean); 
      sortBean.setId(id); 
      sortBean.setTimes(idTimes.get(id)); 
    } 
    Collections.sort(sortBeans, new Comparator<SortBean>(){ 
      public int compare(SortBean o1, SortBean o2){ 
        return o2.getTimes() - o1.getTimes(); 
      } 
    }); 
     
    //構(gòu)建返回字符串 
    StringBuffer sb = new StringBuffer(); 
    for (SortBean sortBean : sortBeans) { 
      sb.append(sortBean.getId()); 
      sb.append(","); 
    } 
     
    //釋放資源 
    idTimes.clear(); 
    idTimes = null; 
    ids.clear(); 
    ids = null; 
    sortBeans.clear(); 
    sortBeans = null; 
     
    //返回 
    return sb.toString(); 
  } 
   
  /** 
   * @param id 
   * @param searchKey 
   * @param obj 
   * @Description: 添加搜索記錄 
   */ 
  public void add(String id, String searchKey, Object obj) { 
    //參數(shù)有部分為空,不加載 
    if (id == null || searchKey == null || obj == null) { 
      return; 
    } 
    //保存對(duì)象 
    details.put(id, obj); 
    //保存搜索詞 
    addSearchKey(id, searchKey); 
  } 
   
  /** 
   * @param id 
   * @param searchKey 
   * @Description: 將搜索詞加入到搜索域中 
   */ 
  private void addSearchKey(String id, String searchKey) { 
    //參數(shù)有部分為空,不加載 
    //這里是私有方法,可以不做如下判斷,但為了設(shè)計(jì)規(guī)范,還是加上 
    if (id == null || searchKey == null) { 
      return; 
    } 
    //下面采用的是字符分詞,這里也可以使用現(xiàn)在成熟的其他分詞器 
    for (int i = 0; i < searchKey.length(); i++) { 
      //at值相當(dāng)于是數(shù)組的下標(biāo),id組成的HashSet相當(dāng)于數(shù)組的值 
      int at = searchKey.charAt(i); 
      if (keySearch[at] == null) { 
        HashSet<String> value = new HashSet<String>(); 
        keySearch[at] = value; 
      } 
      keySearch[at].add(id); 
    } 
  } 
   
   
 
} 

測(cè)試用例:

 /**  
 *@Description:   
 */  
package cn.lulei.search.engine.test;  
 
import java.util.List; 
 
import cn.lulei.search.engine.SerachBase; 
  
public class Test { 
  public static void main(String[] args) { 
    // TODO Auto-generated method stub  
    SerachBase serachBase = SerachBase.getSerachBase(); 
    serachBase.add("1", "你好!", "你好!"); 
    serachBase.add("2", "你好!我是張三。", "你好!我是張三。"); 
    serachBase.add("3", "今天的天氣挺好的。", "今天的天氣挺好的。"); 
    serachBase.add("4", "你是誰?", "你是誰?"); 
    serachBase.add("5", "高數(shù)這門學(xué)科很難", "高數(shù)確實(shí)很難。"); 
    serachBase.add("6", "測(cè)試", "上面的只是測(cè)試"); 
    String ids = serachBase.getIds("你的高數(shù)"); 
    System.out.println(ids); 
    List<Object> objs = serachBase.getObjects(ids); 
    if (objs != null) { 
      for (Object obj : objs) { 
        System.out.println((String) obj); 
      } 
    } 
  } 
 
} 

測(cè)試輸出結(jié)果如下:

5,3,2,1,4,
高數(shù)確實(shí)很難。
今天的天氣挺好的。
你好!我是張三。
你好!
你是誰?

這樣一個(gè)簡(jiǎn)單的搜索引擎也就算是完成了。

問題一:這里面的分詞采用的是字符分詞,對(duì)漢語的處理還是挺不錯(cuò)的,但是對(duì)英文的處理就很弱。

改進(jìn)方法:采用現(xiàn)在成熟的分詞方法,比如IKAnalyzer、StandardAnalyzer等,這樣修改,keySearch的數(shù)據(jù)結(jié)構(gòu)就需要做下修改,可以修改為 private HashMap<String, String>[] keySearch = new HashMap[maxLength]; 其中key存儲(chǔ)分的詞元,value存儲(chǔ)唯一標(biāo)識(shí)id。

問題二:本文實(shí)現(xiàn)的搜索引擎對(duì)詞元并沒有像lucene設(shè)置權(quán)重,只是簡(jiǎn)單的判斷詞元是否在對(duì)象中出現(xiàn)。

改進(jìn)方法:暫無。添加權(quán)重處理,使數(shù)據(jù)結(jié)構(gòu)更加復(fù)雜,所以暫時(shí)沒有對(duì)其做處理,在今后的文章中會(huì)實(shí)現(xiàn)權(quán)重的處理。

下面就簡(jiǎn)單的介紹一下搜索引擎的實(shí)現(xiàn)思路

在SerachBase類中設(shè)置details和keySearch兩個(gè)屬性,details用于存儲(chǔ)Object的詳細(xì)信息,keySearch用于對(duì)搜索域做索引。details數(shù)據(jù)格式為HashMap,keySearch的數(shù)據(jù)格式為稀疏數(shù)組(也可以為HashMap,HashMap中額key值相當(dāng)于稀疏數(shù)組中的下標(biāo),value相當(dāng)于稀疏數(shù)組在該位置的值)。

對(duì)于details我就不做太多的介紹。

keySearch中數(shù)組下標(biāo)(如用HashMap就是key)的計(jì)算方法是獲取詞元的第一個(gè)字符int值(因?yàn)楸疚牡姆衷~采用的是字符分詞,所以一個(gè)字符就是一個(gè)詞元),該int值就是數(shù)組的下標(biāo),相應(yīng)的數(shù)組值就是Object的唯一標(biāo)識(shí)。這樣keySearch的數(shù)據(jù)結(jié)構(gòu)就如下圖

因此想添加新紀(jì)錄的時(shí)候只需要調(diào)用add方法即可。

對(duì)于搜索的實(shí)現(xiàn)邏輯和上面的keySearch類似。對(duì)于id的搜索直接使用HashMap的get方法即可。對(duì)于搜索詞的一個(gè)搜索,整體的過程也是采用先分詞、其次查詢、最后排序。當(dāng)然這里面的分詞要和創(chuàng)建采用的分詞要一致(即創(chuàng)建的時(shí)候采用字符分詞,查找的時(shí)候也采用字符分詞)。

在getIds方法中,HashMap<String, Integer> idTimes = new HashMap<String, Integer>();idTimes 變量用來存儲(chǔ)搜索詞中的詞元有多少個(gè)在keySearch中出現(xiàn),key值為唯一標(biāo)識(shí)id,value為出現(xiàn)的詞元個(gè)數(shù)。HashSet<String> ids = new HashSet<String>(); ids變量用來存儲(chǔ)出現(xiàn)的詞元的ids。這樣搜索的復(fù)雜度就是搜索詞的詞元個(gè)數(shù)n。獲得包含詞元的ids,構(gòu)造SortBean數(shù)組,對(duì)其排序,排序規(guī)則是出現(xiàn)詞元個(gè)數(shù)的降序排列。最后返回ids字符串,每個(gè)id用","分割。如要獲取詳細(xì)信息
再使用getObjects方法即可。

上述的只是一個(gè)簡(jiǎn)單的搜索引擎,并沒有設(shè)計(jì)太多的計(jì)算方法,希望對(duì)大家的學(xué)習(xí)有所啟發(fā)。

相關(guān)文章

  • SpringMVC如何域?qū)ο蠊蚕頂?shù)據(jù)

    SpringMVC如何域?qū)ο蠊蚕頂?shù)據(jù)

    在Spring MVC中,可以使用域?qū)ο髞砉蚕頂?shù)據(jù),域?qū)ο笫且粋€(gè)Map類型的對(duì)象,可以在請(qǐng)求處理方法之間共享數(shù)據(jù),本文給大家介紹SpringMVC 域?qū)ο蠊蚕頂?shù)據(jù)的示例代碼,一起看看吧
    2023-09-09
  • Java Kafka 消費(fèi)積壓監(jiān)控的示例代碼

    Java Kafka 消費(fèi)積壓監(jiān)控的示例代碼

    這篇文章主要介紹了Java Kafka 消費(fèi)積壓監(jiān)控,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • SSM框架搭建圖文教程(推薦)

    SSM框架搭建圖文教程(推薦)

    下面小編就為大家?guī)硪黄猄SM框架搭建圖文教程(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • Java程序員應(yīng)該遵守的10條紀(jì)律

    Java程序員應(yīng)該遵守的10條紀(jì)律

    Java程序員有許多應(yīng)遵循的守則或最佳實(shí)踐方式。本文概述了每個(gè)開發(fā)者最應(yīng)該遵循的10條守則或戒律,如果不遵循它們,將會(huì)導(dǎo)致災(zāi)難性后果。
    2015-09-09
  • SpringBoot 整合WebSocket 前端 uniapp 訪問的詳細(xì)方法

    SpringBoot 整合WebSocket 前端 uniapp 訪問的詳細(xì)方法

    這篇文章主要介紹了SpringBoot 整合WebSocket 前端 uniapp 訪問的詳細(xì)方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • java 中List刪除實(shí)例詳解

    java 中List刪除實(shí)例詳解

    這篇文章主要介紹了java 中List刪除實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 詳解Spring配置及事務(wù)的使用

    詳解Spring配置及事務(wù)的使用

    這篇文章主要介紹了詳解Spring配置及事務(wù)的使用,文中附含詳細(xì)的示例代碼說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-09-09
  • SpringBoot實(shí)現(xiàn)異步消息處理的代碼示例

    SpringBoot實(shí)現(xiàn)異步消息處理的代碼示例

    在現(xiàn)代應(yīng)用程序中,異步消息處理是一項(xiàng)至關(guān)重要的任務(wù)。它可以提高應(yīng)用程序的性能、可伸縮性和可靠性,同時(shí)也可以提供更好的用戶體驗(yàn),本文將介紹如何使用Spring Boot實(shí)現(xiàn)異步消息處理,并提供相應(yīng)的代碼示例
    2023-06-06
  • java解析XML幾種方式小結(jié)

    java解析XML幾種方式小結(jié)

    本文給大家匯總了4種java解析XML的方法,結(jié)合具體的示例,非常的詳細(xì),有需要的小伙伴可以參考下
    2016-01-01
  • SpringBoot中的配置文件加載優(yōu)先級(jí)詳解

    SpringBoot中的配置文件加載優(yōu)先級(jí)詳解

    這篇文章主要介紹了SpringBoot中的配置文件加載優(yōu)先級(jí)詳解,springboot啟動(dòng)會(huì)掃描以下位置的application.properties或者application.yml文件作為Spring?boot的默認(rèn)配置文件,需要的朋友可以參考下
    2024-01-01

最新評(píng)論