1、定义一个工厂类
LuceneFactory
import java.io.IOException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;
import cn.utils.Constant;
public class LuceneFactory
{
private static IndexReader fileReader = null;
private static Directory fileDirectory = null;
private static IndexWriter fileWriter = null;
public static Analyzer ana = new IKAnalyzer();
/**
* 获取indexwriter
* @return
* @throws IOException
*/
public static synchronized IndexWriter getFileWrite() throws IOException
{
if(fileWriter == null){
fileDirectory = FSDirectory.open(Constant.file_index_path_File);
if (IndexWriter.isLocked(fileDirectory)) {
IndexWriter.unlock(fileDirectory);
}
fileWriter = new IndexWriter(fileDirectory, new IndexWriterConfig(Version.LUCENE_36, ana));
return fileWriter;
}
System.out.println("filewriter != null");
return fileWriter;
}
/**
*获得IndexReader对象,判断是否为最新,不是则重新打开
*@param file 索引路径的File对象
**/
public static synchronized IndexReader getFileRead() throws IOException
{
if (fileReader == null) {
fileDirectory = FSDirectory.open(Constant.file_index_path_File);
fileReader = IndexReader.open(fileDirectory);
} else {
if (!fileReader.isCurrent()) {
fileReader = IndexReader.openIfChanged(fileReader);
}
}
return fileReader;
}
/***
* 获得IndexSearcher对象,判断当前的Searcher中reader是否为最新,如果不是,则重新创建IndexSearcher
*
* @return
* @throws IOException
*/
public static synchronized IndexSearcher getFileSearch() throws IOException
{
/*if (fileSearcher == null) {
fileDirectory = FSDirectory.open(file_index_path);
fileSearcher = new IndexSearcher(IndexReader.open(fileDirectory));
} else {
IndexReader r = fileSearcher.getIndexReader();
if (!r.isCurrent()) {
fileSearcher.close();
fileSearcher = new IndexSearcher(IndexReader.openIfChanged(r));
}
}
return fileSearcher;*/
return new IndexSearcher(getFileRead());
}
public static void closeFileWrite()
{
if(fileWriter != null)
{
try
{
fileWriter.commit();
fileWriter.close();
} catch (CorruptIndexException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
2、定义返回结果bean
import java.util.List;
import org.apache.lucene.document.Document;
public class SearchResultBean
{
private int totalHits;
private List<Document> docs;
public SearchResultBean()
{
}
public SearchResultBean(int totalHits, List<Document> docs)
{
this.totalHits = totalHits;
this.docs = docs;
}
public int getTotalHits()
{
return this.totalHits;
}
public void setTotalHits(int totalHits)
{
this.totalHits = totalHits;
}
public List<Document> getDocs()
{
return this.docs;
}
public void setDocs(List<Document> docs)
{
this.docs = docs;
}
}
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、搜索方法 重点
/****
* 命名不是很好
* @param field:暂时么用
* @param query:query
* @param first:分页起始值,如第一页0, first 0 max 20,第二页 first20, max 20
* @param max:每页显示的数目,如20
* @param sort:排序
* @param highLight:是否高亮,这里不咱贴代码
* @return
*/
public static SearchResultBean searchAndSort(String field, Query query, int first,
int max, Sort sort, boolean highLight)
{
if(query == null){
System.out.println(" Query is null return null ");
return null;
}
try
{
List<Document> docs = new ArrayList<Document>();
IndexSearcher searcher = LuceneFactory.getFileSearch();
TopFieldCollector c = TopFieldCollector.create(sort, first+max, false, false, false, false);
searcher.search(query, c);
ScoreDoc[] hits = c.topDocs(first, max).scoreDocs;
if (hits == null || hits.length < 1)
return null;
// 高亮------------------------------
Formatter htmlFormatter = null;
if (highLight)
htmlFormatter = new SimpleHTMLFormatter(
"<span style='color:red;'>", "</span>");
else
htmlFormatter = new SimpleHTMLFormatter("", "");
Scorer scorer = new QueryScorer(query);
//Encoder encoder = new SimpleHTMLEncoder();
Fragmenter fragmenter = new SimpleFragmenter(Max_Match_Num);
Highlighter highlighter = new Highlighter(htmlFormatter, scorer);
highlighter.setTextFragmenter(fragmenter);
for (int i = 0; i < hits.length; i++)
{
Document doc = searcher.doc(hits[i].doc);
highlight(highlighter, doc, field);
docs.add(doc);
}
return new SearchResultBean(c.getTotalHits(), docs);
} catch (Exception e)
{
return null;
}
}
- 第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>