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