Lucen的基础使用

来源:互联网 发布:js调用webapi的安全性 编辑:程序博客网 时间:2024/05/18 17:57

开源全文搜索工具包Lucene3.0.1的使用。

项目环境Struts2 (2.18)+hibernate(3.0)+spring(2.5) JDK:1.6 IDE:myEclipse 8.5 

项目需求:把站内发布的新闻进行全文解索

新闻实体News

[java] view plain copy
  1. public class News {  
  2.     private int id;  
  3.     /**标题*/  
  4.     private String title;  
  5.     /**内容*/  
  6.     private String contents;  
  7. setters();  
  8. getters();  
  9. }  
新闻实体的luceneDao
[java] view plain copy
  1. package com.hkrt.dao;  
  2.   
  3. import com.hkrt.domain.LuceneSearchResult;  
  4. import com.hkrt.domain.News;  
  5. public interface NewsLuceneDao {  
  6.     public static final String FIELD_ID="id";  
  7.     public static final String FIELD_TITLE = "title";  
  8.     public static final String FIELD_CONTENTS = "contents";  
  9.     // 索引存放目录  
  10.      public static final String INDEX_DIR = Thread.currentThread().getContextClassLoader().getResource("").getPath()+"index_dir";  
  11.     /** 
  12.      * 对所有文件进行重新索引 
  13.      */  
  14.     public void rebuildAllIndex();  
  15.     /** 
  16.      * 对指定上传文件对象进行索引并追加到已有的索引文件中 
  17.      * @param news 
  18.      */  
  19.     public void doIndexSingle(News news);  
  20.     /** 
  21.      * 根据关键字搜索,返回符合条件的分页数据 
  22.      * @param keyword   关键字 
  23.      * @param pageNo    起始页 
  24.      * @param pageSize  每页要显示的记录数 
  25.      * @return LuceneSearchResult对象 
  26.      */  
  27.     public LuceneSearchResult<News> doSeacher(String keyword, int pageNo,int pageSize);  
  28.     /** 
  29.      * 更新文件的索引 
  30.      * @param news 
  31.      */  
  32.     public void updateIndex(News news);  
  33.     /** 
  34.      * 根据文件id删除索引 
  35.      * @param id 
  36.      */  
  37.     public void deleteIndex(Integer id);  
  38. }  
新闻lucene dao的实现
[java] view plain copy
  1. package com.hkrt.dao.impl;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.util.ArrayList;  
  6. import java.util.List;  
  7. import org.apache.lucene.analysis.Analyzer;  
  8. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  9. import org.apache.lucene.document.Document;  
  10. import org.apache.lucene.document.Field;  
  11. import org.apache.lucene.index.CorruptIndexException;  
  12. import org.apache.lucene.index.IndexReader;  
  13. import org.apache.lucene.index.IndexWriter;  
  14. import org.apache.lucene.index.Term;  
  15. import org.apache.lucene.queryParser.MultiFieldQueryParser;  
  16. import org.apache.lucene.queryParser.ParseException;  
  17. import org.apache.lucene.search.BooleanClause;  
  18. import org.apache.lucene.search.IndexSearcher;  
  19. import org.apache.lucene.search.Query;  
  20. import org.apache.lucene.search.ScoreDoc;  
  21. import org.apache.lucene.search.TopDocs;  
  22. import org.apache.lucene.search.highlight.Highlighter;  
  23. import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;  
  24. import org.apache.lucene.search.highlight.QueryScorer;  
  25. import org.apache.lucene.search.highlight.SimpleFragmenter;  
  26. import org.apache.lucene.search.highlight.SimpleHTMLFormatter;  
  27. import org.apache.lucene.store.Directory;  
  28. import org.apache.lucene.store.FSDirectory;  
  29. import org.apache.lucene.store.LockObtainFailedException;  
  30. import org.apache.lucene.util.Version;  
  31.   
  32. import com.hkrt.dao.NewsDao;  
  33. import com.hkrt.dao.NewsLuceneDao;  
  34. import com.hkrt.domain.LuceneSearchResult;  
  35. import com.hkrt.domain.News;  
  36. public class NewsLuceneDaoImpl implements NewsLuceneDao {  
  37.     private NewsDao newsDao;  
  38.     /** 获取语法解析器 */  
  39.     public Analyzer getAnalyzer() {  
  40.         return new StandardAnalyzer(Version.LUCENE_30);  
  41.     }  
  42.   
  43.     /** 打开索引的存放目录 */  
  44.     public Directory openDirectory() {  
  45.         try {  
  46.             System.out.println(new File(INDEX_DIR)  + "-------打开索引--------------");  
  47.             return FSDirectory.open(new File(INDEX_DIR));  
  48.         } catch (IOException e) {  
  49.             e.printStackTrace();  
  50.         }  
  51.         return null;  
  52.     }  
  53.   
  54.     /** 对文件的指定属性映射成域,返回文件文档对象 */    
  55.     public Document createForumuploadDocument(News news) {  
  56.         Document doc = new Document(); // 创建一个文档对象  
  57.         //id 域  
  58.         Field field = new Field(FIELD_ID,String.valueOf(news.getId()),Field.Store.YES, Field.Index.NOT_ANALYZED);  
  59.         doc.add(field);  
  60.         // title域  
  61.         Field field1 = new Field(FIELD_TITLE, String.valueOf(news.getTitle()),Field.Store.YES, Field.Index.ANALYZED);  
  62.         doc.add(field1);  
  63.         // content域  
  64.         Field field2 = new Field(FIELD_CONTENTS, String.valueOf(news.getContents()), Field.Store.YES, Field.Index.ANALYZED);  
  65.         doc.add(field2);  
  66.         return doc;  
  67.     }  
  68.   
  69.     public void deleteIndex(Integer id) {  
  70.         IndexReader ir = null;    
  71.         try {    
  72.             ir = IndexReader.open(this.openDirectory(), false);  //打开指定目录下索引文件的索引读取器    
  73.             ir.deleteDocuments(new Term(FIELD_ID,String.valueOf(id)));  //删除符合条件的Document    
  74.         } catch (IOException e) {    
  75.             e.printStackTrace();    
  76.         }finally{    
  77.             if(ir != null){    
  78.                 try {    
  79.                     ir.close();    
  80.                 } catch (IOException e) {    
  81.                     e.printStackTrace();    
  82.                 }    
  83.             }    
  84.         }    
  85.     }  
  86.   
  87.     @Override  
  88.     public void doIndexSingle(News news) {  
  89.         //创建索引写入器    
  90.         IndexWriter indexWriter = null;  
  91.         try {  
  92.             indexWriter = new IndexWriter(openDirectory(), getAnalyzer(),false, IndexWriter.MaxFieldLength.UNLIMITED);  
  93.             Document doc = this.createForumuploadDocument(news);  
  94.             indexWriter.addDocument(doc);  
  95.             indexWriter.optimize(); // 对索引进行优化  
  96.         } catch (CorruptIndexException e) {  
  97.             e.printStackTrace();  
  98.         } catch (LockObtainFailedException e) {  
  99.             e.printStackTrace();  
  100.         } catch (IOException e) {  
  101.             e.printStackTrace();  
  102.         } finally {  
  103.             try {  
  104.                 if (indexWriter != null) {  
  105.                     indexWriter.close(); // 关闭IndexWriter,把内存中的数据写到文件  
  106.                 }  
  107.             } catch (CorruptIndexException e) {  
  108.                 e.printStackTrace();  
  109.             } catch (IOException e) {  
  110.                 e.printStackTrace();  
  111.             }  
  112.         }  
  113.     }  
  114.   
  115.     @Override  
  116.     public LuceneSearchResult<News> doSeacher(String keyword, int pageNo,int pageSize) {  
  117.         LuceneSearchResult<News> lsr = new LuceneSearchResult<News>();  
  118.         lsr.setPageNo(pageNo);  
  119.         lsr.setPageSize(pageSize);  
  120.         lsr.setKeyword(keyword);  
  121.         IndexSearcher searcher = null;  
  122.         try {  
  123.             // 创建一个索引搜索器  
  124.             searcher = new IndexSearcher(this.openDirectory(), true);  
  125.             // 用多域查询解析器来创建一个查询器,  
  126.             Query query = MultiFieldQueryParser.parse(Version.LUCENE_30,keyword, new String[] { FIELD_TITLE, FIELD_CONTENTS },  
  127.                     new BooleanClause.Occur[] {BooleanClause.Occur.SHOULD,BooleanClause.Occur.SHOULD }, this.getAnalyzer());  
  128.             long begin = System.currentTimeMillis();  
  129.             // 查询结集信息类  
  130.             TopDocs ts = searcher.search(query, null100000);  
  131.             // 获取命中的数量  
  132.             lsr.setRecordCount(ts.totalHits);  
  133.             // 用这个进行高亮显示,默认是<b>..</b>  
  134.             SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter("<span style=color:red>""</span>");  
  135.             // 构造高亮:指定高亮的格式,指定查询评分  
  136.             Highlighter highlighter = new Highlighter(simpleHTMLFormatter,new QueryScorer(query));highlighter.setTextFragmenter(new SimpleFragmenter(Integer.MAX_VALUE));  
  137.             // 获取匹配到的结果集  
  138.             ScoreDoc[] hits = ts.scoreDocs;  
  139.             List<News> ais = new ArrayList<News>();  
  140.             int pageCount = (lsr.getRecordCount() + pageSize - 1) / pageSize; // 总页数  
  141.             int start = 0// 要开始返回的文档编号  
  142.             int end = 0// 要结束返回的文档编号  
  143.             if (pageCount > 0) {  
  144.                 start = (pageNo - 1) * pageSize;  
  145.                 end = start + pageSize;  
  146.                 if (pageNo == pageCount) { // 处理最后一页的结束文档的编号  
  147.                     end = start + (lsr.getRecordCount() % pageSize);  
  148.                 }  
  149.             }  
  150.             if (start < end) {  
  151.                 lsr.setStratNo(start + 1);  
  152.                 lsr.setEndNo(end);  
  153.             }  
  154.             for (int i = start; i < end; i++) { // 循环获取分页数据  
  155.                 // 通过内部编号从搜索器中得到对应的文档  
  156.                 Document doc = searcher.doc(hits[i].doc);  
  157.                 News news = new News();  
  158.                 news.setTitle(doc.getField(FIELD_TITLE).stringValue());  
  159.                 news.setContents(doc.getField(FIELD_CONTENTS).stringValue());   
  160.                 // 处理文件名称的高亮显示问题  
  161.                 String title = doc.getField(FIELD_TITLE).stringValue();  
  162.                 String title2 = highlighter.getBestFragment(this.getAnalyzer(),FIELD_TITLE, title);  
  163.                 if (title2 == null) {  
  164.                     news.setTitle(title);  
  165.                 } else {  
  166.                     news.setTitle(title2);  
  167.                 }  
  168.                 // 文件描述高亮显示  
  169.                 String contents1 = doc.getField(FIELD_CONTENTS).stringValue();  
  170.                 String contents2 = highlighter.getBestFragment(this.getAnalyzer(), FIELD_CONTENTS, contents1);  
  171.                 if (contents2 == null) {  
  172.                     news.setContents(contents1);  
  173.                 } else {  
  174.                     if (contents2.length() > 512) {  
  175.                         news.setContents(contents2.substring(0512) + "...");  
  176.                     } else {  
  177.                         news.setContents(contents2);  
  178.                     }  
  179.                 }  
  180.                 ais.add(news); // 把符合条件的数据添加到List  
  181.             }  
  182.             lsr.setTime((System.currentTimeMillis() - begin) / 1000.0); // 计算搜索耗时秒数  
  183.             lsr.setDatas(ais); // 把查询到的数据添加到LuceneSearchResult  
  184.         } catch (IOException e) {  
  185.             e.printStackTrace();  
  186.         } catch (ParseException e) {  
  187.             e.printStackTrace();  
  188.         } catch (InvalidTokenOffsetsException e) {  
  189.             e.printStackTrace();  
  190.         } finally {  
  191.             if (searcher != null) {  
  192.                 try {  
  193.                     searcher.close(); // 关闭搜索器  
  194.                 } catch (Exception e) {  
  195.                     e.printStackTrace();  
  196.                 }  
  197.             }  
  198.         }  
  199.         return lsr;  
  200.     }  
  201.   
  202.     @Override  
  203.     public void rebuildAllIndex() {  
  204.         File file = new File(INDEX_DIR);  
  205.         if (file.exists()) {  
  206.             for (File subFile : file.listFiles()) {  
  207.                 subFile.delete();  
  208.             }  
  209.         } else {  
  210.             file.mkdirs();  
  211.         }  
  212.         List<News> data = this.newsDao.findAll();  
  213.         IndexWriter indexWriter = null;  
  214.         try {  
  215.             indexWriter = new IndexWriter(this.openDirectory(), getAnalyzer(),true, IndexWriter.MaxFieldLength.UNLIMITED);  
  216.             // 设置打开使用复合文件  
  217.             // indexWriter.setUseCompoundFile(true);  
  218.             int size = data == null ? 0 : data.size();  
  219.             for (int i = 0; i < size; i++) {  
  220.                 News news = data.get(i);  
  221.                 Document doc = createForumuploadDocument(news);  
  222.                 indexWriter.addDocument(doc);  
  223.                 if (i % 20 == 0) {  
  224.                     indexWriter.commit();  
  225.                 }  
  226.             }  
  227.             indexWriter.optimize(); // 对索引进行优化  
  228.         } catch (CorruptIndexException e) {  
  229.             e.printStackTrace();  
  230.         } catch (LockObtainFailedException e) {  
  231.             e.printStackTrace();  
  232.         } catch (IOException e) {  
  233.             e.printStackTrace();  
  234.         } finally {  
  235.             try {  
  236.                 if (indexWriter != null) {  
  237.                     indexWriter.close();// 关闭IndexWriter,把内存中的数据写到文件  
  238.                 }  
  239.             } catch (CorruptIndexException e) {  
  240.                 e.printStackTrace();  
  241.             } catch (IOException e) {  
  242.                 e.printStackTrace();  
  243.             }  
  244.         }  
  245.     }  
  246.     @Override  
  247.     public void updateIndex(News news) {  
  248.         this.deleteIndex(news.getId());    
  249.         this.doIndexSingle(news);    
  250.     }  
  251.     public NewsDao getNewsDao() {  
  252.         return newsDao;  
  253.     }  
  254.     public void setNewsDao(NewsDao newsDao) {  
  255.         this.newsDao = newsDao;  
  256.     }  
  257. }  

对查询结果进行分页处理

[java] view plain copy
  1. package com.hkrt.domain;  
  2. import java.util.List;  
  3. public class LuceneSearchResult<T> {  
  4.     private int pageNo = 1;    //当前页    
  5.     private int pageSize = 5;  //每页显示记录数    
  6.     private int recordCount;   //总记录数    
  7.     private double time;       //耗时    
  8.     private List<T> datas;     //当前页的数据    
  9.     private int stratNo;       //开始记录数    
  10.     private int endNo;         //结束记录数    
  11.     private String keyword;    //关键字    
  12.     public int getPageNo() {    
  13.     return pageNo;    
  14.     }    
  15.     public void setPageNo(int pageNo) {    
  16.     this.pageNo = pageNo;    
  17.     }    
  18.     public int getPageSize() {    
  19.     return pageSize;    
  20.     }    
  21.     public void setPageSize(int pageSize) {    
  22.     this.pageSize = pageSize;    
  23.     }    
  24.     public int getRecordCount() {    
  25.     return recordCount;    
  26.     }    
  27.     public void setRecordCount(int recordCount) {    
  28.     this.recordCount = recordCount;    
  29.     }    
  30.     public List<T> getDatas() {    
  31.     return datas;    
  32.     }    
  33.     public void setDatas(List<T> datas) {    
  34.     this.datas = datas;    
  35.     }    
  36.     public double getTime() {    
  37.     return time;    
  38.     }    
  39.     public void setTime(double time) {    
  40.     this.time = time;    
  41.     }    
  42.     public String getKeyword() {    
  43.     return keyword;    
  44.     }    
  45.     public void setKeyword(String keyword) {    
  46.     this.keyword = keyword;    
  47.     }    
  48.     public int getStratNo() {    
  49.     return stratNo;    
  50.     }    
  51.     public void setStratNo(int stratNo) {    
  52.     this.stratNo = stratNo;    
  53.     }    
  54.     public int getEndNo() {    
  55.     return endNo;    
  56.     }    
  57.     public void setEndNo(int endNo) {    
  58.     this.endNo = endNo;    
  59.     }    
  60. }  

代码已经实现对news 进行建立索引和对关键字进行索引
lucene3.0.1 中需要的jar 包


建立索引:


搜索页面数据展示

[html] view plain copy
  1. <table width="100%" height="92" border="0" cellpadding="0" cellspacing="1">    
  2.        <div class="title">搜索结果:搜索关键字【${lsr.keyword}】,共搜索到【${lsr.recordCount }】个文件,耗时:${lsr.time}秒,当前显示${lsr.stratNo}—${lsr.endNo}记录</div>    
  3.        <c:forEach items="${request.lsr.datas}" var="news">    
  4.         <tr>  
  5.           <td height="30" colspan="6" align="left" bgcolor="#f2f2f2" class="left_txt">    
  6.            ${news.id}    
  7.           </td>  
  8.           <td height="30" colspan="6" align="left" bgcolor="#f2f2f2" class="left_txt">    
  9.           ${news.title}    
  10.           </td>    
  11.           <td height="30" colspan="6" align="left" bgcolor="#f2f2f2" class="left_txt">${news.contents}</td>    
  12.         </tr>    
  13.         </c:forEach>    
  14.      </table>   
最终搜索结果:

0 0
原创粉丝点击