`
lxwt909
  • 浏览: 566028 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Lucene5学习之分页查询

阅读更多

    上篇博文《Lucene5学习之创建索引入门示例》里我们创建了索引,现在我们来编写测试代码来查询索引,具体代码如下:

    

package com.yida.framework.lucene5.core;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;

import com.yida.framework.lucene5.util.Page;

/**
 * Lucene搜索第一个示例
 * @author Lanxiaowei
 *
 */
public class SearchFirstTest {
	public static void main(String[] args) throws ParseException, IOException {
		//参数定义
		String directoryPath = "D:/lucenedir";
		String fieldName = "contents";
		String queryString = "mount";
		int currentPage = 1;
		int pageSize = 10;
		
		Page<Document> page = pageQuery(fieldName, queryString, directoryPath, currentPage, pageSize);
		if(page == null || page.getItems() == null || page.getItems().size() == 0) {
			System.out.println("No results found.");
			return;
		}
		for(Document doc : page.getItems()) {
			String path = doc.get("path");
			String content = doc.get("contents");
			System.out.println("path:" + path);
			System.out.println("contents:" + content);
		}
	}
	/**
	 * 创建索引阅读器
	 * @param directoryPath  索引目录
	 * @return
	 * @throws IOException   可能会抛出IO异常
	 */
	public static IndexReader createIndexReader(String directoryPath) throws IOException {
		return DirectoryReader.open(FSDirectory.open(Paths.get(directoryPath, new String[0])));
	}
	
	/**
	 * 创建索引查询器
	 * @param directoryPath   索引目录
	 * @return
	 * @throws IOException
	 */
	public static IndexSearcher createIndexSearcher(String directoryPath) throws IOException {
		return new IndexSearcher(createIndexReader(directoryPath));
	}
	
	/**
	 * 创建索引查询器
	 * @param reader
	 * @return
	 */
	public static IndexSearcher createIndexSearcher(IndexReader reader) {
		return new IndexSearcher(reader);
	}
	
	/**
	 * Lucene分页查询
	 * @param directoryPath
	 * @param query
	 * @param page
	 * @throws IOException
	 */
	public static void pageQuery(String directoryPath,Query query,Page<Document> page) throws IOException {
		IndexSearcher searcher = createIndexSearcher(directoryPath);
		int totalRecord = searchTotalRecord(searcher,query);
		//设置总记录数
		page.setTotalRecord(totalRecord);
		TopDocs topDocs = searcher.searchAfter(page.getAfterDoc(),query, page.getPageSize());
		List<Document> docList = new ArrayList<Document>();
		ScoreDoc[] docs = topDocs.scoreDocs;
		int index = 0;
		for (ScoreDoc scoreDoc : docs) {
			int docID = scoreDoc.doc;
			Document document = searcher.doc(docID);
			if(index == docs.length - 1) {
				page.setAfterDoc(scoreDoc);
				page.setAfterDocId(docID);
			}
			docList.add(document);
			index++;
		}
		page.setItems(docList);
		searcher.getIndexReader().close();
	}
	
	/**
	 * 索引分页查询
	 * @param fieldName
	 * @param queryString
	 * @param currentPage
	 * @param pageSize
	 * @throws ParseException 
	 * @throws IOException 
	 */
	public static Page<Document> pageQuery(String fieldName,String queryString,String directoryPath,int currentPage,int pageSize) throws ParseException, IOException {
		QueryParser parser = new QueryParser(fieldName, new StandardAnalyzer());
		Query query = parser.parse(queryString);
		Page<Document> page = new Page<Document>(currentPage,pageSize);
		pageQuery(directoryPath, query, page);
		return page;
	}
	
	/**
	 * @Title: searchTotalRecord
	 * @Description: 获取符合条件的总记录数
	 * @param query
	 * @return
	 * @throws IOException
	 */
	public static int searchTotalRecord(IndexSearcher searcher,Query query) throws IOException {
		TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);
		if(topDocs == null || topDocs.scoreDocs == null || topDocs.scoreDocs.length == 0) {
			return 0;
		}
		ScoreDoc[] docs = topDocs.scoreDocs;
		return docs.length;
	}
}

 其实查询的核心代码就这一句:
    

searcher.searchAfter(page.getAfterDoc(),query, page.getPageSize());

 searchAfter方法用于分页,如果不需要分页,请使用search方法。

searchAfter需要接收3个参数:

1.afterDocId即下一个Document的id,

2.query接口实现类的对象,query对象可以通过QueryParser类来创建,也可以自己new Query接口的某一个特定接口实现类,Query接口内置有N种实现,具体请查阅Lucene API,这里附上本人制作的Lucene5.0 API文档下载地址:http://pan.baidu.com/s/1uEgB8

3.pageSize即每页显示几条,你懂的。

 

至于如何创建IndexSearcher实例请看代码,跟Lucene4.x的使用方式没什么太大的区别,有一个较大的区别就是Lucene5.0里打开索引目录采用的是NIO2.0的方式,在Lucene4.0里你打开索引目录是这样的:

FSDirectory.open(directoryPath); 

 这里的directoryPath为String类型即你的索引目录,而在Lucene5.0里,则是使用NIO2.0的方式:

FSDirectory.open(Paths.get(directoryPath, new String[0]))

 FSDirectory.open接收的参数不再是String类型而是Path类型。

 

 测试类里关联了一个自己写的Page分页工具类,代码如下:

package com.yida.framework.lucene5.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.search.ScoreDoc;
public class Page<T> {
	/**当前第几页(从1开始计算)*/
    private int currentPage;
    /**每页显示几条*/
    private int pageSize;
    /**总记录数*/
    private int totalRecord;
    /**总页数*/
    private int totalPage;
    /**分页数据集合[用泛型T来限定集合元素类型]*/
    private Collection<T> items;
    /**当前显示起始索引(从零开始计算)*/
    private int startIndex;
    /**当前显示结束索引(从零开始计算)*/
    private int endIndex;
    /**一组最多显示几个页码[比如Google一组最多显示10个页码]*/
    private int groupSize;
    
    /**左边偏移量*/
    private int leftOffset = 5;
    /**右边偏移量*/
    private int rightOffset = 4;
    /**当前页码范围*/
    private String[] pageRange;
    
    /**分页数据*/
    private List<Document> docList;
    /**上一页最后一个ScoreDoc对象*/
    private ScoreDoc afterDoc;
    
    /**上一页最后一个ScoreDoc对象的Document对象ID*/
    private int afterDocId;

	public void setRangeIndex() {
		int groupSize = getGroupSize();
		int totalPage = getTotalPage();
		if(totalPage < 2) {
			startIndex = 0;
			endIndex = totalPage - startIndex;
		} else {
			int currentPage = getCurrentPage();
			if(groupSize >= totalPage) {
				startIndex = 0;
				endIndex = totalPage - startIndex - 1;
			} else {
				int leftOffset = getLeftOffset();
				int middleOffset = getMiddleOffset();
				if(-1 == middleOffset) {
					startIndex = 0;
					endIndex = groupSize - 1;
				} else if(currentPage <= leftOffset) {
					startIndex = 0;
					endIndex = groupSize - 1;
				} else {
					startIndex = currentPage - leftOffset - 1;
					if(currentPage + rightOffset > totalPage) {
						endIndex = totalPage - 1;
					} else {
						endIndex = currentPage + rightOffset - 1;
					}
				}
			}
		}
	}
    
	public int getCurrentPage() {
		if(currentPage <= 0) {
			currentPage = 1;
		} else {
			int totalPage = getTotalPage();
			if(totalPage > 0 && currentPage > getTotalPage()) {
				currentPage = totalPage;
			}
		}
		return currentPage;
	}
	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}
	public int getPageSize() {
		if(pageSize <= 0) {
			pageSize = 10;
		}
		return pageSize;
	}
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}
	public int getTotalRecord() {
		return totalRecord;
	}
	public void setTotalRecord(int totalRecord) {
		this.totalRecord = totalRecord;
	}
	public int getTotalPage() {
		int totalRecord = getTotalRecord();
		if(totalRecord == 0) {
			totalPage = 0;
		} else {
			int pageSize = getPageSize();
			totalPage = totalRecord % pageSize == 0 ? totalRecord / pageSize : (totalRecord / pageSize) + 1;
		}
		return totalPage;
	}
	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}
	
	public int getStartIndex() {
		return startIndex;
	}
	public void setStartIndex(int startIndex) {
		this.startIndex = startIndex;
	}
	
	public int getEndIndex() {
		return endIndex;
	}
	public void setEndIndex(int endIndex) {
		this.endIndex = endIndex;
	}
	public int getGroupSize() {
		if(groupSize <= 0) {
			groupSize = 10;
		}
		return groupSize;
	}
	public void setGroupSize(int groupSize) {
		this.groupSize = groupSize;
	}
	
	public int getLeftOffset() {
		leftOffset = getGroupSize() / 2;
		return leftOffset;
		
	}
	public void setLeftOffset(int leftOffset) {
		this.leftOffset = leftOffset;
	}
	public int getRightOffset() {
		int groupSize = getGroupSize();
		if(groupSize % 2 == 0) {
			rightOffset = (groupSize / 2) - 1;
		} else {
			rightOffset = groupSize / 2;
		}
		return rightOffset;
	}
	public void setRightOffset(int rightOffset) {
		this.rightOffset = rightOffset;
	}
	
	/**中心位置索引[从1开始计算]*/
	public int getMiddleOffset() {
		int groupSize = getGroupSize();
		int totalPage = getTotalPage();
		if(groupSize >= totalPage) {
			return -1;
		}
		return getLeftOffset() + 1;
	}
	public String[] getPageRange() {
		setRangeIndex();
		int size = endIndex - startIndex + 1;
		if(size <= 0) {
			return new String[0];
		}
		if(totalPage == 1) {
			return new String[] {"1"};
		}
		pageRange = new String[size];
		for(int i=0; i < size; i++) {
			pageRange[i] = (startIndex + i + 1) + "";
		}
		return pageRange;
	}

	public void setPageRange(String[] pageRange) {
		this.pageRange = pageRange;
	}

	public Collection<T> getItems() {
		return items;
	}
	public void setItems(Collection<T> items) {
		this.items = items;
	}
	
	public List<Document> getDocList() {
		return docList;
	}

	public void setDocList(List<Document> docList) {
		this.docList = docList;
	}

	public ScoreDoc getAfterDoc() {
		setAfterDocId(afterDocId);
		return afterDoc;
	}

	public void setAfterDoc(ScoreDoc afterDoc) {
		this.afterDoc = afterDoc;
	}
	
	public int getAfterDocId() {
		return afterDocId;
	}

	public void setAfterDocId(int afterDocId) {
		this.afterDocId = afterDocId;
		if(null == afterDoc) {
			this.afterDoc = new ScoreDoc(afterDocId, 1.0f);
		}
	}
	
	public Page() {}

	public Page(int currentPage, int pageSize) {
		this.currentPage = currentPage;
		this.pageSize = pageSize;
	}

	public Page(int currentPage, int pageSize, Collection<T> items) {
		this.currentPage = currentPage;
		this.pageSize = pageSize;
		this.items = items;
	}

	public Page(int currentPage, int pageSize, Collection<T> items, int groupSize) {
		this.currentPage = currentPage;
		this.pageSize = pageSize;
		this.items = items;
		this.groupSize = groupSize;
	}

	public Page(int currentPage, int pageSize, int groupSize, int afterDocId) {
		this.currentPage = currentPage;
		this.pageSize = pageSize;
		this.groupSize = groupSize;
		this.afterDocId = afterDocId;
	}

	public static void main(String[] args) {
		Collection<Integer> items = new ArrayList<Integer>();
		int totalRecord = 201;
		for(int i=0; i < totalRecord; i++) {
			items.add(new Integer(i));
		}
		Page<Integer> page = new Page<Integer>(1,10,items,10);
		page.setTotalRecord(totalRecord);
		int totalPage = page.getTotalPage();
		for(int i=0; i < totalPage; i++) {
			page.setCurrentPage(i+1);
			String[] pageRange = page.getPageRange();
			System.out.println("当前第" + page.currentPage + "页");
			for(int j=0; j < pageRange.length; j++) {
				System.out.print(pageRange[j] + "  ");
			}
			System.out.println("\n");
		}	
	}
}

 

来张运行效果图大家感受下:

 

 demo源代码请在附件里下载,千言万语都在代码中,你们懂的。

若你还有什么疑问,请加我Q-Q:7-3-6-0-3-1-3-0-5,或者加裙:

,欢迎你加入一起交流学习。
 

 

  • 大小: 6 KB
  • 大小: 546.9 KB
分享到:
评论
5 楼 banana1120 2016-05-04  
这边使用普通的WildcardQuery 查询,100条结果使用9S,使用分页带WildcardQuery 查询第一页100条使用了24489 ms,,,,怎么破?原文件2G,创建索引3.4G,xls格式文件
4 楼 永志_爱戴 2016-04-02  
搜索第一页的时候,Page对象的afterDocId没有被赋值,默认是0,所以你的搜索会把docId等于零的文档给跳过去
3 楼 majiedota 2015-06-29  
达子给力,评论细心啊
2 楼 lxwt909 2015-04-15  
tianyaluke 写道
类SearchFirstTest的89行,须改成TopDocs topDocs = searcher.searchAfter(fieldDoc, query, page.getPageSize(), sort);否则page.getPageSize()=10,page.getCurrentPage()=1加上page.getCurrentPage()=2的结果跟page.getPageSize()=20,page.getCurrentPage()=1的结果不一样

感谢你的指正,你非常细心
1 楼 tianyaluke 2015-04-15  
类SearchFirstTest的89行,须改成TopDocs topDocs = searcher.searchAfter(fieldDoc, query, page.getPageSize(), sort);否则page.getPageSize()=10,page.getCurrentPage()=1加上page.getCurrentPage()=2的结果跟page.getPageSize()=20,page.getCurrentPage()=1的结果不一样

相关推荐

    lucene查询工具类和IndexSearcher分页查询示例

    一步一步跟我学习lucene是对近期做lucene索引的总结,大家有问题的话联系本人如蒙加入,不胜感激,大家共同探讨,本人争取每日一博,希望大家持续关注,会带给大家惊喜的

    Lucene 3.6 学习笔记

    2.4 查询索引的基本信息 5 2.5 删除和更新索引 5 (1) 使用writer删除 5 (2) 使用reader删除 5 (3) 恢复删除 5 (4) 彻底删除 6 (5) 更新索引 6 (6) 手动优化 6 2.6 索引文件作用 7 第三章 搜索功能 8 3.1 简单搜索 8 ...

    lucene4.8学习资料和案例

    lucene4.8学习资料和案例,自己学习整理。整理了各种查询,包括分页、排序等!对100W,500W,1000W三个级别的数据量分别进行了测试!

    lucene3.5学习笔记

    介绍lucene3.5的相关技术,包括基本用法、分析器、索引建立与查询,扩展的高亮、分页、以及solr3.5的相关用法

    lucene4.4 Demo事例

    lucene4.,4事例,包含lucene4.4的增删改查,分页查询,适合更开始接触搜索引擎的朋友参考,下载了包你不后悔,因为我也是初学者,根据一些资源学习后,自己写的,适合大家参考

    lucene 学习实战系列(高亮+分页)

    NULL 博文链接:https://hellotommy.iteye.com/blog/826318

    lucene 3.6 检索文件 pdf word ppt excel txt html xml

    基本可以满足 检索电脑内文件的需求了 已经封装过了 直接指定检索目录和索引目录来创建索引.提供给学习者门参考... 直接通过调用静态方法来实现 深度分页检索.

    自己动手写搜索引擎

    该书详细讲解了搜索引擎与信息检索基础,Lucene入门实例,Lucene索引的建立,使用Lucene进行搜索,排序,过滤和分页,Lucene的分析器,对Word、Excel和PDF格式文档的处理,Compass搜索引擎框架,Lucene分布式和...

    Jeecms2012版标签学习手册

    一、2012版关键字标签[@cms_tag_list] 二、2012版搜索结果分页标签[@cms_lucene_page] 三、2012版页面模板包含标签[@cms_Include] 四、2012版留言列表标签[@cms_guestbook_list] ...

    my-ssm-blog:暑假学习ssm架构的时候,花了半个月写的一款博客系统;欢迎喜欢技术的朋友来交流技术

    暑假学习ssm架构的时候,花了半个月写的一款博客系统,页面展示如下后台 功能 后台 文章管理 友链管理 公告管理 评论管理 用户管理 链接管理 后台其他设置 前台 浏览文章 文章分类查找 文章标签查找 按关键字搜索...

    jive.chm

    系统设计 1 jive设计思路 2 jive的工作内幕 3 Jive源代码研究 4 Jive中的设计模式 5 jive学习笔记 &lt;br&gt; 设计模式 1 大道至简-Java之23种模式一点就通 2 设计模式...

    Jive资料集

    系统设计 1 jive设计思路 2 jive的工作内幕 3 Jive源代码研究 4 Jive中的设计模式 5 jive学习笔记 &lt;br&gt; &lt;br&gt; 数据库设计 1 Jive Forums数据库说明(英文) 2 Jive KB...

    Eclipse开发分布式商城系统+完整视频代码及文档

    │ 12-MySQL的查询优化.avi │ 13-数据库结构优化.avi │ 14-插入数据的优化.avi │ 15-服务器优化.avi │ 16-tomcat的3种运行模式和执行器(线程池).avi │ 17-tomcat中连接器.avi │ 18-禁用AJP连接器.avi │ 19-...

    JAVA上百实例源码以及开源项目源代码

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    史上最好传智播客就业班.net培训教程60G 不下会后悔

    数据库开发基础、Microsoft SQLServer基础、SQL语言基础、索引、事务、SQL语言高级技术(空值处理、聚合与分组、数据分页、Union、日期函数、类型转换函数、流控函数、表连接、子查询、存储过程、触发器)、数据库...

    JAVA上百实例源码以及开源项目

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

Global site tag (gtag.js) - Google Analytics