1. 程式人生 > >Lucene 入門和簡單封裝

Lucene 入門和簡單封裝

package com.whf.demo;

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.analysis.Analyzer;
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.queryparser.classic.MultiFieldQueryParser; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.store.Directory; import
org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.util.Version; /** * document(包含多個Field) Field(一個屬性) Analyzer(分詞處理) IndexWriter(建立索引) * Directory(索引的儲存的位置,FSDirectory和RAMDirectory) Term(String field->String * 待檢索的關鍵詞) * * @author whf * */ public class LuceneManager
{
private volatile static LuceneManager singleton = null; private volatile static IndexWriter writer = null; private volatile static IndexReader reader = null; private volatile static IndexSearcher searcher = null; private final Lock writerLock = new ReentrantLock(); private final static Object obj = new Object(); private static Version version = Version.LUCENE_CURRENT; /** * 單例建構函式 * * @return */ private LuceneManager() { } /** * 獲取LuceneTools單例例項(obj同步) * * @return */ public static LuceneManager getInstance() { if (null == singleton) { synchronized (obj) { if (null == singleton) { singleton = new LuceneManager(); } } } return singleton; } /** * 獲取IndexWriter單例例項(writerLock同步) 寫單例 * * @param dir * @param config * @return */ public IndexWriter getIndexWriter(Directory dir, IndexWriterConfig config) { if (dir == null) throw new IllegalArgumentException("Directory can not be null."); if (config == null) throw new IllegalArgumentException( "IndexWriterConfig can not be null."); try { writerLock.lock(); if (writer == null) { 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 (dir == null) throw new IllegalArgumentException("Directory can not be null."); try { if (reader == null) { 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 (reader == null) throw new IllegalArgumentException( "The indexReader can not be null."); if (searcher == null) searcher = new IndexSearcher(reader); return searcher; } /** * 獲取IndexSearcher物件(不支援多執行緒查詢) * * @param reader * IndexReader物件例項 * @return */ public IndexSearcher getIndexSearcher(IndexReader reader) { return getIndexSearcher(reader, null); } /** * 建立QueryParser物件 QueryParser parser=new QueryParser("欄位名稱","分析器例項"); Query * q=parser.parse("關鍵詞"); * parser.setDefaultOperator(QueryParser.Opertator.AND); * 同時含有多個關鍵字,如果是QueryParser.Opertator.OR表示或者 IndexSearcher searcher=new * IndexSearcher(reader); Hits hit=searcher.search(q); * * @param field * @param analyzer * @return */ public static QueryParser createQueryParser(String field, Analyzer analyzer) { return new QueryParser(field, analyzer); } /** * 建立QueryParser物件 QueryParser parser=new QueryParser("欄位名稱","分析器例項"); Query * q=parser.parse("關鍵詞"); * parser.setDefaultOperator(QueryParser.Opertator.AND); * 同時含有多個關鍵字,如果是QueryParser.Opertator.OR表示或者 IndexSearcher searcher=new * IndexSearcher(reader); Hits hit=searcher.search(q); * * @param field * @param analyzer * @return */ public static QueryParser createMultiFieldQueryParser(String[] fields, Analyzer analyzer) { return new MultiFieldQueryParser(fields, analyzer); } /** * 關閉IndexWriter * * @param writer */ public static void closeIndexWriter(IndexWriter writer) { if (writer != null) { try { writer.close(); writer = null; } catch (IOException e) { e.printStackTrace(); } } } /** * 關閉IndexReader * * @param reader */ public static void closeIndexReader(IndexReader reader) { if (reader != null) { try { reader.close(); reader = null; } catch (IOException e) { e.printStackTrace(); } } } /** * 關閉IndexReader和IndexWriter * * @param reader * @param writer */ public static void closeAll(IndexReader reader, IndexWriter writer) { closeIndexReader(reader); closeIndexWriter(writer); } }
package com.whf.demo;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
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.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexOptions;
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.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
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;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

import com.whf.pojo.HighlighterParam;
import com.whf.pojo.Page;

public class LuceneUtil {

    private static final LuceneManager manager = LuceneManager.getInstance();
    private static Analyzer analyzer = new IKAnalyzer(true);
    private static Version version = Version.LUCENE_CURRENT;
    private static FSDirectory fsDirectory = null;
    private static RAMDirectory ramDirectory = null;

    /**
     * 開啟索引目錄
     * 
     * @param luceneDir
     * @return
     * @throws IOException
     */
    public static FSDirectory openFSDirectory(String luceneDir) {
        if (fsDirectory == null)
            try {
                File dir = new File(luceneDir);
                if (!dir.exists())
                    dir.mkdirs();
                fsDirectory = FSDirectory.open(Paths.get(luceneDir));
                // 注意:isLocked方法內部會試圖去獲取Lock,
                // 如果獲取到Lock,會關閉它,否則return false表示索引目錄沒有被鎖.
                // 這也就是為什麼unlock方法被從IndexWriter類中移除的原因
                IndexWriter.isLocked(fsDirectory);
            } catch (IOException e) {
                e.printStackTrace();
            }
        return fsDirectory;
    }

    /**
     * 開啟記憶體目錄
     * 
     * @param luceneDir
     * @return
     * @throws IOException
     */
    public static RAMDirectory openRAMDirectory() {
        if (ramDirectory == null)
            return new RAMDirectory();
        else
            return ramDirectory;
    }

    /**
     * 關閉索引目錄並銷燬
     * 
     * @param directory
     * @throws IOException
     */
    public static void closeDirectory(Directory directory) {
        if (directory != null) {
            try {
                directory.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            directory = null;
        }
    }

    /**
     * 關閉IndexReader
     * 
     * @param reader
     */
    public static void closeIndexReader(IndexReader reader) {
        if (reader != null) {
            try {
                reader.close();
                reader = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 關閉IndexWriter
     * 
     * @param writer
     */
    public static void closeIndexWriter(IndexWriter writer) {
        if (writer != null) {
            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 dir
     * @param config
     * @return
     */
    public static IndexWriter getIndexWrtier(Directory dir,
            IndexWriterConfig config) {
        return manager.getIndexWriter(dir, config);
    }

    /**
     * 獲取IndexWriter
     * 
     * @param dir
     * @param config
     * @return
     */
    public static IndexWriter getIndexWrtier(String directoryPath,
            IndexWriterConfig config) {
        FSDirectory directory = openFSDirectory(directoryPath);
        return manager.getIndexWriter(directory, config);
    }

    /**
     * 獲取IndexReader
     * 
     * @param dir
     * @param enableNRTReader
     *            是否開啟NRTReader
     * @return
     */
    public static IndexReader getIndexReader(Directory dir,
            boolean enableNRTReader) {
        return manager.getIndexReader(dir, enableNRTReader);
    }

    /**
     * 獲取IndexReader(預設不啟用NRTReader)
     * 
     * @param dir
     * @return
     */
    public static IndexReader getIndexReader(Directory dir) {
        return manager.getIndexReader(dir);
    }

    /**
     * 獲取IndexSearcher
     * 
     * @param reader
     *            IndexReader物件
     * @param executor
     *            如果你需要開啟多執行緒查詢,請提供ExecutorService物件引數
     * @return
     */
    public static IndexSearcher getIndexSearcher(IndexReader reader,
            ExecutorService executor) {
        return manager.getIndexSearcher(reader, executor);
    }

    /**
     * 獲取IndexSearcher(不支援多執行緒查詢)
     * 
     * @param reader
     *            IndexReader物件
     * @return
     */
    public static IndexSearcher getIndexSearcher(IndexReader reader) {
        return manager.getIndexSearcher(reader);
    }

    /**
     * 刪除索引[注意:請自己關閉IndexWriter物件]
     * 
     * @param writer
     * @param field
     * @param value
     */
    public static void deleteIndex(IndexWriter writer, String field,
            String keyword) {
        try {
            writer.deleteDocuments(new Term[] { new Term(field, keyword) });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 刪除索引[注意:請自己關閉IndexWriter物件]
     * 
     * @param writer
     * @param term
     */
    public static void deleteIndexs(IndexWriter writer, Term[] terms) {
        try {
            writer.deleteDocuments(terms);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 刪除索引[注意:請自己關閉IndexWriter物件]
     * 
     * @param writer
     * @param field
     * @param value
     */
    public static void deleteIndex(IndexWriter writer, Term term) {
        try {
            writer.deleteDocuments(new Term[] { term });
        } 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();
        }
    }

    /**
     * 刪除索引[注意:請自己關閉IndexWriter物件]
     * 
     * @param writer
     * @param query
     */
    public static void deleteIndex(IndexWriter writer, Query query) {
        try {
            writer.deleteDocuments(query);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 刪除所有索引文件
     * 
     * @param writer
     */
    public static void deleteAllIndex(IndexWriter writer) {
        try {
            writer.deleteAll();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Term term = new Term("id","1234567");
     * 先去索引檔案裡查詢id為1234567的Doc,如果有就更新它(如果有多條,最後更新後只有一條)。如果沒有就新增.
     * 資料庫更新的時候,我們可以只針對某個列來更新,而lucene只能針對一行資料更新。
     * 
     * @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 doc
     */
    public static void addIndex(IndexWriter writer, Document document) {
        updateIndex(writer, null, document);
        // writer.addDocument(document);
    }

    /**
     * 批量新增索引文件
     * 
     * @param writer
     * @param doc
     */
    public static void addIndex(IndexWriter writer, List<Document> documents) {
        try {
            writer.addDocuments(documents);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 將記憶體的資料寫至外存
     * 
     * @param writer
     * @param ramDirectory
     * @param fsramDirectory
     * @param analyzer
     */
    public static void OptimizeRAMToFSDirectory(IndexWriter writer,
            Directory fsDirectory, Analyzer analyzer) {
        try {
            writer.addIndexes(new Directory[] { fsDirectory });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 索引文件查詢
     * 
     * @param searcher
     * @param query
     * @param sort
     * @return
     */
    public static List<Document> query(IndexSearcher searcher, Query query,
            Integer rows, Sort sort, Filter filter) {
        TopDocs topDocs = null;
        List<Document> docList = null;
        try {
            if (sort != null) {
                if (filter != null) {
                    topDocs = searcher.search(query, filter,
                            (rows == null ? Integer.MAX_VALUE : rows), sort);
                } else {
                    topDocs = searcher.search(query,
                            (rows == null ? Integer.MAX_VALUE : rows), sort);
                }
            } else {
                if (filter != null) {
                    topDocs = searcher.search(query, filter,
                            (rows == null ? Integer.MAX_VALUE : rows));
                } else {
                    topDocs = searcher.search(query,
                            (rows == null ? Integer.MAX_VALUE : rows));
                }
            }
            ScoreDoc[] scores = topDocs.scoreDocs;
            int length = scores.length;
            if (length <= 0) {
                return Collections.emptyList();
            }
            docList = new ArrayList<Document>();
            for (int i = 0; i < length; i++) {
                System.out.println(scores[i].score + " " + scores[i].doc);
                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 = LuceneUtil.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, 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);
    }

    /**
     * 建立QueryParser
     * 
     * @return
     */
    public static QueryParser createCustomQueryParser(String field,
            Analyzer analyzer) {
        return manager.createQueryParser(field, analyzer);
    }

    /**
     * 建立多field的QueryParser
     * 
     * @param fields
     * @param analyzer
     * @return
     */
    public static QueryParser createMultiFieldQueryParser(String[] fields,
            Analyzer analyzer) {
        return manager.createMultiFieldQueryParser(fields, analyzer);
    }

    /**
     * 可以在查詢的時候獲取TermVector
     * 
     * @return
     */
    public static Field storeVectorTextField(String name, String value,
            Store store) {
        FieldType type = new FieldType();
        type.setStored(true);
        type.setStoreTermVectors(true);
        type.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
        return new Field(name, value, type);
    }

}
package com.whf.pojo;

import java.io.IOException;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.queries.CustomScoreProvider;
import org.apache.lucene.queries.CustomScoreQuery;
import org.apache.lucene.search.Query;

public class MyCountQuery extends CustomScoreQuery{

    private String field=null;

    private class MyCountQueryScoreProvider extends CustomScoreProvider{

        private String field=null;

        public MyCountQueryScoreProvider(LeafReaderContext context) {
            super(context);
        }

        public MyCountQueryScoreProvider(LeafReaderContext context, String field) {
            super(context);
            this.field = field;
        }

        @Override
        public float customScore(int arg0, float arg1, float[] arg2)
                throws IOException {
            IndexReader reader = context.reader();
            Terms tv = reader.getTermVector(arg0, field);
            TermsEnum termsEnum = null;
            int numTerms = 0;
            if (tv != null) {
                termsEnum = tv.iterator();
                while ((termsEnum.next()) != null) {
                    numTerms++;
                }
            }
            return (float) (numTerms);
        }

    }

    public MyCountQuery(Query subQuery) {
        super(subQuery);
    }

    public MyCountQuery(Query subQuery, String field) {
        super(subQuery);
        this.field = field;
    }

    @Override
    protected CustomScoreProvider getCustomScoreProvider(
            LeafReaderContext context) throws IOException {
        return new MyCountQueryScoreProvider(context, this.field);
    }

}
package com.whf.pojo;

/**
 * @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() {
    }
}
package com.whf.pojo;

import java.io.IOException;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.queries.CustomScoreProvider;
import org.apache.lucene.queries.CustomScoreQuery;
import org.apache.lucene.search.Query;

public class MyCountQuery extends CustomScoreQuery{

    private String field=null;

    private class MyCountQueryScoreProvider extends CustomScoreProvider{

        private String field=null;

        public MyCountQueryScoreProvider(LeafReaderContext context) {
            super(context);
        }

        public MyCountQueryScoreProvider(LeafReaderContext context, String field) {
            super(context);
            this.field