lucene 查询+分页+排序
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页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<%@ page language= "java" pageEncoding= "UTF-8" %>
<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> |