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