szhswl
宋针还的个人空间
使用Lucene实现全文检索,主要有下面三个步骤:
  1、建立索引库:根据网站新闻信息库中的已有的数据资料建立Lucene索引文件。
  2、通过索引库搜索:有了索引后,即可使用标准的词法分析器或直接的词法分析器实现进行全文检索。
  3、维护索引库:网站新闻信息库中的信息会不断的变动,包括新增、修改及删除等,这些信息的变动都需要进一步反映到Lucene索引文件中。
    下面是myrss.easyjf.com相关代码!
 
 一、索引管理(建立及维护)
  索引管理类MyRssIndexManage主要实现根据网站信息库中的数据建立索引,维护索引等。由于索引的过程需要消耗一定的时间,因此,索引管理类实现Runnable接口,使得我们可以在程序中开新线程来运行。
  1package com.easyjf.lucene;
  2import java.util.Date;
  3import java.util.List;
  4import org.apache.lucene.analysis.standard.StandardAnalyzer;
  5import org.apache.lucene.document.Document;
  6import org.apache.lucene.document.Field;
  7import org.apache.lucene.index.IndexReader;
  8import org.apache.lucene.index.IndexWriter;
  9import org.apache.lucene.queryParser.MultiFieldQueryParser;
 10import org.apache.lucene.queryParser.QueryParser;
 11import org.apache.lucene.search.Hits;
 12import org.apache.lucene.search.IndexSearcher;
 13import org.apache.lucene.search.Query;
 14import org.apache.lucene.search.Searcher;
 15import com.easyjf.dbo.EasyJDB;
 16import com.easyjf.news.business.NewsDir;
 17import com.easyjf.news.business.NewsDoc;
 18import com.easyjf.news.business.NewsUtil;
 19import com.easyjf.web.tools.IPageList;
 20public class MyRssIndexManage implements Runnable {
 21 private String indexDir;
 22 private String indexType="add"
 23 public void run() {
 24  // TODO Auto-generated method stub
 25  if("add".equals(indexType))
 26   normalIndex();
 27  else if ("init".equals(indexType)) reIndexAll();
 28 }

 29 public void normalIndex()
 30 {
 31  try{
 32   Date start = new Date();
 33   int num=0;
 34   IndexWriter writer=new IndexWriter(indexDir,new StandardAnalyzer(),false);   
 35   //NewsDir dir=NewsDir.readBySn();   
 36   String scope="(needIndex<2) or(needIndex is null)";
 37   IPageList pList=NewsUtil.pageList(scope,1,50);
 38   for(int p=0;p   {
 39   pList=NewsUtil.pageList(scope,p,100);
 40   List list=pList.getResult();
 41   for(int i=0;i   {
 42    NewsDoc doc=(NewsDoc)list.get(i);     
 43    writer.addDocument(newsdoc2lucenedoc(doc));   
 44    num++;
 45   }

 46   }

 47   writer.optimize();
 48   writer.close();
 49   EasyJDB.getInstance().execute("update NewsDoc set needIndex=2 where "+scope);
 50   Date end = new Date();
 51   System.out.print("新增索引"+num+"条信息,一共花:"+(end.getTime() - start.getTime())/60000+"分钟!");  
 52   }

 53   catch(Exception e)
 54   {
 55    e.printStackTrace();
 56   }

 57 }

 58 public void reIndexAll()
 59 {
 60  try{
 61   Date start = new Date();
 62   int num=0;
 63   IndexWriter writer=new IndexWriter(indexDir,new StandardAnalyzer(),true);   
 64   NewsDir dir=NewsDir.readBySn("easyjf");   
 65   IPageList pList=NewsUtil.pageList(dir,1,50);
 66   for(int p=0;p   {
 67   pList=NewsUtil.pageList(dir,p,100);
 68   List list=pList.getResult();
 69   for(int i=0;i   {    
 70    NewsDoc doc=(NewsDoc)list.get(i);     
 71    writer.addDocument(newsdoc2lucenedoc(doc));
 72    num++;
 73   }

 74   }

 75   writer.optimize();
 76   writer.close();
 77   EasyJDB.getInstance().execute("update NewsDoc set needIndex=2 where dirPath like 'easyjf%'");
 78   Date end = new Date();
 79   System.out.print("全部重新做了一次索引,一共处理了"+num+"条信息,花:"+(end.getTime() - start.getTime())/60000+"分钟!");  
 80   }

 81   catch(Exception e)
 82   {
 83    e.printStackTrace();
 84   }

 85 }

 86 private Document newsdoc2lucenedoc(NewsDoc doc)
 87 {
 88  Document lDoc=new Document();     
 89  lDoc.add(new Field("title",doc.getTitle(),Field.Store.YES,Field.Index.TOKENIZED));
 90  lDoc.add(new Field("content",doc.getContent(),Field.Store.YES,Field.Index.TOKENIZED));
 91  lDoc.add(new Field("url",doc.getRemark(),Field.Store.YES,Field.Index.NO));    
 92  lDoc.add(new Field("cid",doc.getCid(),Field.Store.YES,Field.Index.NO));
 93  lDoc.add(new Field("source",doc.getSource(),Field.Store.YES,Field.Index.NO));
 94  lDoc.add(new Field("inputTime",doc.getInputTime().toString(),Field.Store.YES,Field.Index.NO));
 95  return lDoc;
 96 }

 97 public String getIndexDir() {
 98  return indexDir;
 99 }

100 public void setIndexDir(String indexDir) {
101  this.indexDir = indexDir;
102 }

103 
104 public String getIndexType() {
105  return indexType;
106 }

107 public void setIndexType(String indexType) {
108  this.indexType = indexType;
109 }

110}

111
 
二、使用Lucene实现全文搜索
   下面是MyRssSearch类的源码,该类主要实现使用Lucene中Searcher及QueryParser实现从索引库中搜索关键词。
 1package com.easyjf.lucene;
 2
 3import java.util.List;
 4import org.apache.lucene.analysis.standard.StandardAnalyzer;
 5import org.apache.lucene.document.Document;
 6import org.apache.lucene.index.IndexReader;
 7import org.apache.lucene.queryParser.MultiFieldQueryParser;
 8import org.apache.lucene.queryParser.QueryParser;
 9import org.apache.lucene.search.Hits;
10import org.apache.lucene.search.IndexSearcher;
11import org.apache.lucene.search.Query;
12import org.apache.lucene.search.Searcher;
13
14import com.easyjf.search.MyRssUtil;
15import com.easyjf.search.SearchContent;
16import com.easyjf.web.tools.IPageList;
17import com.easyjf.web.tools.PageList;
18
19public class MyRssSearch {
20    private String indexDir;    
21    IndexReader ir;
22    Searcher search;
23    public IPageList search(String key,int pageSize,int currentPage)
24    {
25        IPageList pList=new PageList(new HitsQuery(doSearch(key)));
26        pList.doList(pageSize,currentPage,"","",null);
27        if(pList!=null)
28        {        
29            List list=pList.getResult();    
30            if(list!=null){
31            for(int i=0;i            {
32                list.set(i,lucene2searchObj((Document)list.get(i),key));
33            }

34            }

35        }

36        try{
37        if(search!=null)search.close();
38        if(ir!=null)ir.close();
39        }

40        catch(Exception e)
41        {
42            e.printStackTrace();
43        }

44        return pList;
45    }

46    private SearchContent lucene2searchObj(Document doc,String key)
47    {
48        SearchContent searchObj=new SearchContent();
49        String title=doc.getField("title").stringValue();
50        searchObj.setTitle(title.replaceAll(key,""+key+""));        
51        searchObj.setTvalue(doc.getField("cid").stringValue());        
52        searchObj.setUrl(doc.getField("url").stringValue());
53        searchObj.setSource(doc.getField("source").stringValue());        
54        searchObj.setLastUpdated(doc.getField("inputTime").stringValue());    
55        searchObj.setIntro(MyRssUtil.content2intro(doc.getField("content").stringValue(),key));        
56        return searchObj;
57    }

58    public Hits doSearch(String key)
59    {
60        Hits hits=null;
61        try{
62        ir=IndexReader.open(indexDir);
63        search=new IndexSearcher(ir);        
64        String fields[]={"title","content"};
65        QueryParser parser=new MultiFieldQueryParser(fields,new StandardAnalyzer());
66        Query query=parser.parse(key);
67        hits=search.search(query);            
68        }

69        catch(Exception e)
70        {
71            e.printStackTrace();
72        }

73        //System.out.println("搜索结果:"+hits.length());
74        return hits;
75    }

76    
77    public String getIndexDir() {
78        return indexDir;
79    }

80    public void setIndexDir(String indexDir) {
81        this.indexDir = indexDir;
82    }

83}

84

  在上面的代码中,search方法返回一个封装了分页查询结果的IPageList,IPageList是EasyJWeb Tools业务引擎中的分页引擎,对于IPageList的使用,请看本人写的这篇文章《EasyJWeb Tools中业务引擎分页的设计实现》

  我们针对Lucene的的查询结果Hits结构,写了一个查询器HitsQuery。代码如下所示:
 1package com.easyjf.lucene;
 2import java.util.ArrayList;
 3import java.util.Collection;
 4import java.util.List;
 5import org.apache.lucene.search.Hits;
 6import com.easyjf.web.tools.IQuery;
 7public class HitsQuery implements IQuery {
 8 private int begin=0;
 9 private int max=0;
10 private Hits hits;
11 public HitsQuery()
12 {
13  
14 }

15 public HitsQuery(Hits hits)
16 {
17  if(hits!=null)
18  {
19   this.hits=hits;   
20   this.max=hits.length();
21  }

22 }

23 public int getRows(String arg0) {
24  // TODO Auto-generated method stub
25  return (hits==null?0:hits.length());
26 }

27 public List getResult(String arg0) {
28  // TODO Auto-generated method stub
29  List list=new ArrayList();  
30  for(int i=begin;i<(begin+max)&&(i  {
31   try{
32   list.add(hits.doc(i));
33   }

34   catch(Exception e)
35   {
36    e.printStackTrace();
37   }

38  }

39  return list;
40 }

41 public void setFirstResult(int begin) {
42  // TODO Auto-generated method stub
43  this.begin=begin;
44 }

45 public void setMaxResults(int max) {
46  // TODO Auto-generated method stub
47  this.max=max;
48 }

49 public void setParaValues(Collection arg0) {
50  // TODO Auto-generated method stub
51  
52 }

53 public List getResult(String condition, int begin, int max) {
54  // TODO Auto-generated method stub
55  if((begin>=0)&&(begin  if(!(max>hits.length()))this.max=max;
56  return getResult(condition);
57 }

58}

59
 
三、Web调用
  下面我们来看看在Web中如果调用商业逻辑层的全文检索功能。下面是处理用户请请的Action中关于搜索部分的源码:
 1package com.easyjf.news.action;
 2public class SearchAction implements IWebAction 
 3public Page doSearch(WebForm form,Module module)throws Exception
 4{
 5 String key=CommUtil.null2String(form.get("v")); 
 6 key=URLDecoder.decode(URLEncoder.encode(key,"ISO8859_1"),"utf-8");
 7 form.set("v",key);
 8 form.addResult("v2",URLEncoder.encode(key,"utf-8"));
 9 if(key.getBytes().length>2){
10 String orderBy=CommUtil.null2String(form.get("order")); 
11 int currentPage=CommUtil.null2Int(form.get("page"));
12 int pageSize=CommUtil.null2Int(form.get("pageSize"));  
13 if(currentPage<1)currentPage=1;
14 if(pageSize<1)pageSize=15;
15 SearchEngine search=new SearchEngine(key,orderBy,pageSize,currentPage);
16 search.getLuceneSearch().setIndexDir(Globals.APP_BASE_DIR+"/WEB-INF/index");
17 search.doSearchByLucene();
18 IPageList pList=search.getResult();
19 if(pList!=null && pList.getRowCount()>0){
20  form.addResult("list",pList.getResult());
21  form.addResult("pages",new Integer(pList.getPages()));
22  form.addResult("rows",new Integer(pList.getRowCount()));
23  form.addResult("page",new Integer(pList.getCurrentPage()));
24  form.addResult("gotoPageHTML",CommUtil.showPageHtml(pList.getCurrentPage(),pList.getPages()));
25  }

26 else 
27 {
28  form.addResult("notFound","true");//找不到数据
29 }
 
30 }

31 else
32  form.addResult("errMsg","您输入的关键字太短!");
33 form.addResult("hotSearch",SearchEngine.getHotSearch(20));
34 return null;
35}

36}

37其中调用的SearchEngine类中有关Lucene部分的源码:
38public class SearchEngine {
39private MyRssSearch luceneSearch=new MyRssSearch();
40public void doSearchByLucene()
41
42 SearchKey keyObj=readCache(); 
43 if(keyObj!=null){
44  result=luceneSearch.search(key,pageSize,currentPage);  
45  if(updateStatus){
46  keyObj.setReadTimes(new Integer(keyObj.getReadTimes().intValue()+1));
47  keyObj.update();
48  }
  
49 }

50 else//缓存中没有该关键字信息,生成关键字搜索结果
51 
52  keyObj=new SearchKey();
53  keyObj.setTitle(key);
54  keyObj.setLastUpdated(new Date());
55  keyObj.setReadTimes(new Integer(1));
56  keyObj.setStatus(new Integer(0));
57  keyObj.setSequence(new Integer(1));
58  keyObj.setVdate(new Date());
59  keyObj.save(); 
60  result=luceneSearch.search(key,pageSize,currentPage);; 
61  
62 }
 
63}

64}

65
本文转自:http://java.ccidnet.com/art/3749/20060704/595099_1.html

---------------------------------------------------------------------------------------------------------------------------------
说人之短,乃护己之短。夸己之长,乃忌人之长。皆由存心不厚,识量太狭耳。能去此弊,可以进德,可以远怨。
http://www.blogjava.net/szhswl
------------------------------------------------------------------------------------------------------ ----------------- ---------
posted on 2007-12-05 17:08 宋针还 阅读(377) 评论(0)  编辑  收藏 所属分类: 搜索引擎

只有注册用户登录后才能发表评论。


网站导航: