`
lxwt909
  • 浏览: 573466 次
  • 性别: 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的结果不一样

相关推荐

    Lucene5学习之自定义Collector

    这篇博客“Lucene5学习之自定义Collector”显然聚焦于如何在Lucene 5版本中通过自定义Collector来优化搜索结果的收集过程。Collector是Lucene搜索框架中的一个重要组件,它负责在搜索过程中收集匹配的文档,并根据...

    自己写的lucene分页高亮显示代码

    本压缩包中的代码着重展示了如何使用 Lucene 进行分页搜索和结果高亮显示。下面将详细解释这两个关键知识点。 **一、Lucene 分页搜索** 在大型数据集上进行搜索时,一次性返回所有结果并不实际,因此分页搜索显得...

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

    《Lucene学习实战系列:高亮与分页技术解析》 Lucene,作为Apache软件基金会的一个开源全文搜索引擎库,被广泛应用于各种搜索场景。本文将深入探讨如何在Lucene中实现高亮显示搜索结果和高效的分页功能,帮助开发者...

    一步一步跟我学习lucene(12)---lucene搜索之分组处理group查询

    在"一步一步跟我学习lucene(12)---lucene搜索之分组处理group查询"中,我们将重点关注如何利用Lucene实现这一高级搜索功能。 首先,Lucene是一个开源全文搜索引擎库,它为Java开发者提供了构建高效、可扩展的搜索...

    lucene4.8学习资料和案例

    2. 代码示例:通过分析提供的"lucene4.8学习资料和案例"压缩包,可以深入了解Lucene的实践操作,如创建索引、执行查询、处理结果等。 3. 在线教程:网络上有许多优秀的Lucene教程,如《Lucene in Action》一书的在线...

    Lucene分词与查询详解

    5. **评分(Scoring)**:Lucene会根据查询和文档的相关性给出一个分数,决定搜索结果的排序。TF-IDF(Term Frequency-Inverse Document Frequency)是最常用的评分算法。 现在,我们详细讲解如何在Lucene中进行...

    lucene学习资料

    这是另一份全面的Lucene学习资料,可能涵盖了Lucene的主要特性和应用,包括分析器的使用、查询解析、索引优化等。 6. **新闻系统全文检索的思绪.txt** 这篇文章可能探讨了在新闻系统中集成全文检索的策略,包括...

    lucene3.5学习笔记

    以上是对 Lucene 3.5 的学习笔记总结,涵盖了从索引构建到查询操作的基础和高级功能。通过深入理解这些概念和实践应用,可以帮助开发者更好地利用 Lucene 和 Solr 构建高效且功能强大的搜索应用。

    Lucene3.5的学习研究报告

    《深入探索Lucene 3.5:学习研究报告》 Lucene 3.5是一个重要的版本更新,它在2011年11月26日发布,为搜索引擎开发者提供了更高效、更稳定的功能。该版本在性能优化、新特性和错误修复上取得了显著的进步。 首先,...

    我封装的搜索引擎之lucene篇

    标题 "我封装的搜索引擎之lucene篇" 暗示了这个压缩包文件包含与Lucene搜索引擎相关的代码或文档。Lucene是Apache软件基金会的开源全文检索库,它提供了高级的文本分析和索引功能,使得开发者能够轻松地在应用程序中...

    luceneDemo

    **Lucene 概述** Lucene 是一个高性能、全文本搜索库...实际的 "luceneDemo" 可能包含更丰富的功能,例如支持多字段查询、高亮显示搜索结果、分页显示等。学习和理解 Lucene,可以帮助开发者构建强大的全文检索系统。

    lucene4.4 Demo事例

    《Lucene 4.4 实战教程:从基础到进阶》 Lucene是一个高性能、全文本搜索引擎库,由Apache软件基金会开发。...这个Demo案例旨在引导你入门,希望你在学习Lucene的旅程中找到乐趣,不断提高你的搜索引擎开发能力。

    Lucene视频教程_讲解部分源码

    5. **内存缓存与倒排索引优化**:Lucene提供缓存机制,如BitSet缓存,可以提高查询性能。同时,通过设置不同类型的Filter和FilterCache,可以进一步优化倒排索引的访问。 6. **实时搜索与更新**:Lucene支持实时...

    lucene学习03

    【标题】"lucene学习03" 涉及到的是Apache Lucene,这是一个高性能、全文本搜索引擎库,广泛应用于各种信息检索系统。在Lucene的学习过程中,我们通常会涵盖以下几个核心知识点: 1. **Lucene简介**:Lucene是一个...

    供lucene初学者学习的几个类

    在IT领域,Lucene是一个非常...然而,Lucene的功能远不止于此,它还包括过滤、排序、分页、高亮显示、近似查询等高级特性。随着对这些基础类的深入理解和实践,你将逐步掌握Lucene的精髓,并能灵活应用到实际项目中。

    LUCENE的搜索引擎例子

    5. **结果展示**:服务器将搜索结果返回给前端,前端通常会展示相关度最高的结果,并可能提供分页、排序等功能。 在`sample.dw.paper.lucene`这个压缩包中,很可能包含了示例代码,用于演示如何在实际项目中集成...

    lucene检索小例子

    总之,"lucene检索小例子"是一个实用的教程,通过它你可以学习到如何利用Lucene这一强大的全文搜索引擎库,实现高效、精准的文本检索功能。无论是在网站、数据库还是其他任何需要搜索功能的应用中,Lucene都是一个...

    Lucene3.0 使 用 教 程

    查询时,需要创建查询对象,使用查询执行器在索引库中执行查询,获取搜索结果,并根据需要对结果进行排序和分页。 通过学习Lucene3.0 使用教程,开发者能够掌握全文检索的基本原理和技术,为自己的应用系统添加高效...

    搜索引擎 Lucene PPT 教程

    5. 查询处理:用户输入查询后,Lucene解析查询语句,生成查询计划并执行,返回匹配的文档。 **三、主要组件** 1. **Analyzer**:负责文本分析,包括分词、去除停用词等。 2. **Document**:代表要索引的数据,包含...

Global site tag (gtag.js) - Google Analytics