从零开始一步一步做论坛------抛砖引玉,欢迎怕转[七]----lucene模块

来源:互联网 发布:linux ping 64字节 编辑:程序博客网 时间:2024/05/16 22:01
好久没有更新了,今天说说最近为这个项目加的一个新功能吧,即全文检索Lucene!至于Lucene到底是什么东西,大家可以在自己学习一下,我这里只说说是怎样将其配置到我的项目中的.大家如果对我这个项目不是很了解,可以先看看前面几个帖子.

      其实说到Lucene,我也是第一次接触,以前听说过,但没有用过.搞了两天,先是看视频,看完了还是不会配到我的S2SH框架中,没办法,咱人笨.最后找项目,配合视频,终于搞定了.Lucene主要是操作其自己的索引,所以其实和数据库没有多少关系,但为了和我的项目框架保持协调性,我依然采用了dao-->service-->action这种模式,其实完全没有必要,我个人觉得有一个service层就足够了.好了,废话补多少了,直接上代码:

 

Java代码  收藏代码
  1. public class SearchDaoImpl implements SearchDao {  
  2.   
  3.     public void save(Document doc, IndexWriter indexWriter) {  
  4.         try {  
  5.             indexWriter.addDocument(doc);  
  6.         } catch (Exception e) {  
  7.             e.printStackTrace();  
  8.         }finally{  
  9.             try {  
  10.                 indexWriter.optimize();  
  11.             } catch (Exception e) {  
  12.                 e.printStackTrace();  
  13.             }  
  14.         }  
  15.   
  16.     }  
  17.   
  18.     public void delete(Term term , IndexWriter indexWriter) {  
  19.         try {  
  20.             indexWriter.deleteDocuments(term);  
  21.         } catch (Exception e) {  
  22.             e.printStackTrace();  
  23.         }finally{  
  24.             try {  
  25.                 indexWriter.close();  
  26.             } catch (Exception e) {  
  27.                 e.printStackTrace();  
  28.             }  
  29.         }  
  30.     }  
  31.   
  32.     public void update(Term term, Document doc, IndexWriter indexWriter) {  
  33.         try {  
  34.             indexWriter.updateDocument(term, doc);  
  35.         } catch (Exception e) {  
  36.             e.printStackTrace();  
  37.         }finally{  
  38.             try {  
  39.                 indexWriter.close();  
  40.             } catch (Exception e) {  
  41.                 e.printStackTrace();  
  42.             }  
  43.         }  
  44.     }  
  45.       
  46.     //返回查询结果集  
  47.     public TopDocs search(Query query, IndexSearcher indexSearcher) throws Exception {  
  48.         Filter filter = null;  
  49.         return indexSearcher.search(query, filter, 10000);  
  50.     }  

 

      大家可以看到,我其实连过滤器都没有写,主要就是为了熟悉这个框架和S2SH项目的整合使用.

 

Java代码  收藏代码
  1. public class ForumSearchServiceImpl implements ForumSearchService {  
  2.     private SearchDao searchDao;  
  3.   
  4.     //保存索引  
  5.     public void saveForumIndex(List forumList)  throws Exception{  
  6.         File indexFile = new File("D:\\index");  
  7.         Analyzer analyzer = new PaodingAnalyzer();  
  8.         IndexWriter indexWriter = new IndexWriter(indexFile, analyzer, true, MaxFieldLength.LIMITED);  
  9.         List<Forum> list =forumList;  
  10.           
  11.         //对所有的论坛进行索引创建  
  12.         for(Forum forum : list){  
  13.             Document doc = new Document();  
  14.             String id = forum.getId();  
  15.             Long bid = forum.getBoard().getId();  
  16.             String title = forum.getTitle();  
  17.             String detail = forum.getDetail();  
  18.             String postTime = BBSNSUtil.formatDateTime(new Date(forum.getPostTime()), Constant.formatDate);  
  19.             //因为要搜索和高亮,所以index是tokennized,TermVector是WITH_POSITIONS_OFFSETS  
  20.             doc.add(new Field("title", title, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));  
  21.             //利用htmlparser得到新闻内容html的纯文本  
  22.             Parser parser = new Parser();  
  23.             parser.setInputHTML(detail);  
  24.             String strings = parser.parse(null).elementAt(0).toPlainTextString().trim();  
  25.             System.out.println("-------"+strings);  
  26.             if(!(strings.length()==0)){  
  27.                 doc.add(new Field("detail", strings, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));  
  28.             }else{  
  29.                 String str = "内容为视频或者图片,不包含文字";  
  30.                 doc.add(new Field("detail", str, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));  
  31.                 System.out.println(str);  
  32.             }  
  33.             //添加时间至文档,因为要按照此字段降序排列排序,所以tokenzied,不用高亮所以TermVector是no就行了  
  34.             doc.add(new Field("postTime", postTime, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO));  
  35.             //添加主键至文档,不分词,不高亮。  
  36.             doc.add(new Field("id" , id , Field.Store.YES , Field.Index.NO , Field.TermVector.NO));  
  37.             doc.add(new Field("bid" , bid.toString() , Field.Store.YES , Field.Index.NO , Field.TermVector.NO));  
  38.   
  39.             searchDao.save(doc, indexWriter);  
  40.         }  
  41.         indexWriter.close();  
  42.     }  
  43.       
  44.     //搜索方法  
  45.     public PageList searchFourm(String which, String keyWord, Pages pages) throws Exception{  
  46.   
  47.         System.out.println("pages.getSpage()="+pages.getSpage());  
  48.           
  49.         QueryResult queryResult = this.searchFourm(which, keyWord, pages.getSpage(), pages.getPerPageNum());  
  50.         PageList pl = new PageList();  
  51.           
  52.         if(pages.getTotalNum()==-1){  
  53.             pages.setTotalNum(queryResult.getRecordCount());  
  54.         }  
  55.         pages.executeCount();  
  56.         queryResult = this.searchFourm(which, keyWord, pages.getSpage(), pages.getPerPageNum());  
  57.         System.out.println("queryResult.getRecordList()="+queryResult.getRecordList());  
  58.         pl.setObjectList(queryResult.getRecordList());  
  59.         pl.setPages(pages);  
  60.         return pl;  
  61.     }  
  62.       
  63.       
  64.     public QueryResult searchFourm(String which, String keyWord, int firstResult, int maxResult) throws Exception {  
  65.         File indexFile = new File("D:\\index");  
  66.         IndexReader reader = IndexReader.open(indexFile);  
  67.         //庖丁解牛分词器  
  68.         Analyzer analyzer = new PaodingAnalyzer();  
  69.         //指定对content还是title进行查询  
  70.         QueryParser queryParser = new QueryParser(which, analyzer);  
  71.         IndexSearcher indexSearcher = new IndexSearcher(reader);  
  72.         //对用户的输入进行查询  
  73.         Query query = queryParser.parse(keyWord);  
  74.           
  75.         TopDocs topDocs = searchDao.search(query, indexSearcher);  
  76.         int recordCount = topDocs.totalHits;  
  77.         //高亮htmlFormatter对象  
  78.         SimpleHTMLFormatter sHtmlF = new SimpleHTMLFormatter("<font color='red'>""</font>");  
  79.         //高亮对象  
  80.         Highlighter highlighter = new Highlighter(sHtmlF, new QueryScorer(query));  
  81.         //设置高亮附近的字数  
  82.         highlighter.setTextFragmenter(new SimpleFragmenter(100));  
  83.   
  84.         List<ForumSearch> recordList = new ArrayList<ForumSearch>();  
  85.           
  86.       
  87.         // 3,取出当前页的数据  
  88.         int end = Math.min(firstResult + maxResult, topDocs.totalHits);  
  89.         for(int i = firstResult; i < end; i++){  
  90.             ScoreDoc scoreDoc = topDocs.scoreDocs[i];  
  91.             int docSn = scoreDoc.doc;//文档内部编号  
  92.             Document doc = indexSearcher.doc(docSn); // 根据编号取出相应的文档  
  93.               
  94.             //取得该条索引文档  
  95.             ForumSearch fs = new ForumSearch();  
  96.             String title = doc.get("title");  
  97.             String detail = doc.get("detail");  
  98.             String id = doc.get("id");  
  99.             String bid = doc.get("bid");  
  100.             String postTime = doc.get("postTime");  
  101.               
  102.               
  103.             if(which.equals("title")){  
  104.                 String bestFragment = highlighter.getBestFragment(analyzer, which, title);  
  105.                 //获得高亮后的标题内容  
  106.                 fs.setTitle(bestFragment);  
  107.                 //如果内容不足100字,全部设置  
  108.                 if(detail.length()<100){  
  109.                     fs.setDetail(detail);  
  110.                 }else{  
  111.                     fs.setDetail(detail.substring(0100));  
  112.                 }  
  113.             }else{  
  114.                 //如果查询内容  
  115.                 String bestFragment = highlighter.getBestFragment(analyzer, which, detail);  
  116.                 //取得高亮内容并设置  
  117.                 fs.setDetail(bestFragment);  
  118.                 fs.setTitle(title);  
  119.             }  
  120.             //设置日期  
  121.             fs.setPostTime(postTime);  
  122.             fs.setId(id);  
  123.             fs.setBid(bid);  
  124.             recordList.add(fs);  
  125.         }  
  126.           
  127.         return new QueryResult(recordCount, recordList);  
  128.     }  
  129.       
  130.     public SearchDao getSearchDao() {  
  131.         return searchDao;  
  132.     }  
  133.     public void setSearchDao(SearchDao searchDao) {  
  134.         this.searchDao = searchDao;  
  135.     }  
  136.   
  137.       
  138. }  

ForumSearchServiceImpl只写了两个方法,一个就是创建索引,另一个就是搜索.其中为了返回数据方便,定义了一个QueryResult结构,里面只有两个变量,这里就不粘代码了,能看懂的人自然知道那两个变量是什么,注意,这里面的方法模仿了Hibernate分页,接下来将我的Action层的代码贴出来:

Java代码  收藏代码
  1. public String createIndex() throws Exception{  
  2.         List<Forum> forumList = forumService.listForums();  
  3.         forumSearchService.saveForumIndex(forumList);     
  4.         return SUCCESS;  
  5.     }  
  6.   
  7.     public String search() throws Exception {  
  8.         Pages pages = new Pages();  
  9.         pages.setPerPageNum(10);  
  10.         pages.setPage(this.getPage());  
  11.         pages.setFileName(basePath + "forumSearch.bbsns?action=search"+"&keyWord="+keyWord+"&which="+which);  
  12.         this.setPageList(forumSearchService.searchFourm(which, keyWord, pages));  
  13.         return "result";  
  14.     }  

      其实至于搜索和创建索引,大家可以完善很多功能,比如多关键字,多条件查询,方法只要实现好,创建好索引就行了,可以实现高级搜索等功能.最近有点懒,大概写了这么点,哎...

      好了,大概差不多了,就到这里吧,如果各位有什么问题,欢迎留言探讨.

原创首发,谢谢支持!