1、定义一个工厂类
LuceneFactory
1 import java.io.IOException; 2 3 import org.apache.lucene.analysis.Analyzer; 4 import org.apache.lucene.index.CorruptIndexException; 5 import org.apache.lucene.index.IndexReader; 6 import org.apache.lucene.index.IndexWriter; 7 import org.apache.lucene.index.IndexWriterConfig; 8 import org.apache.lucene.search.IndexSearcher; 9 import org.apache.lucene.store.Directory; 10 import org.apache.lucene.store.FSDirectory; 11 import org.apache.lucene.util.Version; 12 import org.wltea.analyzer.lucene.IKAnalyzer; 13 14 import cn.utils.Constant; 15 16 public class LuceneFactory 17 { 18 private static IndexReader fileReader = null; 19 private static Directory fileDirectory = null; 20 private static IndexWriter fileWriter = null; 21 22 public static Analyzer ana = new IKAnalyzer(); 23 24 25 26 /** 27 * 获取indexwriter 28 * @return 29 * @throws IOException 30 */ 31 public static synchronized IndexWriter getFileWrite() throws IOException 32 { 33 34 if(fileWriter == null){ 35 fileDirectory = FSDirectory.open(Constant.file_index_path_File); 36 if (IndexWriter.isLocked(fileDirectory)) { 37 IndexWriter.unlock(fileDirectory); 38 } 39 fileWriter = new IndexWriter(fileDirectory, new IndexWriterConfig(Version.LUCENE_36, ana)); 40 41 return fileWriter; 42 } 43 44 System.out.println("filewriter != null"); 45 46 return fileWriter; 47 } 48 49 /** 50 *获得IndexReader对象,判断是否为最新,不是则重新打开 51 *@param file 索引路径的File对象 52 **/ 53 public static synchronized IndexReader getFileRead() throws IOException 54 { 55 if (fileReader == null) { 56 fileDirectory = FSDirectory.open(Constant.file_index_path_File); 57 fileReader = IndexReader.open(fileDirectory); 58 } else { 59 if (!fileReader.isCurrent()) { 60 fileReader = IndexReader.openIfChanged(fileReader); 61 } 62 } 63 64 return fileReader; 65 } 66 67 /*** 68 * 获得IndexSearcher对象,判断当前的Searcher中reader是否为最新,如果不是,则重新创建IndexSearcher 69 * 70 * @return 71 * @throws IOException 72 */ 73 public static synchronized IndexSearcher getFileSearch() throws IOException 74 { 75 /*if (fileSearcher == null) { 76 fileDirectory = FSDirectory.open(file_index_path); 77 fileSearcher = new IndexSearcher(IndexReader.open(fileDirectory)); 78 } else { 79 IndexReader r = fileSearcher.getIndexReader(); 80 if (!r.isCurrent()) { 81 fileSearcher.close(); 82 fileSearcher = new IndexSearcher(IndexReader.openIfChanged(r)); 83 } 84 } 85 86 return fileSearcher;*/ 87 88 return new IndexSearcher(getFileRead()); 89 } 90 91 public static void closeFileWrite() 92 { 93 if(fileWriter != null) 94 { 95 try 96 { 97 fileWriter.commit(); 98 fileWriter.close(); 99 } catch (CorruptIndexException e) 100 { 101 102 e.printStackTrace(); 103 } catch (IOException e) 104 { 105 106 e.printStackTrace(); 107 } 108 109 } 110 } 111 112 }
2、定义返回结果bean
1 import java.util.List; 2 3 import org.apache.lucene.document.Document; 4 5 public class SearchResultBean 6 { 7 private int totalHits; 8 private List<Document> docs; 9 10 public SearchResultBean() 11 { 12 13 } 14 15 public SearchResultBean(int totalHits, List<Document> docs) 16 { 17 this.totalHits = totalHits; 18 this.docs = docs; 19 } 20 21 public int getTotalHits() 22 { 23 return this.totalHits; 24 } 25 26 public void setTotalHits(int totalHits) 27 { 28 this.totalHits = totalHits; 29 } 30 31 public List<Document> getDocs() 32 { 33 return this.docs; 34 } 35 36 public void setDocs(List<Document> docs) 37 { 38 this.docs = docs; 39 } 40 }
3、分页bean
import java.util.ArrayList; import java.util.List; public class PageBean { private int currentPage = 1;// 当前页数 private int totalPages = 0;// 总页数 private int pageSize = 0;// 每页显示数 private int totalRows = 0;// 总数据数 private int startNum = 0;// 开始记录 private int nextPage = 0;// 下一页 private int previousPage = 0;// 上一页 private boolean hasNextPage = false;// 是否有下一页 private boolean hasPreviousPage = false;// 是否有前一页 private List<String> pageCodes; private int showPageSize = 8; //显示多少个超链接页面 public PageBean() {} public PageBean(int pageSize, int currentPage, int totalRows) { this.pageSize = pageSize; this.currentPage = currentPage; this.totalRows = totalRows; if ((totalRows % pageSize) == 0) { totalPages = totalRows / pageSize; } else { totalPages = totalRows / pageSize + 1; } if (currentPage >= totalPages) { hasNextPage = false; currentPage = totalPages; } else { hasNextPage = true; } if (currentPage <= 1) { hasPreviousPage = false; currentPage = 1; } else { hasPreviousPage = true; } startNum = (currentPage - 1) * pageSize; nextPage = currentPage + 1; if (nextPage >= totalPages) { nextPage = totalPages; } previousPage = currentPage - 1; if (previousPage <= 1) { previousPage = 1; } reflashPageCode(); } public void reflashPageCode() { this.pageCodes = new ArrayList<String>(); if (this.totalPages <= this.showPageSize) { for (int i = 1; i <= this.totalPages; i++) { this.pageCodes.add(String.valueOf(i)); } return; } int middleSide = this.showPageSize >> 1; if (this.currentPage <= middleSide) { for (int i = 1; i <= this.showPageSize; i++) { this.pageCodes.add(String.valueOf(i)); } this.pageCodes.add(String.valueOf("..")); return; } if ((this.totalPages - this.currentPage) <= middleSide) { this.pageCodes.add(String.valueOf("..")); for (int i = this.showPageSize - 1; i >= 0; i--) { this.pageCodes.add(String.valueOf(this.totalPages - i)); } return; } if (middleSide < this.currentPage && this.currentPage - (middleSide + 1) > 0) this.pageCodes.add(String.valueOf("..")); for (int i = 0; i < this.showPageSize; i++) { this.pageCodes.add(String.valueOf((this.currentPage + i) - middleSide)); } if (middleSide > this.currentPage || this.totalPages - (this.currentPage + middleSide) > 0) this.pageCodes.add(String.valueOf("..")); } public boolean isHasNextPage() { return hasNextPage; } public boolean isHasPreviousPage() { return hasPreviousPage; } /** * @return the nextPage */ public int getNextPage() { return nextPage; } /** * @param nextPage * the nextPage to set */ public void setNextPage(int nextPage) { this.nextPage = nextPage; } /** * @return the previousPage */ public int getPreviousPage() { return previousPage; } /** * @param previousPage * the previousPage to set */ public void setPreviousPage(int previousPage) { this.previousPage = previousPage; } /** * @return the currentPage */ public int getCurrentPage() { return currentPage; } /** * @param currentPage * the currentPage to set */ public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } /** * @return the pageSize */ public int getPageSize() { return pageSize; } /** * @param pageSize * the pageSize to set */ public void setPageSize(int pageSize) { this.pageSize = pageSize; } /** * @return the totalPages */ public int getTotalPages() { return totalPages; } /** * @param totalPages * the totalPages to set */ public void setTotalPages(int totalPages) { this.totalPages = totalPages; } /** * @return the totalRows */ public int getTotalRows() { return totalRows; } /** * @param totalRows * the totalRows to set */ public void setTotalRows(int totalRows) { this.totalRows = totalRows; } /** * @param hasNextPage * the hasNextPage to set */ public void setHasNextPage(boolean hasNextPage) { this.hasNextPage = hasNextPage; } /** * @param hasPreviousPage * the hasPreviousPage to set */ public void setHasPreviousPage(boolean hasPreviousPage) { this.hasPreviousPage = hasPreviousPage; } /** * @return the startNum */ public int getStartNum() { return startNum; } /** * @param startNum * the startNum to set */ public void setStartNum(int startNum) { this.startNum = startNum; } public List<String> getPageCodes() { if (this.pageCodes == null) { return new ArrayList<String>(); } return pageCodes; } public void setPageCodes(List<String> pageCodes) { this.pageCodes = pageCodes; } public int getShowPageSize() { return showPageSize; } public void setShowPageSize(int showPageSize) { this.showPageSize = showPageSize; } }
4、搜索方法 重点
1 /**** 2 * 命名不是很好 3 * @param field:暂时么用 4 * @param query:query 5 * @param first:分页起始值,如第一页0, first 0 max 20,第二页 first20, max 20 6 * @param max:每页显示的数目,如20 7 * @param sort:排序 8 * @param highLight:是否高亮,这里不咱贴代码 9 * @return 10 */ 11 public static SearchResultBean searchAndSort(String field, Query query, int first, 12 int max, Sort sort, boolean highLight) 13 { 14 if(query == null){ 15 System.out.println(" Query is null return null "); 16 return null; 17 } 18 try 19 { 20 List<Document> docs = new ArrayList<Document>(); 21 IndexSearcher searcher = LuceneFactory.getFileSearch(); 22 23 TopFieldCollector c = TopFieldCollector.create(sort, first+max, false, false, false, false); 24 searcher.search(query, c); 25 ScoreDoc[] hits = c.topDocs(first, max).scoreDocs; 26 if (hits == null || hits.length < 1) 27 return null; 28 29 // 高亮------------------------------ 30 Formatter htmlFormatter = null; 31 if (highLight) 32 htmlFormatter = new SimpleHTMLFormatter( 33 "<span style='color:red;'>", "</span>"); 34 else 35 htmlFormatter = new SimpleHTMLFormatter("", ""); 36 37 Scorer scorer = new QueryScorer(query);
38 //Encoder encoder = new SimpleHTMLEncoder(); 39 Fragmenter fragmenter = new SimpleFragmenter(Max_Match_Num); 40 Highlighter highlighter = new Highlighter(htmlFormatter, scorer); 41 highlighter.setTextFragmenter(fragmenter); 42 43 for (int i = 0; i < hits.length; i++) 44 { 45 Document doc = searcher.doc(hits[i].doc); 46 highlight(highlighter, doc, field); 47 48 docs.add(doc); 49 } 50 51 return new SearchResultBean(c.getTotalHits(), docs); 52 } catch (Exception e) 53 { 54 return null; 55 } 56 } 57
- 第23行,max+first 值无所谓,返回的是命中数,不会是一个list集合,不用担心内存开销
- 第38行,中文分词、做高亮的时候,不注释这段代码,高亮的结果是unicode编码,搞不懂,暂时没研究。我用IK分词,测试与IK无关。
- 第51行,c.getTotalHits(),回到第一个问题,就是lucene分页,以前做数据库分页的时候,需要查询2次,而lucene只需要一次就OK。
分页jsp页面
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<script type="text/javascript" src="${pageContext.request.contextPath}/script/jquery.js"></script>
<div class="pagelistbox">
<input type="hidden" name="currentPage" id="currentPage" value="${pager.currentPage}" />
<span>共 ${pager.totalPages} 页/${pager.totalRows}条记录 </span>
<c:if test="${pager.hasPreviousPage}">
<span class="indexPage"> <a href="${pageContext.request.contextPath}/${page_url}1">首页</a></span>
</c:if>
<c:forEach var="every" items="${pager.pageCodes}">
<c:choose>
<c:when test="${every ne fn:trim(pager.currentPage) && every eq '..'}">
<span>${every} </span>
</c:when>
<c:when test="${every ne fn:trim(pager.currentPage)}">
<a href="${pageContext.request.contextPath}/${page_url}${every}">${every}</a>
</c:when>
<c:otherwise>
<strong>${every}</strong>
</c:otherwise>
</c:choose>
</c:forEach>
<c:if test="${pager.hasNextPage}">
<a class="nextPage" href="${pageContext.request.contextPath}/${page_url}${pager.nextPage}">下页</a>
<a class="nextPage" href="${pageContext.request.contextPath}/${page_url}${pager.totalPages}">末页</a>
</c:if>
</div>