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

Lucene5学习之LuceneUtils工具类简单封装

阅读更多

     周六花了整整一下午,将Lucene5中有关索引的常见操作进行了简单封装,废话不多说,上代码:

 

package com.yida.framework.lucene5.util;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.lucene.index.DirectoryReader;
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.LockObtainFailedException;
/**
 * Lucene索引读写器/查询器单例获取工具类
 * @author Lanxiaowei
 *
 */
public class LuceneManager {
	private volatile static LuceneManager singleton;
	
	private volatile static IndexWriter writer;
	
	private volatile static IndexReader reader;
	
	private volatile static IndexSearcher searcher;
	
	private final Lock writerLock = new ReentrantLock();
	
	//private final Lock readerLock = new ReentrantLock();
	
	//private final Lock searcherLock = new ReentrantLock();

	private LuceneManager() {}

	public static LuceneManager getInstance() {
		if (null == singleton) {
			synchronized (LuceneManager.class) {
				if (null == singleton) {
					singleton = new LuceneManager();
				}
			}
		}
		return singleton;
	}

	/**
	 * 获取IndexWriter单例对象
	 * @param dir
	 * @param config
	 * @return
	 */
	public IndexWriter getIndexWriter(Directory dir, IndexWriterConfig config) {
		if(null == dir) {
			throw new IllegalArgumentException("Directory can not be null.");
		}
		if(null == config) {
			throw new IllegalArgumentException("IndexWriterConfig can not be null.");
		}
		try {
			writerLock.lock();
			if(null == writer){
				//如果索引目录被锁,则直接抛异常
				if(IndexWriter.isLocked(dir)) {
					throw new LockObtainFailedException("Directory of index had been locked.");
				}
				writer = new IndexWriter(dir, config);
			}
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			writerLock.unlock();
		}
		return writer;
	}
	
	/**
	 * 获取IndexReader对象
	 * @param dir
	 * @param enableNRTReader  是否开启NRTReader
	 * @return
	 */
	public IndexReader getIndexReader(Directory dir,boolean enableNRTReader) {
		if(null == dir) {
			throw new IllegalArgumentException("Directory can not be null.");
		}
		try {
			if(null == reader){
				reader = DirectoryReader.open(dir);
			} else {
				if(enableNRTReader && reader instanceof DirectoryReader) {
					//开启近实时Reader,能立即看到动态添加/删除的索引变化
					reader = DirectoryReader.openIfChanged((DirectoryReader)reader);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return reader;
	}
	
	/**
	 * 获取IndexReader对象(默认不启用NETReader)
	 * @param dir
	 * @return
	 */
	public IndexReader getIndexReader(Directory dir) {
		return getIndexReader(dir, false);
	}
	
	/**
	 * 获取IndexSearcher对象
	 * @param reader    IndexReader对象实例
	 * @param executor  如果你需要开启多线程查询,请提供ExecutorService对象参数
	 * @return
	 */
	public IndexSearcher getIndexSearcher(IndexReader reader,ExecutorService executor) {
		if(null == reader) {
			throw new IllegalArgumentException("The indexReader can not be null.");
		}
		if(null == searcher){
			searcher = new IndexSearcher(reader);
		}
		return searcher;
	}
	
	/**
	 * 获取IndexSearcher对象(不支持多线程查询)
	 * @param reader    IndexReader对象实例
	 * @return
	 */
	public IndexSearcher getIndexSearcher(IndexReader reader) {
		return getIndexSearcher(reader, null);
	}
}

 

package com.yida.framework.lucene5.util;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;

import org.ansj.lucene5.AnsjAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
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.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.Scorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

/**
 * Lucene工具类(基于Lucene5.0封装)
 * @author Lanxiaowei
 *
 */
public class LuceneUtils {
	private static final LuceneManager luceneManager = LuceneManager.getInstance();
	private static Analyzer analyzer = new AnsjAnalyzer();
	
	/**
	 * 打开索引目录
	 * 
	 * @param luceneDir
	 * @return
	 * @throws IOException
	 */
	public static FSDirectory openFSDirectory(String luceneDir) {
		FSDirectory directory = null;
		try {
			directory = FSDirectory.open(Paths.get(luceneDir));
			/**
			 * 注意:isLocked方法内部会试图去获取Lock,如果获取到Lock,会关闭它,否则return false表示索引目录没有被锁,
			 * 这也就是为什么unlock方法被从IndexWriter类中移除的原因
			 */
			IndexWriter.isLocked(directory);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return directory;
	}
	
	/**
	 * 关闭索引目录并销毁
	 * @param directory
	 * @throws IOException
	 */
	public static void closeDirectory(Directory directory) throws IOException {
		if (null != directory) {
			directory.close();
			directory = null;
		}
	}
	
	/**
	 * 获取IndexWriter
	 * @param dir
	 * @param config
	 * @return
	 */
	public static IndexWriter getIndexWrtier(Directory dir, IndexWriterConfig config) {
		return luceneManager.getIndexWriter(dir, config);
	}
	
	/**
	 * 获取IndexWriter
	 * @param dir
	 * @param config
	 * @return
	 */
	public static IndexWriter getIndexWrtier(String directoryPath, IndexWriterConfig config) {
		FSDirectory directory = openFSDirectory(directoryPath);
		return luceneManager.getIndexWriter(directory, config);
	}
	
	/**
	 * 获取IndexReader
	 * @param dir
	 * @param enableNRTReader  是否开启NRTReader
	 * @return
	 */
	public static IndexReader getIndexReader(Directory dir,boolean enableNRTReader) {
		return luceneManager.getIndexReader(dir, enableNRTReader);
	}
	
	/**
	 * 获取IndexReader(默认不启用NRTReader)
	 * @param dir
	 * @return
	 */
	public static IndexReader getIndexReader(Directory dir) {
		return luceneManager.getIndexReader(dir);
	}
	
	/**
	 * 获取IndexSearcher
	 * @param reader    IndexReader对象
	 * @param executor  如果你需要开启多线程查询,请提供ExecutorService对象参数
	 * @return
	 */
	public static IndexSearcher getIndexSearcher(IndexReader reader,ExecutorService executor) {
		return luceneManager.getIndexSearcher(reader, executor);
	}
	
	/**
	 * 获取IndexSearcher(不支持多线程查询)
	 * @param reader    IndexReader对象
	 * @return
	 */
	public static IndexSearcher getIndexSearcher(IndexReader reader) {
		return luceneManager.getIndexSearcher(reader);
	}
	
	/**
	 * 创建QueryParser对象
	 * @param field
	 * @param analyzer
	 * @return
	 */
	public static QueryParser createQueryParser(String field, Analyzer analyzer) {
		return new QueryParser(field, analyzer);
	}
	
	/**
	 * 关闭IndexReader
	 * @param reader
	 */
	public static void closeIndexReader(IndexReader reader) {
		if (null != reader) {
			try {
				reader.close();
				reader = null;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 关闭IndexWriter
	 * @param writer
	 */
	public static void closeIndexWriter(IndexWriter writer) {
		if(null != writer) {
			try {
				writer.close();
				writer = null;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 关闭IndexReader和IndexWriter
	 * @param reader
	 * @param writer
	 */
	public static void closeAll(IndexReader reader, IndexWriter writer) {
		closeIndexReader(reader);
		closeIndexWriter(writer);
	}
	
	/**
	 * 删除索引[注意:请自己关闭IndexWriter对象]
	 * @param writer
	 * @param field
	 * @param value
	 */
	public static void deleteIndex(IndexWriter writer, String field, String value) {
		try {
			writer.deleteDocuments(new Term[] {new Term(field,value)});
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 删除索引[注意:请自己关闭IndexWriter对象]
	 * @param writer
	 * @param query
	 */
	public static void deleteIndex(IndexWriter writer, Query query) {
		try {
			writer.deleteDocuments(query);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 批量删除索引[注意:请自己关闭IndexWriter对象]
	 * @param writer
	 * @param terms
	 */
	public static void deleteIndexs(IndexWriter writer,Term[] terms) {
		try {
			writer.deleteDocuments(terms);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 批量删除索引[注意:请自己关闭IndexWriter对象]
	 * @param writer
	 * @param querys
	 */
	public static void deleteIndexs(IndexWriter writer,Query[] querys) {
		try {
			writer.deleteDocuments(querys);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 删除所有索引文档
	 * @param writer
	 */
	public static void deleteAllIndex(IndexWriter writer) {
		try {
			writer.deleteAll();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 更新索引文档
	 * @param writer
	 * @param term
	 * @param document
	 */
	public static void updateIndex(IndexWriter writer,Term term,Document document) {
		try {
			writer.updateDocument(term, document);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 更新索引文档
	 * @param writer
	 * @param term
	 * @param document
	 */
	public static void updateIndex(IndexWriter writer,String field,String value,Document document) {
		updateIndex(writer, new Term(field, value), document);
	}
	
	/**
	 * 添加索引文档
	 * @param writer
	 * @param doc
	 */
	public static void addIndex(IndexWriter writer, Document document) {
		updateIndex(writer, null, document);
	}
	
	/**
	 * 索引文档查询
	 * @param searcher
	 * @param query
	 * @return
	 */
	public static List<Document> query(IndexSearcher searcher,Query query) {
		TopDocs topDocs = null;
		try {
			topDocs = searcher.search(query, Integer.MAX_VALUE);
		} catch (IOException e) {
			e.printStackTrace();
		}
		ScoreDoc[] scores = topDocs.scoreDocs;
		int length = scores.length;
		if (length <= 0) {
			return Collections.emptyList();
		}
		List<Document> docList = new ArrayList<Document>();
		try {
			for (int i = 0; i < length; i++) {
				Document doc = searcher.doc(scores[i].doc);
				docList.add(doc);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return docList;
	}
	
	/**
	 * 返回索引文档的总数[注意:请自己手动关闭IndexReader]
	 * @param reader
	 * @return
	 */
	public static int getIndexTotalCount(IndexReader reader) {
		return reader.numDocs();
	}
	
	/**
	 * 返回索引文档中最大文档ID[注意:请自己手动关闭IndexReader]
	 * @param reader
	 * @return
	 */
	public static int getMaxDocId(IndexReader reader) {
		return reader.maxDoc();
	}
	
	/**
	 * 返回已经删除尚未提交的文档总数[注意:请自己手动关闭IndexReader]
	 * @param reader
	 * @return
	 */
	public static int getDeletedDocNum(IndexReader reader) {
		return getMaxDocId(reader) - getIndexTotalCount(reader);
	}
	
	/**
	 * 根据docId查询索引文档
	 * @param reader         IndexReader对象
	 * @param docID          documentId
	 * @param fieldsToLoad   需要返回的field
	 * @return
	 */
	public static Document findDocumentByDocId(IndexReader reader,int docID, Set<String> fieldsToLoad) {
		try {
			return reader.document(docID, fieldsToLoad);
		} catch (IOException e) {
			return null;
		}
	}
	
	/**
	 * 根据docId查询索引文档
	 * @param reader         IndexReader对象
	 * @param docID          documentId
	 * @return
	 */
	public static Document findDocumentByDocId(IndexReader reader,int docID) {
		return findDocumentByDocId(reader, docID, null);
	}
	
	/**
	 * @Title: createHighlighter
	 * @Description: 创建高亮器
	 * @param query             索引查询对象
	 * @param prefix            高亮前缀字符串
	 * @param stuffix           高亮后缀字符串
	 * @param fragmenterLength  摘要最大长度
	 * @return
	 */
	public static Highlighter createHighlighter(Query query, String prefix, String stuffix, int fragmenterLength) {
		Formatter formatter = new SimpleHTMLFormatter((prefix == null || prefix.trim().length() == 0) ? 
			"<font color=\"red\">" : prefix, (stuffix == null || stuffix.trim().length() == 0)?"</font>" : stuffix);
		Scorer fragmentScorer = new QueryScorer(query);
		Highlighter highlighter = new Highlighter(formatter, fragmentScorer);
		Fragmenter fragmenter = new SimpleFragmenter(fragmenterLength <= 0 ? 50 : fragmenterLength);
		highlighter.setTextFragmenter(fragmenter);
		return highlighter;
	}
	
	/**
	 * @Title: highlight
	 * @Description: 生成高亮文本
	 * @param document          索引文档对象
	 * @param highlighter       高亮器
	 * @param analyzer          索引分词器
	 * @param field             高亮字段
	 * @return
	 * @throws IOException
	 * @throws InvalidTokenOffsetsException
	 */
	public static String highlight(Document document,Highlighter highlighter,Analyzer analyzer,String field) throws IOException {
		List<IndexableField> list = document.getFields();
		for (IndexableField fieldable : list) {
			String fieldValue = fieldable.stringValue();
			if(fieldable.name().equals(field)) {
				try {
					fieldValue = highlighter.getBestFragment(analyzer, field, fieldValue);
				} catch (InvalidTokenOffsetsException e) {
					fieldValue = fieldable.stringValue();
				}
				return (fieldValue == null || fieldValue.trim().length() == 0)? fieldable.stringValue() : fieldValue;
			}
		}
		return null;
	}
	
	/**
	 * @Title: searchTotalRecord
	 * @Description: 获取符合条件的总记录数
	 * @param query
	 * @return
	 * @throws IOException
	 */
	public static int searchTotalRecord(IndexSearcher search,Query query) {
		ScoreDoc[] docs = null;
		try {
			TopDocs topDocs = search.search(query, Integer.MAX_VALUE);
			if(topDocs == null || topDocs.scoreDocs == null || topDocs.scoreDocs.length == 0) {
				return 0;
			}
			docs = topDocs.scoreDocs;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return docs.length;
	}
	
	/**
	 * @Title: pageQuery
	 * @Description: Lucene分页查询
	 * @param searcher
	 * @param query
	 * @param page
	 * @throws IOException
	 */
	public static void pageQuery(IndexSearcher searcher,Directory directory,Query query,Page<Document> page) {
		int totalRecord = searchTotalRecord(searcher,query);
		//设置总记录数
		page.setTotalRecord(totalRecord);
		TopDocs topDocs = null;
		try {
			topDocs = searcher.searchAfter(page.getAfterDoc(),query, page.getPageSize());
		} catch (IOException e) {
			e.printStackTrace();
		}
		List<Document> docList = new ArrayList<Document>();
		ScoreDoc[] docs = topDocs.scoreDocs;
		int index = 0;
		for (ScoreDoc scoreDoc : docs) {
			int docID = scoreDoc.doc;
			Document document = null;
			try {
				document = searcher.doc(docID);
			} catch (IOException e) {
				e.printStackTrace();
			}
			if(index == docs.length - 1) {
				page.setAfterDoc(scoreDoc);
				page.setAfterDocId(docID);
			}
			docList.add(document);
			index++;
		}
		page.setItems(docList);
		closeIndexReader(searcher.getIndexReader());
	}
	
	/**
	 * @Title: pageQuery
	 * @Description: 分页查询[如果设置了高亮,则会更新索引文档]
	 * @param searcher
	 * @param directory
	 * @param query
	 * @param page
	 * @param highlighterParam
	 * @param writerConfig
	 * @throws IOException
	 */
	public static void pageQuery(IndexSearcher searcher,Directory directory,Query query,Page<Document> page,HighlighterParam highlighterParam,IndexWriterConfig writerConfig) throws IOException {
		IndexWriter writer = null;
		//若未设置高亮
		if(null == highlighterParam || !highlighterParam.isHighlight()) {
			pageQuery(searcher,directory,query, page);
		} else {
			int totalRecord = searchTotalRecord(searcher,query);
			System.out.println("totalRecord:" + totalRecord);
			//设置总记录数
			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;
			writer = getIndexWrtier(directory, writerConfig);
			for (ScoreDoc scoreDoc : docs) {
				int docID = scoreDoc.doc;
				Document document = searcher.doc(docID);
				String content = document.get(highlighterParam.getFieldName());
				if(null != content && content.trim().length() > 0) {
					//创建高亮器
					Highlighter highlighter = LuceneUtils.createHighlighter(query, 
						highlighterParam.getPrefix(), highlighterParam.getStuffix(), 
						highlighterParam.getFragmenterLength());
					String text = highlight(document, highlighter, analyzer, highlighterParam.getFieldName());
					//若高亮后跟原始文本不相同,表示高亮成功
					if(!text.equals(content)) {
						Document tempdocument = new Document();
						List<IndexableField> indexableFieldList = document.getFields();
						if(null != indexableFieldList && indexableFieldList.size() > 0) {
							for(IndexableField field : indexableFieldList) {
								if(field.name().equals(highlighterParam.getFieldName())) {
									tempdocument.add(new TextField(field.name(), text, Field.Store.YES));
								} else {
									tempdocument.add(field);
								}
							}
						}
						updateIndex(writer, new Term(highlighterParam.getFieldName(),content), tempdocument);
						document = tempdocument;
					}
				}
				if(index == docs.length - 1) {
					page.setAfterDoc(scoreDoc);
					page.setAfterDocId(docID);
				}
				docList.add(document);
				index++;
			}
			page.setItems(docList);
		}
		closeIndexReader(searcher.getIndexReader());
		closeIndexWriter(writer);
	}
}

 

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");
		}	
	}
}

 

package com.yida.framework.lucene5.util;
/**
 * @ClassName: HighlighterParam
 * @Description: 高亮器参数对象
 * @author Lanxiaowei
 * @date 2014-3-30 下午12:22:08
 */
public class HighlighterParam {
	/**是否需要设置高亮*/
	private boolean highlight;
	/**需要设置高亮的属性名*/
	private String fieldName;
	/**高亮前缀*/
	private String prefix;
	/**高亮后缀*/
	private String stuffix;
	/**显示摘要最大长度*/
	private int fragmenterLength;
	public boolean isHighlight() {
		return highlight;
	}
	public void setHighlight(boolean highlight) {
		this.highlight = highlight;
	}
	public String getFieldName() {
		return fieldName;
	}
	public void setFieldName(String fieldName) {
		this.fieldName = fieldName;
	}
	public String getPrefix() {
		return prefix;
	}
	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}
	public String getStuffix() {
		return stuffix;
	}
	public void setStuffix(String stuffix) {
		this.stuffix = stuffix;
	}
	public int getFragmenterLength() {
		return fragmenterLength;
	}
	public void setFragmenterLength(int fragmenterLength) {
		this.fragmenterLength = fragmenterLength;
	}
	public HighlighterParam(boolean highlight, String fieldName, String prefix, String stuffix, int fragmenterLength) {
		this.highlight = highlight;
		this.fieldName = fieldName;
		this.prefix = prefix;
		this.stuffix = stuffix;
		this.fragmenterLength = fragmenterLength;
	}
	
	public HighlighterParam(boolean highlight, String fieldName, int fragmenterLength) {
		this.highlight = highlight;
		this.fieldName = fieldName;
		this.fragmenterLength = fragmenterLength;
	}
	
	public HighlighterParam(boolean highlight, String fieldName, String prefix, String stuffix) {
		this.highlight = highlight;
		this.fieldName = fieldName;
		this.prefix = prefix;
		this.stuffix = stuffix;
	}
	public HighlighterParam() {
	}
}

    工具类对IndexWriter,IndexReader,IndexSearcher,Analyzer,QueryParser等Lucene这些常用操作对象的获取进行了封装,其中IndexWriter采用了单例模式,确保始终只有一个对象实例,因为Lucene限制了索引写操作是阻塞的,即同一时刻只能有一个IndexWriter在执行写操作,直到indexWriter释放lock,而索引读的操作是可以并发进行的。如果你不想复制粘帖的话,请到最底下的附件里去下载源码。

    如果有哪里封装的不够合理,还望大家指正,多批评,谢谢!

 

    如果你还有什么问题请加我Q-Q:7-3-6-0-3-1-3-0-5,

或者加裙
一起交流学习!

 

5
1
分享到:
评论
14 楼 w592376568 2018-08-30  
博主:添加后修改索引后,如何实现实时搜索啊??
13 楼 mohaoyang 2018-05-25  
同意12楼的说法,close方法,单例的意义如何,每次close完indexWriter之后,就不能再使用了
12 楼 zjj350 2016-12-13  
有几个疑问:
1、LuceneUtils的closeIndexWriter方法中,writer = null;这名话是无效的,writer只是对象引用,是不可能在方法中置空的。
2、indexwriter的单例模式意义在哪里?每次获取indexwriter后,索引更新后,都需要close,也就是这时indexwriter已经不能再用了,下次再用需要重新new一个indexwriter。
3、多线程模式下,每个一线程都持有一个indexwriter(由于是单例 ,所以肯定是同一个实例 ),当第一个线程完成索引更新并关闭后,其它线程持有的indexwriter都无效,导致报错。
欢迎交流 14787712
11 楼 蜡笔小色妞 2016-06-15  
可以暂时使用IK分词器进行测试
10 楼 世界杯2009 2016-05-26  
LinApex 写道
org.ansj.lucene5.AnsjAnalyzer 类没有提供,项目跑不起来

看这里
http://codepub.cn/2016/03/23/Maven-project-integrating-Lucene-Chinese-Segmentation-tools-Jcseg-and-Ansj/
9 楼 世界杯2009 2016-05-26  
错误太多,open(final IndexWriter writer) 这个是开启NRT搜索
DirectoryReader.openIfChanged((DirectoryReader)reader);  这个只是重新开一个reader,并且索引无变化的话,该方法返回null,你根本拿不到reader。
8 楼 世界杯2009 2016-05-26  
世界杯2009 写道
yj963552657 写道
学习了。锁用的多了。

这里writerLock.lock();用锁完全是多余的。

还有这里IndexWriter.isLocked()也是多余
FSDirectory.open的时候会自动去获取锁,获取不到自动抛异常。
7 楼 世界杯2009 2016-05-26  
yj963552657 写道
学习了。锁用的多了。

这里writerLock.lock();用锁完全是多余的。
6 楼 LinApex 2015-11-19  
org.ansj.lucene5.AnsjAnalyzer 类没有提供,项目跑不起来
5 楼 yj963552657 2015-10-20  
学习了。锁用的多了。
4 楼 fdgghghjfgh 2015-10-01  
请问lucene5集成这个ansj分词器不需要设置哪种分词方式吗?
3 楼 ctwen 2015-08-22  
east.net 写道
org.ansj.lucene5.AnsjAnalyzer这个类在哪个包中,一直没有找到。
ansj_seg-2.0.8.jar中没有啊

自己拿ansj_lucene4_plug源码改造,不难。
2 楼 Given_xing 2015-07-10  
跟1楼同问。。。 
1 楼 east.net 2015-04-22  
org.ansj.lucene5.AnsjAnalyzer这个类在哪个包中,一直没有找到。
ansj_seg-2.0.8.jar中没有啊

相关推荐

    Lucene5 工具类

    工具类对IndexWriter,IndexReader,IndexSearcher,Analyzer,QueryParser等Lucene这些常用操作对象的获取进行了封装,其中IndexWriter采用了单例模式,确保始终只有一个对象实例,因为Lucene限制了索引写操作是阻塞的...

    java Lucene 工具类

    总之,Java Lucene工具类是开发者实现全文搜索功能的强大助手,通过博主的示例,我们可以学习到如何有效地利用Lucene进行文本索引和搜索,提升应用程序的信息检索能力。这个“LuceneDemo”对于想要深入了解和应用...

    Lucene5学习之Facet(续)

    《Lucene5学习之Facet(续)》 在深入探讨Lucene5的Facet功能之前,我们先来了解一下什么是Faceting。Faceting是搜索引擎提供的一种功能,它允许用户通过分类或属性对搜索结果进行细分,帮助用户更精确地探索和理解...

    LUCENE5.2工具封装

    基于java的lucene 5.2的封装,主要包括lucene的各种查询方法、建索引方法的实现,为使用lucene开发者提供便利,而不需要过多的lucene知识即可使用,具体使用方法请到github上download,里面有完整的demo。...

    我封装的搜索引擎之lucene篇

    2. **搜索工具封装**:可能包含一个自定义的搜索引擎工具类,简化了Lucene的调用过程,便于集成到其他项目中。 3. **配置管理**:"search.xml"可能涉及到的配置项,如索引目录、分析器配置、搜索结果分页设置等。 4....

    Lucene5学习之SpellCheck拼写纠错

    **标题:“Lucene5学习之SpellCheck拼写纠错”** 在深入探讨Lucene5的SpellCheck功能之前,首先需要理解Lucene是什么。Lucene是一个开源的全文检索库,由Apache软件基金会开发,它提供了高性能、可扩展的文本搜索...

    Lucene5学习之Group分组统计

    "Lucene5学习之Group分组统计" 这个标题指出我们要讨论的是关于Apache Lucene 5版本中的一个特定功能——Grouping。在信息检索领域,Lucene是一个高性能、全文搜索引擎库,而Grouping是它提供的一种功能,允许用户对...

    Lucene5学习之排序-Sort

    “Lucene5学习之排序-Sort”这个标题表明了我们要探讨的是关于Apache Lucene 5版本中的排序功能。Lucene是一个高性能、全文检索库,它提供了强大的文本搜索能力。在这个主题中,我们将深入理解如何在Lucene 5中对...

    Lucene5学习之拼音搜索

    本文将围绕“Lucene5学习之拼音搜索”这一主题,详细介绍其拼音搜索的实现原理和实际应用。 首先,我们需要理解拼音搜索的重要性。在中文环境中,由于汉字的复杂性,用户往往习惯于通过输入词语的拼音来寻找信息。...

    Lucene5学习之自定义Collector

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

    Lucene5学习之创建索引入门示例

    同时,Lucene还提供了工具类,如IndexReader和IndexSearcher,用于读取和搜索已建立的索引,这些在后续的Lucene学习中都是非常重要的部分。 通过不断实践和深入研究,你可以掌握Lucene的强大功能,从而构建高效、...

    Lucene5学习之Highlighte关键字高亮

    《Lucene5学习之Highlighter关键字高亮》 在信息技术领域,搜索引擎的使用已经变得无处不在,而其中的关键技术之一就是如何有效地突出显示搜索结果中的关键字,这就是我们今天要探讨的主题——Lucene5中的...

    Lucene5学习之FunctionQuery功能查询

    **标题解析:** "Lucene5学习之FunctionQuery功能查询" Lucene5是Apache Lucene的一个版本,这是一个高性能、全文本搜索库,广泛应用于搜索引擎和其他需要高效文本检索的系统。FunctionQuery是Lucene中的一种查询...

    Lucene5学习之分页查询

    本文将深入探讨"Lucene5学习之分页查询"这一主题,结合给定的标签"源码"和"工具",我们将讨论如何在Lucene5中实现高效的分页查询,并探讨其背后的源码实现。 首先,理解分页查询的重要性是必要的。在大型数据集的...

    Lucene5学习之Spatial地理位置搜索

    2. **编码坐标点**:Lucene5 Spatial提供了Point类来表示地理坐标点。你需要将经度和纬度值转换为二进制编码,以便存储在索引中。 3. **创建空间字段**:在Lucene的Document对象中,添加一个专门的空间字段,用于...

    Lucene5学习之Suggest关键字提示

    《深入探索Lucene5:Suggest关键字提示技术》 在信息检索领域,用户输入查询时,提供快速、准确的关键字提示能显著提升用户体验...通过持续学习和实践,我们可以更好地驾驭这一强大的工具,为我们的项目增添更多价值。

    Lucene5学习之自定义排序

    本文将深入探讨“Lucene5学习之自定义排序”这一主题,帮助你理解如何在Lucene5中实现自定义的排序规则。 首先,Lucene的核心功能之一就是提供高效的全文检索能力,但默认的搜索结果排序通常是基于相关度得分...

    Lucene5学习之自定义同义词分词器简单示例

    本篇将聚焦于"Lucene5学习之自定义同义词分词器简单示例",通过这个主题,我们将深入探讨如何在Lucene5中自定义分词器,特别是实现同义词扩展,以提升搜索质量和用户体验。 首先,理解分词器(Analyzer)在Lucene中...

    Lucene5学习之增量索引(Zoie)

    总结起来,Lucene5学习之增量索引(Zoie)涉及到的关键技术点包括: 1. 基于Lucene的增量索引解决方案:Zoie系统。 2. 主从复制架构:Index Provider和Index User的角色。 3. 数据变更追踪:通过变更日志实现增量索引...

    Lucene5学习之多线程创建索引

    《Lucene5学习之多线程创建索引》 在深入了解Lucene5的多线程索引创建之前,我们先来了解一下Lucene的基本概念。Lucene是一个高性能、全文本搜索库,由Apache软件基金会开发。它提供了强大的文本分析、索引和搜索...

Global site tag (gtag.js) - Google Analytics