Lucene学习笔记-内存与文件索引的简单操作

Lucene是一个高性能的基于Java的全文检索工具包,使用的是倒排文件索引结构。Lucene的工作原理或索引结构这里就不在阐述了,网上有很多详细的说明。这里主要是记录一些Lucene内存索引、文件索引的一些简单操作。代码使用的版本是Lucene 4.5.1。


/** 索引接口-获取IndexWriter,IndexSearcher */
public interface IIndex {
	
	/** Lucene版本*/
	public static final Version VERSION = Version.LUCENE_45;
	
	/** 分词器类型*/
	/** 标准分词器*/
	public static final String ANALYZER_STANDARD = "standard";
	/** IK分词器*/
	public static final String ANALYZER_IK = "ik";
	/** SMARTCN 分词器*/
	public static final String ANALYZER_SMART_CN = "smart_cn";
	/** MMSEG4J 分词器*/
	public static final String ANALYZER_MMSEG4J = "mmseg4j";
	/** MMSEG4J 简单分词器*/
	public static final String ANALYZER_MMSEG4J_SIMPLE = "mmseg4j_simple";
	/** MMSEG4J 复杂分词器*/
	public static final String ANALYZER_MMSEG4J_COMPLEX = "mmseg4j_complex";
	/** MMSEG4J 最多词分词器*/
	public static final String ANALYZER_MMSEG4J_MAXWORD = "mmseg4j_maxword";
	
	
	/**
	 * 获取IndexWriter对象
	 * @return
	 */
	public IndexWriter obtainIndexWriter();
	
	/**
	 * 获取IndexSearcher对象
	 * @return
	 */
	public IndexSearcher obtainIndexSearcher();
	
	/**
	 * 关闭IndexWriter
	 */
	public void closeIndexWriter();
	
	/**
	 * 释放IndexSearcher
	 * @param indexSearcher
	 */
	public void releaseIndexSearcher(IndexSearcher indexSearcher);

}

/** 内存索引*/
public class RAMIndex implements IIndex {
	
	private Logger LOG = Logger.getLogger(RAMIndex.class);
	
	private IndexWriter indexWriter = null;
	
	private ReferenceManager<IndexSearcher> referenceManager = null;
	
	private Object writeLock = new Object();

	@Override
	public IndexWriter obtainIndexWriter() {
		try {
			synchronized(writeLock) {
				if (null == indexWriter) {
					Directory directory = new RAMDirectory();
					if (IndexWriter.isLocked(directory)) {
						IndexWriter.unlock(directory);
					}
					IndexWriterConfig indexWriterConfig = new IndexWriterConfig(VERSION, 
							IndexUtil.obtainDefaultAnalyzer());
					indexWriter = new IndexWriter(directory, indexWriterConfig);
				}
			}
		} catch (IOException e) {
			LOG.debug(e.getMessage(), e);
		}
		return indexWriter;
	}
	
	@Override
	public IndexSearcher obtainIndexSearcher() {
		try {
			if (null != referenceManager) {
				referenceManager.maybeRefresh();
				return referenceManager.acquire();
			}
			if (null == indexWriter) indexWriter = obtainIndexWriter();
			SearcherFactory searcherFactory = new SearcherFactory();
			referenceManager = new SearcherManager(indexWriter, true, searcherFactory);
			return referenceManager.acquire();
		} catch (Exception e) {
			LOG.debug(e.getMessage(), e);
		}
		return null;
	}
	
	@Override
	public void closeIndexWriter() {
		try {
			indexWriter.close();
		} catch (IOException e) {
			LOG.debug(e.getMessage(), e);
		}
	}
	
	@Override
	public void releaseIndexSearcher(IndexSearcher indexSearcher) {
		try {
			referenceManager.release(indexSearcher);
		} catch (IOException e) {
			LOG.debug(e.getMessage(), e);
		}
	}
}

/** 文件索引*/
public class FSIndex implements IIndex {
	
	private Logger logger = Logger.getLogger(FSIndex.class);

	private IndexWriter indexWriter = null;
	
	private ReferenceManager<IndexSearcher> referenceManager = null;
	
	private Object writeLock = new Object();
	
	private boolean isNearRealTime = false;
	
	private String indexPath = null;
	
	public FSIndex() {
		this.indexPath = PropertyUtil.get("INDEX_PATH");
	}
	
	public FSIndex(String indexPath) {
		this.indexPath = indexPath;
	}
	
	public FSIndex(boolean isNearRealTime) {
		this.indexPath = PropertyUtil.get("INDEX_PATH");
		this.isNearRealTime = isNearRealTime;
	}
	
	public FSIndex(String indexPath, boolean isNearRealTime) {
		this.indexPath = indexPath;
		this.isNearRealTime = isNearRealTime;
	}

	@Override
	public IndexWriter obtainIndexWriter() {
		try {
			synchronized(writeLock) {
				if (null == indexWriter) {
					File indexFileDir = new File(indexPath);
					if (!indexFileDir.exists()) indexFileDir.mkdirs();
					Directory directory = new NIOFSDirectory(indexFileDir);
//					Directory directory = FSDirectory.open(indexFileDir);
					if (IndexWriter.isLocked(directory)) {
						IndexWriter.unlock(directory);
					}
					IndexWriterConfig indexWriterConfig = new IndexWriterConfig(VERSION, 
							IndexUtil.obtainDefaultAnalyzer());
					indexWriter = new IndexWriter(directory, indexWriterConfig);
				}
			}
		} catch (IOException e) {
			logger.debug(e.getMessage(), e);
		}
		return indexWriter;
	}

	@SuppressWarnings("resource")
	@Override
	public IndexSearcher obtainIndexSearcher() {
		try {
			if (null != referenceManager) {
				if (!isNearRealTime) referenceManager.maybeRefresh();
				return referenceManager.acquire();
			}
			if (null == indexWriter) indexWriter = obtainIndexWriter();
			SearcherFactory searcherFactory = new SearcherFactory();
			referenceManager = new SearcherManager(indexWriter, false, searcherFactory);
			if (isNearRealTime) {
				TrackingIndexWriter trackingIndexWriter = new TrackingIndexWriter(indexWriter);
				ControlledRealTimeReopenThread<IndexSearcher> controlledRealTimeReopenThread = 
						new ControlledRealTimeReopenThread<IndexSearcher>(trackingIndexWriter, referenceManager, 5.0, 0.025);
				controlledRealTimeReopenThread.setName("FSControlledRealTimeReopenThread");
				controlledRealTimeReopenThread.setDaemon(true);
				controlledRealTimeReopenThread.start();
			}
			return referenceManager.acquire();
		} catch (Exception e) {
			logger.debug(e.getMessage(), e);
		}
		return null;
	}
	
	@Override
	public void closeIndexWriter() {
		try {
			indexWriter.close();
		} catch (IOException e) {
			logger.debug(e.getMessage(), e);
		}
	}
	
	@Override
	public void releaseIndexSearcher(IndexSearcher indexSearcher) {
		try {
			referenceManager.release(indexSearcher);
		} catch (IOException e) {
			logger.debug(e.getMessage(), e);
		}
	}

}

/** 索引管理器*/
public class IndexUtil {
	
	private static Map<String, IIndex> indexes = null;
	
	private static Map<String, Analyzer> analyzeries = null;
	
	static {
		indexes = new HashMap<String, IIndex>();
		indexes.put(IIndex.RAM, new RAMIndex());
		indexes.put(IIndex.FILE_NRT, new FSIndex(true));

		
		analyzeries = new HashMap<String, Analyzer>();
		analyzeries.put(IIndex.ANALYZER_IK, new IKAnalyzer());
		analyzeries.put(IIndex.ANALYZER_STANDARD, new StandardAnalyzer());
		analyzeries.put(IIndex.ANALYZER_SMART_CN, new SmartChineseAnalyzer());
		analyzeries.put(IIndex.ANALYZER_MMSEG4J, new MMSegAnalyzer());
		analyzeries.put(IIndex.ANALYZER_MMSEG4J_SIMPLE, new SimpleAnalyzer());
		analyzeries.put(IIndex.ANALYZER_MMSEG4J_COMPLEX, new ComplexAnalyzer());
		analyzeries.put(IIndex.ANALYZER_MMSEG4J_MAXWORD, new MaxWordAnalyzer());
	}

	private IndexUtil(){
	}
	
	public static IIndex obtainIndex(String indexType) {
		if (null == indexes.get(indexType)) {
			System.out.println("未找到相关索引");
		}
		return indexes.get(indexType);
	}
	
	public static boolean existIndex(String indexType) {
		return null == indexes.get(indexType) ? false : true;
	}
	
	public static void addIndex(String indexType, IIndex index) {
		indexes.put(indexType, index);
	}
	
	public static void removeIndex(String indexType) {
		indexes.remove(indexType);
	}
	
	public static IndexWriter obtainIndexWriter(String indexType) {
		return existIndex(indexType) ? obtainIndex(indexType).obtainIndexWriter() : null;
	}
	
	public static IndexSearcher obtainIndexSearcher(String indexType) {
		return existIndex(indexType) ? obtainIndex(indexType).obtainIndexSearcher() : null;
	}
	
	public static void releaseIndexSearcher(String indexType, IndexSearcher indexSearcher) {
		if (existIndex(indexType)) {
			obtainIndex(indexType).releaseIndexSearcher(indexSearcher);
		} else {
			System.out.println("索引不存在");
		}
	}
	
	public static void closeIndexWriter(String indexType) {
		if (existIndex(indexType)) {
			obtainIndex(indexType).closeIndexWriter();
			removeIndex(indexType);
		} else {
			System.out.println("索引不存在");
		}
	}
	
	public static Analyzer obtainDefaultAnalyzer() {
		return analyzeries.get(IIndex.ANALYZER_MMSEG4J_MAXWORD);
	}
	
	public static Analyzer obtainAnalyzer(String analyzerType) {
		if (null == analyzeries.get(analyzerType)) {
			System.out.println("未找到相关分词器");
		}
		return analyzeries.get(analyzerType);
	}
	
}

/** 查询参数 */
public class QueryParams {

	/** 实体类*/
	private Class<?> entityClass = null;
	/** 关键词*/
	private String keyword = null;
	/** 分词器*/
	private Analyzer analyzer = null;
	/** 过滤器*/
	private Filter filter = null;
	/** 排序*/
	private Sort sort = null;
	/** 查询类型标识*/
	private String queryTag = null;
	/** 查询域*/
	private String[] queryFields = null;
	/** 高亮域*/
	private String[] highLighterFields = null;
	/** 偏移量*/
	private int offset = 0;
	/** 限制长度*/
	private int limit = Integer.MAX_VALUE;
	
	public Class<?> getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class<?> entityClass) {
		this.entityClass = entityClass;
	}

	public String getKeyword() {
		return keyword;
	}

	public void setKeyword(String keyword) {
		this.keyword = keyword;
	}

	public Analyzer getAnalyzer() {
		return analyzer;
	}

	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
	}

	public Filter getFilter() {
		return filter;
	}

	public void setFilter(Filter filter) {
		this.filter = filter;
	}
	
	public Sort getSort() {
		return sort;
	}

	public void setSort(Sort sort) {
		this.sort = sort;
	}

	public String getQueryTag() {
		return queryTag;
	}

	public void setQueryTag(String queryTag) {
		this.queryTag = queryTag;
	}

	public String[] getQueryFields() {
		return queryFields;
	}

	public void setQueryFields(String[] queryFields) {
		this.queryFields = queryFields;
	}

	public String[] getHighLighterFields() {
		return highLighterFields;
	}

	public void setHighLighterFields(String[] highLighterFields) {
		this.highLighterFields = highLighterFields;
	}

	public int getOffset() {
		return offset;
	}

	public void setOffset(int offset) {
		this.offset = offset;
	}

	public int getLimit() {
		return limit;
	}

	public void setLimit(int limit) {
		this.limit = limit;
	}

}

/** 索引服务接口*/
public interface IIndexService {
	
	/**
	 * 新增索引
	 * @param objects 索引对象
	 */
	public void insert(Object... objects);
	
	/**
	 * 更新索引对象
	 * @param term 已索引的条目 
	 * @param object 待更新的对象
	 */
	public void update(Term term, Object object);
	
	/**
	 * 删除索引条目
	 * @param term
	 */
	public void delete(Term term);
	
	/**
	 * 删除所有索引
	 */
	public void deleteAll();
	
	/**
	 * 提交索引
	 */
	public void commit();
	
	/**
	 * 合并索引
	 * @param directories 索引目录
	 */
	public void merge(Directory...directories);
	
	/**
	 * 根据条件查询索引
	 * @param params 条件
	 * @return
	 */
	public QueryResult<?> readDataListByCondition(QueryParams params);
	
}

/** 抽象索引服务类*/
public abstract class AbstractIndexServiceImpl implements IIndexService {

	protected Logger LOG = Logger.getLogger(getClass());
	
	protected IndexWriter obtainIndexWriter() {
		return null;
	}
	
	protected IndexSearcher obtainIndexSearcher() {
		return null;
	}
	
	protected void releaseIndexSearcher(IndexSearcher indexSearcher) {
	}
	
	@Override
	public void insert(Object... objects) {
		List<Document> documents = new ArrayList<Document>();
		for (Object object : objects) {
			documents.add(object2Document(object));
		}
		try {
			obtainIndexWriter().addDocuments(documents);
		} catch (IOException e) {
			LOG.info(e.getMessage(), e);
		}
	}

	@Override
	public void update(Term term, Object object) {
		try {
			obtainIndexWriter().updateDocument(term, object2Document(object));
		} catch (Exception e) {
			LOG.info(e.getMessage(), e);
		}
	}

	@Override
	public void delete(Term term) {
		try {
			obtainIndexWriter().deleteDocuments(term);
		} catch (Exception e) {
			LOG.info(e.getMessage(), e);
		}
	}

	@Override
	public void deleteAll() {
		try {
			obtainIndexWriter().deleteAll();
		} catch (IOException e) {
			LOG.info(e.getMessage(), e);
		}
	}
	
	@Override
	public void commit() {
		try {
			obtainIndexWriter().commit();
		} catch (IOException e) {
			LOG.info(e.getMessage(), e);
		}
	}
	
	@Override
	public void merge(Directory...directories) {
		IndexWriter indexWriter = obtainIndexWriter();
		try {
			indexWriter.addIndexes(directories);
		} catch (IOException e) {
			LOG.info(e.getMessage(), e);
		}	
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public QueryResult<?> readDataListByCondition(QueryParams params) {
		Query query = obtainQuery(params);
		Filter filter = params.getFilter();
		Sort sort = obtainSort(params);
		int offset = params.getOffset();
		int limit = params.getLimit(); 
		int currentPageNum = offset == 0 ? 1 : (offset - 1) / limit + 1;
		int topN = currentPageNum * limit < limit ? limit : currentPageNum * limit;
		List<Object> objectList = new ArrayList<Object>();
		IndexSearcher indexSearcher = obtainIndexSearcher();
		try {
			TopDocs topDocs = readDataList(indexSearcher, query, filter, topN, sort);
			topN = null == topDocs ? 0 : topDocs.totalHits;
			if (currentPageNum > 1) {
				int prePageIndexNum = (currentPageNum - 1) * limit - 1;
				ScoreDoc[] scoreDocs = topDocs.scoreDocs;
				ScoreDoc prePageLastScoreDoc = scoreDocs[prePageIndexNum];
				topDocs = indexSearcher.searchAfter(prePageLastScoreDoc, query, filter,
						limit < topDocs.totalHits ? limit : topDocs.totalHits);
			}
			if (null != topDocs && null != topDocs.scoreDocs) {
				Analyzer analyzer = params.getAnalyzer();
				if (null == analyzer) analyzer = IndexUtil.obtainDefaultAnalyzer();
				String[] highLighterFields = params.getHighLighterFields();
				for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
					LOG.info(scoreDoc.doc + " score: " + scoreDoc.score);
					Document document = indexSearcher.doc(scoreDoc.doc);
					Object object = document2Object(document, params.getEntityClass());
					highLighter(analyzer, query, document, object, highLighterFields);
					objectList.add(object);
				}
			}
		} catch (Exception e) {
			LOG.info(e.getMessage(), e);
		} finally {
			releaseIndexSearcher(indexSearcher);
		}
		return new QueryResult(topN, objectList);
	}
	
	protected Document object2Document(Object object) {
		Document document = new Document();
		try {
			Field[] fields = ReflectUtil.getFields(object);
			for (int i = 0, length = fields.length; i < length; i++) {
				Field field = fields[i];
				field.setAccessible(true);
				String fieldName = field.getName();
				Class<?> fieldType = field.getType();
				Object fieldValue = field.get(object);
				if ("serialVersionUID".equals(field.getName()) || null == fieldValue
						|| Collection.class.isAssignableFrom(fieldType)) {
					continue;
				} 
				if (String.class.isAssignableFrom(fieldType)) {
					document.add(new StringField(fieldName, String.valueOf(fieldValue), Store.YES));
				} else if (Integer.class.isAssignableFrom(fieldType)) {
					document.add(new IntField(fieldName, Integer.parseInt(String.valueOf(fieldValue)), Store.YES));
				} else if (Long.class.isAssignableFrom(fieldType)) {
					document.add(new LongField(fieldName, Long.parseLong(String.valueOf(fieldValue)), Store.YES));
				} else if (Double.class.isAssignableFrom(fieldType)) {
					document.add(new DoubleField(fieldName, Double.parseDouble(String.valueOf(fieldValue)), Store.YES));
				} else if (Float.class.isAssignableFrom(fieldType)) {
					document.add(new FloatField(fieldName, Float.parseFloat(String.valueOf(fieldValue)), Store.YES));
				} else if (Date.class.isAssignableFrom(fieldType)) {
					document.add(new LongField(fieldName, ((Date) fieldValue).getTime(), Store.YES));
				} else if (Byte.class.isAssignableFrom(fieldType)) {
					document.add(new StringField(fieldName, String.valueOf(fieldValue), Store.YES));
				}
				field.setAccessible(false);
			}
		} catch (Exception e) {
			LOG.info(e.getMessage(), e);
		}
		return document;
	}

	protected Object document2Object(Document document, Class<?> clazz) {
		Object object = null;
		try {
			object = clazz.newInstance();
			Field[] fields = ReflectUtil.getFields(object);
			for (int i = 0, length = fields.length; i < length; i++) {
				Field field = fields[i];
				field.setAccessible(true);
				Class<?> fieldType = field.getType();
				IndexableField indexableField = document.getField(field.getName());
				if (Collection.class.isAssignableFrom(fieldType) || null == indexableField) {
					continue;
				}
				if (String.class.isAssignableFrom(fieldType)) {
					field.set(object, indexableField.stringValue());
				} else if (Integer.class.isAssignableFrom(fieldType)) {
					field.set(object, indexableField.numericValue().intValue());
				} else if (Long.class.isAssignableFrom(fieldType)) {
					field.set(object, indexableField.numericValue().longValue());
				} else if (Double.class.isAssignableFrom(fieldType)) {
					field.set(object, indexableField.numericValue().doubleValue());
				} else if (Float.class.isAssignableFrom(fieldType)) {
					field.set(object, indexableField.numericValue().floatValue());
				} else if (Date.class.isAssignableFrom(fieldType)) {
					field.set(object, new Date(indexableField.numericValue().longValue()));
				} else if (Byte.class.isAssignableFrom(fieldType)) {
					field.set(object, indexableField.stringValue());
				} 
				field.setAccessible(false);
			}
		} catch (Exception e) {
			LOG.info(e.getMessage(), e);
		}
		return object;
	}
	
	protected Query obtainQuery(QueryParams params) {
		String[] queryFields = params.getQueryFields();
		if (null == queryFields) {
			Field[] fields = ReflectUtil.getFields(params.getEntityClass());
			queryFields = new String[fields.length];
			for (int i = 0, length = fields.length; i < length; i++) {
				Field field = fields[i];
				field.setAccessible(true);
				Class<?> type = field.getType();
				if (Collection.class.isAssignableFrom(type)) continue;
				queryFields[i] = field.getName();
				field.setAccessible(false);
			}
		}
		BooleanQuery orQuery = new BooleanQuery();
		List<String> words = WordUtil.split(params.getKeyword());
		words.add(params.getKeyword());
		for (int i = 0, wLen = words.size(); i < wLen; i++) {
			String word = words.get(i);
			for (int j = 0, fLen = queryFields.length; j < fLen; j++) {
				String wildcardWord = "*" + word + "*";
				orQuery.add(new WildcardQuery(new Term(queryFields[j], wildcardWord)), 
						BooleanClause.Occur.SHOULD);
			}
		}
		return orQuery;
	}
	
	protected Query obtainQuery(Class<?> clazz, String keyword) {
		List<String> fieldNames = new ArrayList<String>();
		Field[] fields = ReflectUtil.getFields(clazz);
		for (int i = 0, length = fields.length; i < length; i++) {
			Field field = fields[i];
			field.setAccessible(true);
			Class<?> type = field.getType();
			if (Collection.class.isAssignableFrom(type)) {
				continue;
			} 
			fieldNames.add(field.getName());
			field.setAccessible(false);
		}
		MultiFieldQueryParser queryParser = new MultiFieldQueryParser(IIndex.VERSION, 
				fieldNames.toArray(new String[0]), IndexUtil.obtainDefaultAnalyzer());
		Query query = null;
		try {
			query = queryParser.parse(keyword);
		} catch (ParseException e) {
			LOG.info(e.getMessage(), e);
		}
		return query;
	}
	
	public Sort obtainSort(QueryParams params) {
		if (null != params.getSort()) return params.getSort();
		SortField[] sortFields = new SortField[]{new SortField(null, SortField.Type.SCORE, true),
				new SortField("createTime", SortField.Type.LONG, true)};
		return new Sort(sortFields);
	}
	
	protected TopDocs readDataList(IndexSearcher indexSearcher, Query query, Filter filter, 
			int topN, Sort sort) throws IOException {
		TopDocs topDocs = null;
		if (null == filter && null == sort) {
			topDocs = indexSearcher.search(query, topN);
		} else if (null != filter && null == sort) {
			topDocs = indexSearcher.search(query, filter, topN);
		} else if (null == filter && null != sort) {
			topDocs = indexSearcher.search(query, topN, sort);
		} else if (null != filter && null != sort) {
			topDocs = indexSearcher.search(query, filter, topN, sort);
		}
		return topDocs;
	}
	
	protected void highLighter(Analyzer analyzer, Query query, Document document, Object object, String... highLighterFields) {
		if (null == highLighterFields || highLighterFields.length == 0 || null == document || null == object) {
			return;
		}
		QueryScorer scorer = new QueryScorer(query);
		Formatter fmt = new SimpleHTMLFormatter("<font color='red'>", "</font>");
		Highlighter highLighter = new Highlighter(fmt, scorer);
		Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);
		highLighter.setTextFragmenter(fragmenter);
		try {
			for (String highLighterField : highLighterFields) {
				Field field = ReflectUtil.getFieldByFieldName(object, highLighterField);
				if (null == field) continue;
				IndexableField indexableField = document.getField(highLighterField);
				Class<?> fieldType = field.getType();
				if (!String.class.isAssignableFrom(fieldType) || null == indexableField) continue;
				String highLighterFieldValue = indexableField.stringValue();
				TokenStream tokenStream = TokenSources.getTokenStream(document, highLighterField, analyzer);
				String highLighterText = highLighter.getBestFragments(
						tokenStream, highLighterFieldValue, 5, "......\n");
				if (null == highLighterText || "".equals(highLighterText)) continue;
				ReflectUtil.setValueByFieldName(object, highLighterField, 
						null == highLighterText ? indexableField.stringValue() : highLighterText);
			}
		} catch (Exception e) {
			LOG.info(e.getMessage(), e);
		} 
	}
	
	protected void highLighterFast(IndexSearcher indexSearcher, Query query, int docId, Object object, String... highLighterFields) {
		if (null == highLighterFields || highLighterFields.length == 0 || null == object) {
			return;
		}
		FragListBuilder fragListBuilder = new SimpleFragListBuilder();  
		//注意下面的构造函数里,使用的是颜色数组,用来支持多种颜色高亮
		FragmentsBuilder fragmentsBuilder= new ScoreOrderFragmentsBuilder(
				BaseFragmentsBuilder.COLORED_PRE_TAGS, BaseFragmentsBuilder.COLORED_POST_TAGS);  
		FastVectorHighlighter fastHighlighter = new FastVectorHighlighter(true, true, fragListBuilder, fragmentsBuilder);  
		FieldQuery fieldQuery = fastHighlighter.getFieldQuery(query);
		try {
			for (String highLighterField : highLighterFields) {
				String highLighterText = fastHighlighter.getBestFragment(
						fieldQuery, indexSearcher.getIndexReader(), docId, highLighterField, 300);
				if (null == highLighterText || "".equals(highLighterText)) continue;
				ReflectUtil.setValueByFieldName(object, highLighterField, highLighterText);
			}
		} catch (Exception e) {
			LOG.info(e.getMessage(), e);
		} 
	}
	
	protected String obtainHighLighterText(Analyzer analyzer, Query query, String highLighterField, String highLighterFieldValue) {
		QueryScorer scorer = new QueryScorer(query);
		Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);
		Formatter fmt = new SimpleHTMLFormatter("<font color='red'>", "</font>");
		Highlighter highLighter = new Highlighter(fmt, scorer);
		highLighter.setTextFragmenter(fragmenter);
		String highLighterTxt = null;
		try {
			highLighterTxt = highLighter.getBestFragments(
						analyzer.tokenStream(highLighterField, new StringReader(highLighterFieldValue)), 
						highLighterFieldValue, 3, "......\n");
		} catch (Exception e) {
			LOG.info(e.getMessage(), e);
		} 
		return null == highLighterTxt ? highLighterFieldValue : highLighterTxt;
	}
}

/** 基于内存的索引操作服务*/
public class RAMIndexServiceImpl extends AbstractIndexServiceImpl {
	
	private String indexType = null;
	
	public RAMIndexServiceImpl(String indexType) {
		this.indexType = indexType;
	}

	@Override
	protected IndexWriter obtainIndexWriter() {
		return IndexUtil.obtainIndexWriter(indexType);
	}

	@Override
	protected IndexSearcher obtainIndexSearcher() {
		return IndexUtil.obtainIndexSearcher(indexType);
	}

	@Override
	protected void releaseIndexSearcher(IndexSearcher indexSearcher) {
		IndexUtil.releaseIndexSearcher(indexType, indexSearcher);
	}

}

/** 基于文件索引的操作服务*/
public class FSIndexServiceImpl extends AbstractIndexServiceImpl {
	
	private String indexType = null;
	
	public FSIndexServiceImpl(String indexType) {
		this.indexType = indexType;
	}

	@Override
	protected IndexWriter obtainIndexWriter() {
		return IndexUtil.obtainIndexWriter(indexType);
	}

	@Override
	protected IndexSearcher obtainIndexSearcher() {
		return IndexUtil.obtainIndexSearcher(indexType);
	}

	@Override
	protected void releaseIndexSearcher(IndexSearcher indexSearcher) {
		IndexUtil.releaseIndexSearcher(indexType, indexSearcher);
	}

}

/** 基于内存、文件混合索引的操作服务 */
public class MixIndexServiceImpl extends AbstractIndexServiceImpl {
	
	/** 内存索引类型*/
	private String ramIndexType = null;
	/** 文件索引类型*/
	private String fsIndexType = null;
	
	public MixIndexServiceImpl(String ramIndexType, String fsIndexType) {
		this.ramIndexType = ramIndexType;
		this.fsIndexType = fsIndexType;
	}

	@Override
	public void insert(Object... objects) {
		List<Document> documents = new ArrayList<Document>();
		for (Object object : objects) {
			documents.add(object2Document(object));
		}
		try {
			IndexUtil.obtainIndexWriter(ramIndexType).addDocuments(documents);
		} catch (IOException e) {
			LOG.debug(e.getMessage(), e);
		}
	}

	@Override
	public void update(Term term, Object object) {
		try {
			IndexUtil.obtainIndexWriter(ramIndexType).updateDocument(term, object2Document(object));
		} catch (Exception e) {
			LOG.debug(e.getMessage(), e);
		}
	}

	@Override
	public void delete(Term term) {
		try {
			IndexUtil.obtainIndexWriter(ramIndexType).deleteDocuments(term);
		} catch (Exception e) {
			LOG.debug(e.getMessage(), e);
		}
	}

	@Override
	public void deleteAll() {
		try {
			IndexUtil.obtainIndexWriter(ramIndexType).deleteAll();
			IndexUtil.obtainIndexWriter(fsIndexType).deleteAll();
		} catch (IOException e) {
			LOG.debug(e.getMessage(), e);
		}
	}
	
	@Override
	public void commit() {
		try {
			IndexUtil.obtainIndexWriter(ramIndexType).commit();
		} catch (IOException e) {
			LOG.debug(e.getMessage(), e);
		}
	}
	
	@Override
	public void merge(Directory...directories) {
		try {
			System.out.println("merge index start");
			//合并内存索引到文件索引中,合并完成后提交文件索引,新增一个内存索引
			IndexUtil.obtainIndexWriter(ramIndexType).commit();
			IndexUtil.obtainIndexWriter(fsIndexType).addIndexes(
					IndexUtil.obtainIndexWriter(ramIndexType).getDirectory());
			IndexUtil.obtainIndexWriter(fsIndexType).commit();
			IndexUtil.closeIndexWriter(ramIndexType);
			IndexUtil.addIndex(ramIndexType, new RAMIndex());
			System.out.println("merge index end");
		} catch (IOException e) {
			LOG.debug(e.getMessage(), e);
		}	
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public QueryResult<?> readDataListByCondition(QueryParams params) {
		Query query = obtainQuery(params);
		Filter filter = params.getFilter();
		Sort sort = obtainSort(params);
		int offset = params.getOffset();
		int limit = params.getLimit(); 
		int currentPageNum = offset == 0 ? 1 : (offset - 1) / limit + 1;
		int topN = currentPageNum * limit < limit ? limit : currentPageNum * limit;
		List<Object> objectList = new ArrayList<Object>();
		//查询步骤1、从内存索引中查询结果 2、从文件索引中查询结果
		String indexType = ramIndexType;
		IndexSearcher indexSearcher = null;
		TopDocs topDocs = null;
		try {
			indexSearcher = IndexUtil.obtainIndexSearcher(indexType);
			if (null != indexSearcher) {
				topDocs = readDataList(indexSearcher, query, filter, topN, sort);
				topN = (null == topDocs || topDocs.totalHits == 0) ? topN : topDocs.totalHits;
			}
			if (null == topDocs || topDocs.totalHits == 0) {
				IndexUtil.releaseIndexSearcher(indexType, indexSearcher);
				indexType = fsIndexType;
				indexSearcher = IndexUtil.obtainIndexSearcher(indexType);
				if (null != indexSearcher) {
					topDocs = readDataList(indexSearcher, query, filter, topN, sort);
					topN = null == topDocs ? 0 : topDocs.totalHits;
				}
			}
			System.out.println("query result from " + indexType);
			if (currentPageNum > 1) {
				int prePageIndexNum = (currentPageNum - 1) * limit - 1;
				ScoreDoc[] scoreDocs = topDocs.scoreDocs;
				ScoreDoc prePageLastScoreDoc = scoreDocs[prePageIndexNum];
				topDocs = indexSearcher.searchAfter(prePageLastScoreDoc, query, filter,
						limit < topDocs.totalHits ? limit : topDocs.totalHits);
			}
			if (null != topDocs && null != topDocs.scoreDocs) {
				Analyzer analyzer = params.getAnalyzer();
				if (null == analyzer) analyzer = IndexUtil.obtainDefaultAnalyzer();
				String[] highLighterFields = params.getHighLighterFields();
				for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
					LOG.info(scoreDoc.doc + " score: " + scoreDoc.score);
					Document document = indexSearcher.doc(scoreDoc.doc);
					Object object = document2Object(document, params.getEntityClass());
					highLighter(analyzer, query, document, object, highLighterFields);
					objectList.add(object);
				}
			}
		} catch (Exception e) {
			LOG.debug(e.getMessage(), e);
		} finally {
			IndexUtil.releaseIndexSearcher(indexType, indexSearcher);
		}
		return new QueryResult(topN, objectList);
	}
	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值