lucene 查询+分页+排序

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;
         }
     }
  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>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
lucene搜索分页过程中,可以有两种方式 一种是将搜索结果集直接放到session中,但是假如结果集非常大,同时又存在大并发访问的时候,很可能造成服务器的内存不足,而使服务器宕机 还有一种是每次都重新进行搜索,这样虽然避免了内存溢出的可能,但是,每次搜索都要进行一次IO操作,如果大并发访问的时候,你要保证你的硬盘的转速足够的快,还要保证你的cpu有足够高的频率 而我们可以将这两种方式结合下,每次查询都多缓存一部分的结果集,翻页的时候看看所查询的内容是不是在已经存在在缓存当中,如果已经存在了就直接拿出来,如果不存在,就进行查询后,从缓存中读出来. 比如:现在我们有一个搜索结果集 一个有100条数据,每页显示10条,就有10页数据. 安装第一种的思路就是,我直接把这100条数据缓存起来,每次翻页时从缓存种读取 而第二种思路就是,我直接从搜索到的结果集种显示前十条给第一页显示,第二页的时候,我在查询一次,给出10-20条数据给第二页显示,我每次翻页都要重新查询 第三种思路就变成了 我第一页仅需要10条数据,但是我一次读出来50条数据,把这50条数据放入到缓存当中,当我需要10--20之间的数据的时候,我的发现我的这些数据已经在我的缓存种存在了,我就直接存缓存中把数据读出来,少了一次查询,速度自然也提高了很多. 如果我访问第六页的数据,我就把我的缓存更新一次.这样连续翻页10次才进行两次IO操作 同时又保证了内存不容易被溢出.而具体缓存设置多少,要看你的服务器的能力和访问的人数来决定
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值