1. 程式人生 > >Lucene之模糊、精確、匹配、範圍、多條件查詢-yellowcong

Lucene之模糊、精確、匹配、範圍、多條件查詢-yellowcong

Lucene的查詢方式很 豐富,對於數值型別的資料,採取TermRangeQuery的方式,對於String型別的,就可以採取TermQuery等,查詢方式了,可以通過採取合適的查詢方式,檢索到資料。Queryparser這個查詢方式包含了其他幾種查詢方式。

查詢方式

查詢方式 意義
TermQuery 精確查詢
TermRangeQuery 查詢一個範圍
PrefixQuery 字首匹配查詢
WildcardQuery 萬用字元查詢
BooleanQuery 多條件查詢
PhraseQuery 短語查詢
FuzzyQuery 模糊查詢
Queryparser 萬能查詢(上面的都可以用這個來查詢到)

案例

package com.yellowcong.demo;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import
org.apache.lucene.document.Field; import org.apache.lucene.document.IntField; import org.apache.lucene.document.LongField; import org.apache.lucene.document.StringField; import org.apache.lucene.document.TextField; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import
org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.Term; import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.NumericRangeQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; /** * 建立使用者:狂飆的yellowcong<br/> * 建立時間:下午5:27:50<br/> * 建立日期:2017年12月2日<br/> * 機能概要: */ public class Demo4 { private static List<Passage> psgList = null; // 寫物件 private static IndexWriter writer = null; public static void main(String[] args) throws Exception { // 刪除 所有索引 deleteAll(); // 建立索引 index(); //精確String 型別查詢 getByTermQuery(); //範圍查詢 getByRange(); //字首匹配查詢 getByPrefix(); //萬用字元查詢 getByWildcard(); //短語查詢 getByPhrase(); //模糊查詢 getByFuzzy(); } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月3日<br/> * 建立時間:下午12:00:43<br/> * 機能概要:精確查詢 * @throws Exception */ public static void getByTermQuery() { System.out.println("-------------查詢使用者名稱為yellowcong的資料-------------"); //精確查詢,根據名稱來直接 Query query = new TermQuery(new Term("username", "yellowcong")); //執行查詢 excQuery(query); } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月3日<br/> * 建立時間:下午12:25:21<br/> * 機能概要:範圍查詢 */ public static void getByRange(){ //精確查詢 System.out.println("-------------查詢id在1-3的資料-------------"); //查詢前三條資料,後面兩個true,表示的是是否包含頭和尾 Query query = NumericRangeQuery.newIntRange("id", 1, 3, true, true); //執行查詢 excQuery(query); } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月3日<br/> * 建立時間:下午12:25:56<br/> * 機能概要:字首查詢資料 */ public static void getByPrefix(){ System.out.println("-------------查詢字首 郵箱 以z開頭的資料-------------"); //查詢字首 郵箱 以z開頭的資料 Query query = new PrefixQuery(new Term("email", "z")); //執行查詢 excQuery(query); } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月3日<br/> * 建立時間:下午12:29:55<br/> * 機能概要:萬用字元查詢資料 */ public static void getByWildcard(){ //萬用字元就更簡單了,只要知道“*”表示0到多個字元,而使用“?”表示一個字元就行了 System.out.println("-------------------查詢email 以 @qq結尾的資料--------------"); //查詢email 以 @qq結尾的資料 Query query = new WildcardQuery(new Term("email","*@qq.com")); //執行查詢 excQuery(query); } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月3日<br/> * 建立時間:下午12:43:43<br/> * 機能概要:短語查詢,查詢中間有幾個單詞的那種 */ public static void getByPhrase(){ System.out.println("------------查詢內容中,有I LOVE YOU 的資料---------------"); //短語查詢,但是對於中文沒有太多的用,其中查詢的時候還有 PhraseQuery query = new PhraseQuery(); //設定有幾跳,表示中間存在一個單詞 query.setSlop(1); //查詢 query.add(new Term("content","i")); //I XX you 就可以被查詢出來 query.add(new Term("content","you")); excQuery(query); } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月3日<br/> * 建立時間:下午12:49:14<br/> * 機能概要:預設提供的模糊查詢對中文來說,沒有任何用 * @throws Exception */ public static void getByFuzzy() throws Exception{ System.out.println("-------------------------模糊查詢---------------"); FuzzyQuery query = new FuzzyQuery(new Term("username","zhangsan")); excQuery(query); } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月3日<br/> * 建立時間:下午12:01:55<br/> * 機能概要:查詢Query 將需要查詢的條件傳遞進來 * @param query */ public static void excQuery(Query query){ //查詢 IndexReader reader = null; try { reader = getIndexReader(); //獲取查詢資料 IndexSearcher searcher = new IndexSearcher(reader); //檢索資料 TopDocs topDocs = searcher.search(query, 100); for(ScoreDoc scoreDoc : topDocs.scoreDocs){ //湖區偶 Document doc = reader.document(scoreDoc.doc); System.out.println(doc.get("id")+":"+doc.get("username")+":"+doc.get("email")); } } catch (Exception e) { e.printStackTrace(); }finally{ coloseReader(reader); } } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月3日<br/> * 建立時間:上午11:52:52<br/> * 機能概要:關閉IndexReader * @param reader */ private static void coloseReader(IndexReader reader) { try { if (reader != null) { reader.close(); } } catch (IOException e) { e.printStackTrace(); } } static { psgList = new ArrayList<Passage>(); // 產生一堆資料 psgList.add(new Passage(1, "yellowcong" , "[email protected]", "逗比", 23 , "I LOVE YOU ", new Date())); psgList.add(new Passage(2, "張三" , "[email protected]", "逗比", 23, "三炮", new Date())); psgList.add(new Passage(3, "李四" , "[email protected]", "逗比", 23, "三炮", new Date())); psgList.add(new Passage(4, "王五" , "[email protected]", "逗比", 23, "三炮", new Date())); psgList.add(new Passage(5, "趙六" , "[email protected]", "逗比", 23, "三炮", new Date())); System.out.println("-------------------------新增的資料----------------------"); for(Passage psg:psgList){ System.out.println(psg.getId()+":"+psg.getUsername()+":"+psg.getEmail()+":"+psg.getContent()); } } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月2日<br/> * 建立時間:下午5:43:57<br/> * 機能概要:獲取IndexWriter 同一時間 ,只能開啟一個 IndexWriter,獨佔寫鎖 。內建執行緒安全機制。 * * @return * @throws Exception */ @SuppressWarnings("static-access") public static IndexWriter getIndexWriter() throws Exception { // 建立IdnexWriter String path = getIndexPath(); FSDirectory fs = FSDirectory.open(new File(path)); // 判斷資源是否佔用 if (writer == null || !writer.isLocked(fs)) { synchronized (Demo3.class) { if (writer == null || !writer.isLocked(fs)) { // 建立writer物件 writer = new IndexWriter(fs, new IndexWriterConfig(Version.LUCENE_45, new StandardAnalyzer(Version.LUCENE_45))); } } } return writer; } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月2日<br/> * 建立時間:下午5:46:36<br/> * 機能概要:獲取到IndexReader 任意多個IndexReaders可同時開啟,可以跨JVM。 * * @return * @throws Exception */ public static IndexReader getIndexReader() throws Exception { // 建立IdnexWriter String path = getIndexPath(); FSDirectory fs = FSDirectory.open(new File(path)); // 獲取到讀 return IndexReader.open(fs); } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月2日<br/> * 建立時間:下午7:57:04<br/> * 機能概要:刪除所有的索引 */ public static void deleteAll() { IndexWriter writer = null; try { // 獲取IndexWriter writer = getIndexWriter(); // 刪除所有的資料 writer.deleteAll(); int cnt = writer.numDocs(); System.out.println("索引條數\t" + cnt); // 提交事物 writer.commit(); } catch (Exception e) { e.printStackTrace(); } finally { coloseWriter(writer); } } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月2日<br/> * 建立時間:下午5:37:22<br/> * 機能概要:獲取索引目錄 * * @return 目錄 */ private static String getIndexPath() { // 獲取索引的目錄 String path = Demo3.class.getClassLoader().getResource("index").getPath(); // 不存在就建立目錄 File file = new File(path); if (!file.exists()) { file.mkdirs(); } return path; } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月2日<br/> * 建立時間:下午8:24:16<br/> * 機能概要:關閉IndexWriter */ private static void coloseWriter(IndexWriter writer) { try { if (writer != null) { writer.close(); } } catch (IOException e) { e.printStackTrace(); } } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月2日<br/> * 建立時間:下午8:26:15<br/> * 機能概要:關閉IndexReader * * @param reader */ public static void closerReader(IndexReader reader) { try { if (reader != null) { reader.close(); } } catch (IOException e) { e.printStackTrace(); } } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月2日<br/> * 建立時間:下午8:10:01<br/> * 機能概要: 查詢資料 * * @param key * 查詢範圍 * @param val * 值 */ public static void search(String key, Object val) { IndexReader reader = null; try { reader = getIndexReader(); IndexSearcher searcher = new IndexSearcher(reader); // 精確查詢 Query query = null; // 定義查詢條件 if (val instanceof Integer) { // 後面的兩個true 表示的是 是否包含 上下的資料 query = NumericRangeQuery.newIntRange(key, Integer.parseInt(val.toString()), Integer.parseInt(val.toString()), true, true); } else { query = new TermQuery(new Term(key, val.toString())); } // QueryParser paraser = new QueryParser(Version.LUCENE_45, key, new // StandardAnalyzer(Version.LUCENE_45)); // Query query = paraser.parse(val); // 獲取查詢到的Docuemnt TopDocs topDocs = searcher.search(query, 500); // 總共命中的條數 System.out.println(topDocs.totalHits); for (ScoreDoc score : topDocs.scoreDocs) { // Document doc = searcher.doc(score.doc); // 查詢到的結果 String username = doc.get("username"); System.out.println(username); } } catch (Exception e) { e.printStackTrace(); } finally { closerReader(reader); } } /** * 建立使用者:狂飆的yellowcong<br/> * 建立日期:2017年12月2日<br/> * 建立時間:下午6:03:33<br/> * 機能概要:建立索引 */ public static void index() { IndexWriter writer = null; try { // 1、獲取IndexWriter writer = getIndexWriter(); // 2、建立索引 for (Passage psg : psgList) { Document doc = new Document(); // IntField 不能直接檢索到,需要結合 doc.add(new IntField("id", psg.getId(), Field.Store.YES)); // 使用者String型別的欄位的儲存,StringField是隻索引不分詞 doc.add(new TextField("username", psg.getUsername(), Field.Store.YES)); // 主要對int型別的欄位進行儲存,需要注意的是如果需要對InfField進行排序使用SortField.Type.INT來比較,如果進範圍查詢或過濾,需要採用NumericRangeQuery.newIntRange() doc.add(new IntField("age", psg.getAge(), Field.Store.YES)); // 對String型別的欄位進行儲存,TextField和StringField的不同是TextField既索引又分詞 doc.add(new TextField("content", psg.getContent(), Field.Store.NO)); doc.add(new StringField("keyword", psg.getKeyword(), Field.Store.YES)); doc.add(new StringField("email", psg.getEmail(), Field.Store.YES)); // 日期資料新增索引 doc.add(new LongField("addDate", psg.getAddDate().getTime(), Field.Store.YES)); // 3、新增文件 writer.addDocument(doc); } // 索引條數 int cnt = writer.numDocs(); System.out.println("索引條數\t" + cnt); // 提交事物 writer.commit(); } catch (Exception e) { e.printStackTrace(); } finally { coloseWriter(writer); } } static class Passage { private int id; private String username; private String email; private String keyword; private int age; // 這個模擬的是文章 private String content; private Date addDate; public Passage(int id, String username, String email, String keyword, int age, String content, Date addDate) { super(); this.id = id; this.username = username; this.email = email; this.keyword = keyword; this.age = age; this.content = content; this.addDate = addDate; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getKeyword() { return keyword; } public void setKeyword(String keyword) { this.keyword = keyword; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Date getAddDate() { return addDate; } public void setAddDate(Date addDate) { this.addDate = addDate; } } }

執行結果
這裡寫圖片描述

Queryparser

通過Queryparaser直接就可以將上面的方法都包攬了

常用匹配

@Test
    public void searchByQueryPhase() throws ParseException{
        IndexUtils utls = new IndexUtils();
        //設定預設搜尋域,將預設搜尋域 設定在Content
        QueryParser parse = new QueryParser(Version.LUCENE_35, "content",new StandardAnalyzer(Version.LUCENE_35));
//      parse.setDefaultOperator(Operator.AND);//將空格預設 定義為AND
        parse.setAllowLeadingWildcard(true);//設定第一個* 可以匹配
        Query query = parse.parse("yellow");
        //其中空格預設就是OR 
        query = parse.parse("yellow cong");

        //改變搜尋域,搜尋域 為 name
        query = parse.parse("name:yellow1");

        //使用萬用字元 , 設定查詢類容為 以 y 開頭的資料
        query = parse.parse("name:y*"); //其中* 不可以放在字串的首位

        //將字串放在首位,預設情況下回報錯
        query = parse.parse("email:*@yellow.com"); //其中我們可以更改 第一個通配值得功能

        //其中 + - 表示有 和沒有 其中需要有空格 ,而且第一個+ 或者 - 需要放在第一個位置
        query = parse.parse("- content: cong  + i "); //這個表示的是content 中不含有 cong ,但是含有i

        //匹配區間, 其中TO 必須是大寫的,還有有空格
        query = parse.parse("id:[1 TO 4]"); //設定查詢的Id為 1-4

         //開區間匹配
        query = parse.parse("id:(1 TO 4)");
        //匹配連起來的String
        query = parse.parse("\"I like yellow cong\""); //這個是查詢的一個一個詞  ,匹配String

        //匹配一個或者多個數據
        query = parse.parse("\"I cong\"~2"); //表示中間含有一個單詞

        //模糊查詢
        query = parse.parse("name:yellow~");

        //匹配數字,這個方法中沒有字元類容,所以需要自定義了

        IndexReaderHelper.searchByQueryPhase(query, 10);
    }

案例

package com.yellowcong.demo;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

/**
 * 建立使用者:狂飆的yellowcong<br/>
 * 建立時間:下午5:27:50<br/>
 * 建立日期:2017年12月2日<br/>
 * 機能概要:
 */
public class Demo5 {
    private static List<Passage> psgList = null;

    // 寫物件
    private static IndexWriter writer = null;

    public static void main(String[] args) throws Exception {

        // 刪除 所有索引
        deleteAll();

        // 建立索引
        index();

        QueryParser parser = getQueryParser();
        //將空格預設 定義為AND
//      parse.setDefaultOperator(Operator.AND);
        //設定第一個* 可以匹配
        parser.setAllowLeadingWildcard(true);

        //精確String 型別查詢
        System.out.println("-------------查詢使用者名稱為yellowcong的資料-------------");
        //精確查詢,根據名稱來直接
        Query query = parser.parse("username:yellowcong");
        //執行查詢
        excQuery(query);


        //範圍查詢
        System.out.println("-------------查詢id在1-3的資料-------------");
        //查詢前三條資料,後面兩個true,表示的是是否包含頭和尾
        //匹配區間, 其中TO 必須是大寫的,還有有空格
        query = parser.parse("id:[1 TO 3]"); //設定查詢的Id為 1-4

        //執行查詢
        excQuery(query);


        //字首匹配查詢
        System.out.println("-------------查詢字首 郵箱 以z開頭的資料-------------");
        //查詢字首 郵箱 以z開頭的資料
        query = parser.parse("email:z*");
        excQuery(query);

        //萬用字元查詢
        //萬用字元就更簡單了,只要知道“*”表示0到多個字元,而使用“?”表示一個字元就行了
        System.out.println("-------------------查詢email 以 @qq結尾的資料--------------");
        //查詢email 以 @qq結尾的資料
        //需要設定 * 可以放在前面  QueryParser.setAllowLeadingWildcard(true);
        //將字串放在首位,預設情況下回報錯
        query = parser.parse("email:*@qq.com");
        excQuery(query);        


        //短語查詢
        System.out.println("------------查詢內容中,有I LOVE YOU 的資料---------------");
        //短語查詢,但是對於中文沒有太多的用,其中查詢的時候還有
        query =parser.parse("\"i you\"~2"); //表示中間含有一個單詞
        excQuery(query);

        //模糊查詢
        System.out.println("-------------------------模糊查詢---------------");
        query = parser.parse("username:zhangsan~");
        excQuery(query);

    }

    private static QueryParser getQueryParser(){
        QueryParser parser =new QueryParser(Version.LUCENE_45,"content", new StandardAnalyzer(Version.LUCENE_45));
        return parser;
    }
    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月3日<br/>
     * 建立時間:下午12:01:55<br/>
     * 機能概要:查詢Query 將需要查詢的條件傳遞進來
     * @param query
     */
    public static void excQuery(Query query){
        //查詢
        IndexReader reader  = null;
        try {
            reader = getIndexReader();

            //獲取查詢資料
            IndexSearcher searcher = new IndexSearcher(reader);

            //檢索資料
            TopDocs topDocs = searcher.search(query, 100);
            for(ScoreDoc scoreDoc : topDocs.scoreDocs){
                //湖區偶
                Document doc = reader.document(scoreDoc.doc);
                System.out.println(doc.get("id")+":"+doc.get("username")+":"+doc.get("email"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            coloseReader(reader);
        }
    }
    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月3日<br/>
     * 建立時間:上午11:52:52<br/>
     * 機能概要:關閉IndexReader
     * @param reader
     */
    private static void coloseReader(IndexReader reader) {
        try {
            if (reader != null) {
                reader.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static {
        psgList = new ArrayList<Passage>();

        // 產生一堆資料
        psgList.add(new Passage(1, "yellowcong" ,
                "[email protected]", "逗比", 23 , "I LOVE YOU ", new Date()));

        psgList.add(new Passage(2, "張三" ,
                "[email protected]", "逗比", 23, "三炮", new Date()));
        psgList.add(new Passage(3, "李四" ,
                "[email protected]", "逗比", 23, "三炮", new Date()));
        psgList.add(new Passage(4, "王五" ,
                "[email protected]", "逗比", 23, "三炮", new Date()));
        psgList.add(new Passage(5, "趙六" ,
                "[email protected]", "逗比", 23, "三炮", new Date()));
        System.out.println("-------------------------新增的資料----------------------");
        for(Passage psg:psgList){
            System.out.println(psg.getId()+":"+psg.getUsername()+":"+psg.getEmail()+":"+psg.getContent());
        }
    }

    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月2日<br/>
     * 建立時間:下午5:43:57<br/>
     * 機能概要:獲取IndexWriter 同一時間 ,只能開啟一個 IndexWriter,獨佔寫鎖 。內建執行緒安全機制。
     * 
     * @return
     * @throws Exception
     */
    @SuppressWarnings("static-access")
    public static IndexWriter getIndexWriter() throws Exception {
        // 建立IdnexWriter
        String path = getIndexPath();
        FSDirectory fs = FSDirectory.open(new File(path));
        // 判斷資源是否佔用
        if (writer == null || !writer.isLocked(fs)) {
            synchronized (Demo3.class) {
                if (writer == null || !writer.isLocked(fs)) {
                    // 建立writer物件
                    writer = new IndexWriter(fs,
                            new IndexWriterConfig(Version.LUCENE_45, new StandardAnalyzer(Version.LUCENE_45)));
                }
            }
        }
        return writer;
    }

    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月2日<br/>
     * 建立時間:下午5:46:36<br/>
     * 機能概要:獲取到IndexReader 任意多個IndexReaders可同時開啟,可以跨JVM。
     * 
     * @return
     * @throws Exception
     */
    public static IndexReader getIndexReader() throws Exception {
        // 建立IdnexWriter
        String path = getIndexPath();
        FSDirectory fs = FSDirectory.open(new File(path));
        // 獲取到讀
        return IndexReader.open(fs);
    }


    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月2日<br/>
     * 建立時間:下午7:57:04<br/>
     * 機能概要:刪除所有的索引
     */
    public static void deleteAll() {
        IndexWriter writer = null;
        try {
            // 獲取IndexWriter
            writer = getIndexWriter();

            // 刪除所有的資料
            writer.deleteAll();

            int cnt = writer.numDocs();
            System.out.println("索引條數\t" + cnt);

            // 提交事物
            writer.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            coloseWriter(writer);
        }
    }

    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月2日<br/>
     * 建立時間:下午5:37:22<br/>
     * 機能概要:獲取索引目錄
     * 
     * @return 目錄
     */
    private static String getIndexPath() {
        // 獲取索引的目錄
        String path = Demo3.class.getClassLoader().getResource("index").getPath();

        // 不存在就建立目錄
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        return path;
    }

    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月2日<br/>
     * 建立時間:下午8:24:16<br/>
     * 機能概要:關閉IndexWriter
     */
    private static void coloseWriter(IndexWriter writer) {
        try {
            if (writer != null) {
                writer.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月2日<br/>
     * 建立時間:下午8:26:15<br/>
     * 機能概要:關閉IndexReader
     * 
     * @param reader
     */
    public static void closerReader(IndexReader reader) {
        try {
            if (reader != null) {
                reader.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月2日<br/>
     * 建立時間:下午8:10:01<br/>
     * 機能概要: 查詢資料
     * 
     * @param key
     *            查詢範圍
     * @param val
     *            值
     */
    public static void search(String key, Object val) {
        IndexReader reader = null;
        try {
            reader = getIndexReader();

            IndexSearcher searcher = new IndexSearcher(reader);

            // 精確查詢
            Query query = null;

            // 定義查詢條件
            if (val instanceof Integer) {
                // 後面的兩個true 表示的是 是否包含 上下的資料
                query = NumericRangeQuery.newIntRange(key, Integer.parseInt(val.toString()),
                        Integer.parseInt(val.toString()), true, true);
            } else {
                query = new TermQuery(new Term(key, val.toString()));
            }
            // QueryParser paraser = new QueryParser(Version.LUCENE_45, key, new
            // StandardAnalyzer(Version.LUCENE_45));
            // Query query = paraser.parse(val);

            // 獲取查詢到的Docuemnt
            TopDocs topDocs = searcher.search(query, 500);
            // 總共命中的條數
            System.out.println(topDocs.totalHits);
            for (ScoreDoc score : topDocs.scoreDocs) {
                //
                Document doc = searcher.doc(score.doc);

                // 查詢到的結果
                String username = doc.get("username");
                System.out.println(username);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closerReader(reader);
        }
    }

    /**
     * 建立使用者:狂飆的yellowcong<br/>
     * 建立日期:2017年12月2日<br/>
     * 建立時間:下午6:03:33<br/>
     * 機能概要:建立索引
     */
    public static void index() {
        IndexWriter writer = null;
        try {
            // 1、獲取IndexWriter
            writer = getIndexWriter();

            // 2、建立索引
            for (Passage psg : psgList) {
                Document doc = new Document();

                // IntField 不能直接檢索到,需要結合
                doc.add(new IntField("id", psg.getId(), Field.Store.YES));

                // 使用者String型別的欄位的儲存,StringField是隻索引不分詞
                doc.add(new TextField("username", psg.getUsername(), Field.Store.YES));

                // 主要對int型別的欄位進行儲存,需要注意的是如果需要對InfField進行排序使用SortField.Type.INT來比較,如果進範圍查詢或過濾,需要採用NumericRangeQuery.newIntRange()
                doc.add(new IntField("age", psg.getAge(), Field.Store.YES));

                // 對String型別的欄位進行儲存,TextField和StringField的不同是TextField既索引又分詞
                doc.add(new TextField("content", psg.getContent(), Field.Store.NO));

                doc.add(new StringField("keyword", psg.getKeyword(), Field.Store.YES));

                doc.add(new StringField("email", psg.getEmail(), Field.Store.YES));

                // 日期資料新增索引
                doc.add(new LongField("addDate", psg.getAddDate().getTime(), Field.Store.YES));

                // 3、新增文件
                writer.addDocument(doc);
            }

            // 索引條數
            int cnt = writer.numDocs();
            System.out.println("索引條數\t" + cnt);

            // 提交事物
            writer.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            coloseWriter(writer);
        }
    }

    static class Passage {
        private int id;
        private String username;
        private String email;
        private String keyword;
        private int age;
        // 這個模擬的是文章
        private String content;
        private Date addDate;

        public Passage(int id, String username, String email, String keyword, int age, String content, Date addDate) {
            super();
            this.id = id;
            this.username = username;
            this.email = email;
            this.keyword = keyword;
            this.age = age;
            this.content = content;
            this.addDate = addDate;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String userna