欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

lucene 查询+分页+排序

程序员文章站 2022-07-09 09:53:14
...

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
  1.  第23行,max+first 值无所谓,返回的是命中数,不会是一个list集合,不用担心内存开销
  2.  第38行,中文分词、做高亮的时候,不注释这段代码,高亮的结果是unicode编码,搞不懂,暂时没研究。我用IK分词,测试与IK无关。
  3.  第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>