<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    華山論劍

    一心一意做技術!

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      31 Posts :: 0 Stories :: 447 Comments :: 0 Trackbacks
      Lucene是apache軟件基金會 jakarta項目組的一個子項目,是一個開放源代碼的全文檢索引擎工具包及架構,提供了完整的查詢引擎和索引引擎,實現了一些通用的分詞算法,預留很多詞法分析器接口。本文以myrss.easyjf.com網站系統中使用Lucene實現全文檢索的代碼為例,簡單演示Lucene在實際項目中的應用。
      使用Lucene實現全文檢索,主要有下面三個步驟:
      1、建立索引庫:根據網站新聞信息庫中的已有的數據資料建立Lucene索引文件。
      2、通過索引庫搜索:有了索引后,即可使用標準的詞法分析器或直接的詞法分析器實現進行全文檢索。
      3、維護索引庫:網站新聞信息庫中的信息會不斷的變動,包括新增、修改及刪除等,這些信息的變動都需要進一步反映到Lucene索引文件中。
    ??? 下面是myrss.easyjf.com相關代碼!
    ?
    ?一、索引管理(建立及維護)
      索引管理類MyRssIndexManage主要實現根據網站信息庫中的數據建立索引,維護索引等。由于索引的過程需要消耗一定的時間,因此,索引管理類實現Runnable接口,使得我們可以在程序中開新線程來運行。
    package com.easyjf.lucene;
    import java.util.Date;
    import java.util.List;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.document.Field;
    import org.apache.lucene.index.IndexReader;
    import org.apache.lucene.index.IndexWriter;
    import org.apache.lucene.queryParser.MultiFieldQueryParser;
    import org.apache.lucene.queryParser.QueryParser;
    import org.apache.lucene.search.Hits;
    import org.apache.lucene.search.IndexSearcher;
    import org.apache.lucene.search.Query;
    import org.apache.lucene.search.Searcher;
    import com.easyjf.dbo.EasyJDB;
    import com.easyjf.news.business.NewsDir;
    import com.easyjf.news.business.NewsDoc;
    import com.easyjf.news.business.NewsUtil;
    import com.easyjf.web.tools.IPageList;
    public class MyRssIndexManage implements Runnable {
    ?private String indexDir;
    ?private String indexType="add";?
    ?public void run() {
    ??// TODO Auto-generated method stub
    ??if("add".equals(indexType))
    ???normalIndex();
    ??else if ("init".equals(indexType)) reIndexAll();
    ?}
    ?public void normalIndex()
    ?{
    ??try{
    ???Date start = new Date();
    ???int num=0;
    ???IndexWriter writer=new IndexWriter(indexDir,new StandardAnalyzer(),false);???
    ???//NewsDir dir=NewsDir.readBySn();???
    ???String scope="(needIndex<2) or(needIndex is null)";
    ???IPageList pList=NewsUtil.pageList(scope,1,50);
    ???for(int p=0;p<pList.getPages();p++)
    ???{
    ???pList=NewsUtil.pageList(scope,p,100);
    ???List list=pList.getResult();
    ???for(int i=0;i<list.size();i++)
    ???{
    ????NewsDoc doc=(NewsDoc)list.get(i);?????
    ????writer.addDocument(newsdoc2lucenedoc(doc));???
    ????num++;
    ???}
    ???}
    ???writer.optimize();
    ???writer.close();
    ???EasyJDB.getInstance().execute("update NewsDoc set needIndex=2 where "+scope);
    ???Date end = new Date();
    ???System.out.print("新增索引"+num+"條信息,一共花:"+(end.getTime() - start.getTime())/60000+"分鐘!");??
    ???}
    ???catch(Exception e)
    ???{
    ????e.printStackTrace();
    ???}
    ?}
    ?public void reIndexAll()
    ?{
    ??try{
    ???Date start = new Date();
    ???int num=0;
    ???IndexWriter writer=new IndexWriter(indexDir,new StandardAnalyzer(),true);???
    ???NewsDir dir=NewsDir.readBySn("easyjf");???
    ???IPageList pList=NewsUtil.pageList(dir,1,50);
    ???for(int p=0;p<pList.getPages();p++)
    ???{
    ???pList=NewsUtil.pageList(dir,p,100);
    ???List list=pList.getResult();
    ???for(int i=0;i<list.size();i++)
    ???{????
    ????NewsDoc doc=(NewsDoc)list.get(i);?????
    ????writer.addDocument(newsdoc2lucenedoc(doc));
    ????num++;
    ???}
    ???}
    ???writer.optimize();
    ???writer.close();
    ???EasyJDB.getInstance().execute("update NewsDoc set needIndex=2 where dirPath like 'easyjf%'");
    ???Date end = new Date();
    ???System.out.print("全部重新做了一次索引,一共處理了"+num+"條信息,花:"+(end.getTime() - start.getTime())/60000+"分鐘!");??
    ???}
    ???catch(Exception e)
    ???{
    ????e.printStackTrace();
    ???}
    ?}
    ?private Document newsdoc2lucenedoc(NewsDoc doc)
    ?{
    ??Document lDoc=new Document();?????
    ??lDoc.add(new Field("title",doc.getTitle(),Field.Store.YES,Field.Index.TOKENIZED));
    ??lDoc.add(new Field("content",doc.getContent(),Field.Store.YES,Field.Index.TOKENIZED));
    ??lDoc.add(new Field("url",doc.getRemark(),Field.Store.YES,Field.Index.NO));????
    ??lDoc.add(new Field("cid",doc.getCid(),Field.Store.YES,Field.Index.NO));
    ??lDoc.add(new Field("source",doc.getSource(),Field.Store.YES,Field.Index.NO));
    ??lDoc.add(new Field("inputTime",doc.getInputTime().toString(),Field.Store.YES,Field.Index.NO));
    ??return lDoc;
    ?}
    ?public String getIndexDir() {
    ??return indexDir;
    ?}
    ?public void setIndexDir(String indexDir) {
    ??this.indexDir = indexDir;
    ?}
    ?
    ?public String getIndexType() {
    ??return indexType;
    ?}
    ?public void setIndexType(String indexType) {
    ??this.indexType = indexType;
    ?}
    }
    ?
    二、使用Lucene實現全文搜索
    ?? 下面是MyRssSearch類的源碼,該類主要實現使用Lucene中Searcher及QueryParser實現從索引庫中搜索關鍵詞。
    package com.easyjf.lucene;
    import java.util.List;
    import org.apache.lucene.analysis.standard.StandardAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.index.IndexReader;
    import org.apache.lucene.queryParser.MultiFieldQueryParser;
    import org.apache.lucene.queryParser.QueryParser;
    import org.apache.lucene.search.Hits;
    import org.apache.lucene.search.IndexSearcher;
    import org.apache.lucene.search.Query;
    import org.apache.lucene.search.Searcher;
    import com.easyjf.search.MyRssUtil;
    import com.easyjf.search.SearchContent;
    import com.easyjf.web.tools.IPageList;
    import com.easyjf.web.tools.PageList;
    public class MyRssSearch {
    ?private String indexDir;?
    ?IndexReader ir;
    ?Searcher search;
    ?public IPageList search(String key,int pageSize,int currentPage)
    ?{
    ??IPageList pList=new PageList(new HitsQuery(doSearch(key)));
    ??pList.doList(pageSize,currentPage,"","",null);
    ??if(pList!=null)
    ??{??
    ???List list=pList.getResult();?
    ???if(list!=null){
    ???for(int i=0;i<list.size();i++)
    ???{
    ????list.set(i,lucene2searchObj((Document)list.get(i),key));
    ???}
    ???}
    ??}
    ??try{
    ??if(search!=null)search.close();
    ??if(ir!=null)ir.close();
    ??}
    ??catch(Exception e)
    ??{
    ???e.printStackTrace();
    ??}
    ??return pList;
    ?}
    ?private SearchContent lucene2searchObj(Document doc,String key)
    ?{
    ??SearchContent searchObj=new SearchContent();
    ??String title=doc.getField("title").stringValue();
    ??searchObj.setTitle(title.replaceAll(key,"<font color=red>"+key+"</font>"));??
    ??searchObj.setTvalue(doc.getField("cid").stringValue());??
    ??searchObj.setUrl(doc.getField("url").stringValue());
    ??searchObj.setSource(doc.getField("source").stringValue());??
    ??searchObj.setLastUpdated(doc.getField("inputTime").stringValue());?
    ??searchObj.setIntro(MyRssUtil.content2intro(doc.getField("content").stringValue(),key));??
    ??return searchObj;
    ?}
    ?public Hits doSearch(String key)
    ?{
    ??Hits hits=null;
    ??try{
    ??ir=IndexReader.open(indexDir);
    ??search=new IndexSearcher(ir);??
    ??String fields[]={"title","content"};
    ??QueryParser parser=new MultiFieldQueryParser(fields,new StandardAnalyzer());
    ??Query query=parser.parse(key);
    ??hits=search.search(query);???
    ??}
    ??catch(Exception e)
    ??{
    ???e.printStackTrace();
    ??}
    ??//System.out.println("搜索結果:"+hits.length());
    ??return hits;
    ?}
    ?
    ?public String getIndexDir() {
    ??return indexDir;
    ?}
    ?public void setIndexDir(String indexDir) {
    ??this.indexDir = indexDir;
    ?}
    }
      在上面的代碼中,search方法返回一個封裝了分頁查詢結果的IPageList,IPageList是EasyJWeb Tools業務引擎中的分頁引擎,對于IPageList的使用,請看本人寫的這篇文章《EasyJWeb Tools中業務引擎分頁的設計實現》:

      我們針對Lucene的的查詢結果Hits結構,寫了一個查詢器HitsQuery。代碼如下所示:
    package com.easyjf.lucene;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    import org.apache.lucene.search.Hits;
    import com.easyjf.web.tools.IQuery;
    public class HitsQuery implements IQuery {
    ?private int begin=0;
    ?private int max=0;
    ?private Hits hits;
    ?public HitsQuery()
    ?{
    ??
    ?}
    ?public HitsQuery(Hits hits)
    ?{
    ??if(hits!=null)
    ??{
    ???this.hits=hits;???
    ???this.max=hits.length();
    ??}
    ?}
    ?public int getRows(String arg0) {
    ??// TODO Auto-generated method stub
    ??return (hits==null?0:hits.length());
    ?}
    ?public List getResult(String arg0) {
    ??// TODO Auto-generated method stub
    ??List list=new ArrayList();??
    ??for(int i=begin;i<(begin+max)&&(i<hits.length());i++)
    ??{
    ???try{
    ???list.add(hits.doc(i));
    ???}
    ???catch(Exception e)
    ???{
    ????e.printStackTrace();
    ???}
    ??}
    ??return list;
    ?}
    ?public void setFirstResult(int begin) {
    ??// TODO Auto-generated method stub
    ??this.begin=begin;
    ?}
    ?public void setMaxResults(int max) {
    ??// TODO Auto-generated method stub
    ??this.max=max;
    ?}
    ?public void setParaValues(Collection arg0) {
    ??// TODO Auto-generated method stub
    ??
    ?}
    ?public List getResult(String condition, int begin, int max) {
    ??// TODO Auto-generated method stub
    ??if((begin>=0)&&(begin<max))this.begin=begin;
    ??if(!(max>hits.length()))this.max=max;
    ??return getResult(condition);
    ?}
    }
    ?
    三、Web調用
      下面我們來看看在Web中如果調用商業邏輯層的全文檢索功能。下面是處理用戶請請的Action中關于搜索部分的源碼:
    package com.easyjf.news.action;
    public class SearchAction implements IWebAction {?
    public Page doSearch(WebForm form,Module module)throws Exception
    {
    ?String key=CommUtil.null2String(form.get("v"));?
    ?key=URLDecoder.decode(URLEncoder.encode(key,"ISO8859_1"),"utf-8");
    ?form.set("v",key);
    ?form.addResult("v2",URLEncoder.encode(key,"utf-8"));
    ?if(key.getBytes().length>2){
    ?String orderBy=CommUtil.null2String(form.get("order"));?
    ?int currentPage=CommUtil.null2Int(form.get("page"));
    ?int pageSize=CommUtil.null2Int(form.get("pageSize"));??
    ?if(currentPage<1)currentPage=1;
    ?if(pageSize<1)pageSize=15;
    ?SearchEngine search=new SearchEngine(key,orderBy,pageSize,currentPage);
    ?search.getLuceneSearch().setIndexDir(Globals.APP_BASE_DIR+"/WEB-INF/index");
    ?search.doSearchByLucene();
    ?IPageList pList=search.getResult();
    ?if(pList!=null && pList.getRowCount()>0){
    ??form.addResult("list",pList.getResult());
    ??form.addResult("pages",new Integer(pList.getPages()));
    ??form.addResult("rows",new Integer(pList.getRowCount()));
    ??form.addResult("page",new Integer(pList.getCurrentPage()));
    ??form.addResult("gotoPageHTML",CommUtil.showPageHtml(pList.getCurrentPage(),pList.getPages()));
    ??}
    ?else
    ?{
    ??form.addResult("notFound","true");//找不到數據
    ?}?
    ?}
    ?else
    ??form.addResult("errMsg","您輸入的關鍵字太短!");
    ?form.addResult("hotSearch",SearchEngine.getHotSearch(20));
    ?return null;
    }
    }
    其中調用的SearchEngine類中有關Lucene部分的源碼:
    public class SearchEngine {
    private MyRssSearch luceneSearch=new MyRssSearch();
    public void doSearchByLucene()
    {?
    ?SearchKey keyObj=readCache();?
    ?if(keyObj!=null){
    ??result=luceneSearch.search(key,pageSize,currentPage);??
    ??if(updateStatus){
    ??keyObj.setReadTimes(new Integer(keyObj.getReadTimes().intValue()+1));
    ??keyObj.update();
    ??}??
    ?}
    ?else//緩存中沒有該關鍵字信息,生成關鍵字搜索結果
    ?{?
    ??keyObj=new SearchKey();
    ??keyObj.setTitle(key);
    ??keyObj.setLastUpdated(new Date());
    ??keyObj.setReadTimes(new Integer(1));
    ??keyObj.setStatus(new Integer(0));
    ??keyObj.setSequence(new Integer(1));
    ??keyObj.setVdate(new Date());
    ??keyObj.save();?
    ??result=luceneSearch.search(key,pageSize,currentPage);;?
    ??
    ?}?
    }
    }
    ?
    四、程序演示效果
      這是EasyJF團隊官方網站上提供java信息搜索的myrss.easyjf.com的運行效果。
    ????

    ?
    posted on 2006-07-03 11:51 大峽 閱讀(3847) 評論(4)  編輯  收藏

    Feedback

    # re: lucene全文檢索應用示例及代碼簡析 2006-07-05 22:31 獵手
    呵呵,非常好啊,
    請問當添加,修改,刪除數據庫中的數據后,大俠是如何及時的處理索引,能不能說說你的實現思路,謝謝。
    很想看看你的代碼,如果可以的話,能給我發一份么?我的郵箱是jsrmade@126.com  回復  更多評論
      

    # re: lucene全文檢索應用示例及代碼簡析 2008-04-23 09:49 卡片
    給我發一份吧,郵箱是liangyao_86@163.com  回復  更多評論
      

    # re: lucene全文檢索應用示例及代碼簡析 2008-04-25 01:05 啊新
    為什么要對Hits 封裝成HitsQuery,看上去像是給查詢封裝,但我覺得應該是給查詢到的結果封裝。不太明白,請解釋一下,謝謝!  回復  更多評論
      

    # re: lucene全文檢索應用示例及代碼簡析 2010-09-26 09:13 maxin
    挺好的,佩服!  回復  更多評論
      


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲国产香蕉碰碰人人| 亚洲国产精品人人做人人爽| 亚洲av日韩av高潮潮喷无码| CAOPORM国产精品视频免费| 国产一级理论免费版| 小说专区亚洲春色校园| 免费国产不卡午夜福在线| 亚洲精品GV天堂无码男同| 狠狠久久永久免费观看| 婷婷国产偷v国产偷v亚洲| 亚洲欧洲国产成人综合在线观看| 麻豆91免费视频| 亚洲毛片av日韩av无码| 中文字幕免费在线视频| 亚洲自偷自偷在线成人网站传媒 | 亚洲国产精品SSS在线观看AV| 国产精品青草视频免费播放| 国产亚洲精品精品国产亚洲综合| 黄网站免费在线观看| 亚洲高清免费在线观看| aa级一级天堂片免费观看| 亚洲爆乳无码专区www| 亚洲毛片网址在线观看中文字幕 | 亚洲色偷偷偷鲁综合| 久久永久免费人妻精品下载| 亚洲午夜精品一区二区公牛电影院| 国产99视频精品免费观看7| 香蕉视频亚洲一级| 亚洲色欲色欲www在线丝| 91免费人成网站在线观看18| 亚洲国产aⅴ成人精品无吗| 亚洲AⅤ无码一区二区三区在线| 国产一区二区三区免费观在线| 亚洲资源在线视频| 日本免费网站观看| 国色精品va在线观看免费视频 | 亚洲免费福利在线视频| 国产日产亚洲系列最新| 亚洲一区二区三区免费观看| 免费看黄福利app导航看一下黄色录像 | 色婷婷亚洲十月十月色天 |