Java實(shí)現(xiàn)全文檢索-Lucene

1.1. 數(shù)據(jù)分類

結(jié)構(gòu)化數(shù)據(jù):指具有固定格式或有限長(zhǎng)度的數(shù)據(jù),如數(shù)據(jù)庫(kù)嚼黔,元數(shù)據(jù)等细层。
非結(jié)構(gòu)化數(shù)據(jù):指不定長(zhǎng)或無(wú)固定格式的數(shù)據(jù),如郵件唬涧,word文檔等磁盤上的文件

1.2. 非結(jié)構(gòu)化數(shù)據(jù)查詢方法

將非結(jié)構(gòu)化數(shù)據(jù)中的一部分信息提取出來(lái)疫赎,重新組織,使其變得有一定結(jié)構(gòu)碎节,然后對(duì)此有一定結(jié)構(gòu)的數(shù)據(jù)進(jìn)行搜索捧搞,從而達(dá)到搜索相對(duì)較快的目的。這部分從非結(jié)構(gòu)化數(shù)據(jù)中提取出的然后重新組織的信息,我們稱之索引胎撇。
例如:字典介粘。字典的拼音表和部首檢字表就相當(dāng)于字典的索引,對(duì)每一個(gè)字的解釋是非結(jié)構(gòu)化的晚树,如果字典沒(méi)有音節(jié)表和部首檢字表姻采,在茫茫辭海中找一個(gè)字只能順序掃描。然而字的某些信息可以提取出來(lái)進(jìn)行結(jié)構(gòu)化處理爵憎,比如讀音慨亲,就比較結(jié)構(gòu)化,分聲母和韻母宝鼓,分別只有幾種可以一一列舉刑棵,于是將讀音拿出來(lái)按一定的順序排列,每一項(xiàng)讀音都指向此字的詳細(xì)解釋的頁(yè)數(shù)愚铡。我們搜索時(shí)按結(jié)構(gòu)化的拼音搜到讀音蛉签,然后按其指向的頁(yè)數(shù),便可找到我們的非結(jié)構(gòu)化數(shù)據(jù)——也即對(duì)字的解釋茂附。
這種先建立索引正蛙,再對(duì)索引進(jìn)行搜索的過(guò)程就叫全文檢索(Full-text Search)督弓。
雖然創(chuàng)建索引的過(guò)程也是非常耗時(shí)的营曼,但是索引一旦創(chuàng)建就可以多次使用,全文檢索主要處理的是查詢愚隧,所以耗時(shí)間創(chuàng)建索引是值得的蒂阱。

2.1. 可以使用Lucene實(shí)現(xiàn)全文檢索

2.2.1. 獲取原始文檔
Lucene不提供信息采集的類庫(kù),需要自己編寫一個(gè)爬蟲(chóng)程序?qū)崿F(xiàn)信息采集狂塘,也可以通過(guò)一些開(kāi)源軟件實(shí)現(xiàn)信息采集录煤,如下:

Nutch(http://lucene.apache.org/nutch), Nutch是apache的一個(gè)子項(xiàng)目,包括大規(guī)模爬蟲(chóng)工具荞胡,能夠抓取和分辨web網(wǎng)站數(shù)據(jù)妈踊。

jsoup(http://jsoup.org/ ),jsoup 是一款Java 的HTML解析器泪漂,可直接解析某個(gè)URL地址廊营、HTML文本內(nèi)容。它提供了一套非常省力的API萝勤,可通過(guò)DOM露筒,CSS以及類似于jQuery的操作方法來(lái)取出和操作數(shù)據(jù)。

heritrix(http://sourceforge.net/projects/archive-crawler/files/)敌卓,Heritrix 是一個(gè)由 java 開(kāi)發(fā)的慎式、開(kāi)源的網(wǎng)絡(luò)爬蟲(chóng),用戶可以使用它來(lái)從網(wǎng)上抓取想要的資源。其最出色之處在于它良好的可擴(kuò)展性瘪吏,方便用戶實(shí)現(xiàn)自己的抓取邏輯癣防。

本案例我們要獲取磁盤上文件的內(nèi)容,可以通過(guò)文件流來(lái)讀取文本文件的內(nèi)容肪虎,對(duì)于pdf劣砍、doc、xls等文件可通過(guò)第三方提供的解析工具讀取文件內(nèi)容扇救,比如Apache POI讀取doc和xls的文件內(nèi)容刑枝。

2.2.2. 創(chuàng)建文檔對(duì)象
在索引前需要將原始內(nèi)容創(chuàng)建成文檔(Document),文檔中包括一個(gè)一個(gè)的域(Field)迅腔,域中存儲(chǔ)內(nèi)容装畅。
注意:每個(gè)Document可以有多個(gè)Field,不同的Document可以有不同的Field沧烈,同一個(gè)Document可以有相同的Field(域名和域值都相同)
每個(gè)文檔都有一個(gè)唯一的編號(hào)掠兄,就是文檔id。

此例子中


ABC.jpg

2.2.3. 分析文檔
需要再對(duì)域中的內(nèi)容進(jìn)行分析锌雀,分析的過(guò)程是經(jīng)過(guò)對(duì)原始文檔提取單詞蚂夕、將字母轉(zhuǎn)為小寫、去除標(biāo)點(diǎn)符號(hào)腋逆、去除停用詞等過(guò)程生成最終的語(yǔ)匯單元婿牍,可以將語(yǔ)匯單元理解為一個(gè)一個(gè)的單詞。

比如下邊的文檔經(jīng)過(guò)分析如下:
原文檔內(nèi)容:
Lucene is a Java full-text search engine. Lucene is not a complete
application, but rather a code library and API that can easily be used
to add search capabilities to applications.
分析后得到的語(yǔ)匯單元:
lucene惩歉、java等脂、full、search撑蚌、engine上遥。。争涌。粉楚。

每個(gè)單詞叫做一個(gè)Term,不同的域中拆分出來(lái)的相同的單詞是不同的term亮垫。term中包含兩部分一部分是文檔的域名模软,另一部分是單詞的內(nèi)容。
例如:文件名中包含apache和文件內(nèi)容中包含的apache是不同的term包警。

2.2.4. 創(chuàng)建索引
對(duì)所有文檔分析得出的語(yǔ)匯單元進(jìn)行索引撵摆,索引的目的是為了搜索
注意:創(chuàng)建索引是對(duì)語(yǔ)匯單元索引,通過(guò)詞語(yǔ)找文檔害晦,這種索引的結(jié)構(gòu)叫倒排索引結(jié)構(gòu)特铝。
傳統(tǒng)方法是根據(jù)文件找到該文件的內(nèi)容暑中,在文件內(nèi)容中匹配搜索關(guān)鍵字,這種方法是順序掃描方法鲫剿,數(shù)據(jù)量大鳄逾、搜索慢。

2.2.5. 查詢索引
用戶輸入查詢關(guān)鍵字執(zhí)行搜索之前需要先構(gòu)建一個(gè)查詢對(duì)象灵莲,查詢對(duì)象中可以指定查詢要搜索的Field文檔域雕凹、查詢關(guān)鍵字等,查詢對(duì)象會(huì)生成具體的查詢語(yǔ)法政冻,
例如:
語(yǔ)法 “fileName:lucene”表示要搜索Field域的內(nèi)容為“l(fā)ucene”的文檔
搜索過(guò)程就是在索引上查找域?yàn)閒ileName枚抵,并且關(guān)鍵字為L(zhǎng)ucene的term,并根據(jù)term找到文檔id列表明场。

3.1. Lucene應(yīng)用

3.1.1. 功能一:創(chuàng)建索引庫(kù)

3.1.2. Field域的屬性

sadb.jpg

代碼實(shí)現(xiàn)


//創(chuàng)建索引
    @Test
    public void createIndex() throws Exception {
        
        //指定索引庫(kù)存放的路徑
        //D:\temp\0108\index
        Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index"));
        //索引庫(kù)還可以存放到內(nèi)存中
        //Directory directory = new RAMDirectory();
        //創(chuàng)建一個(gè)標(biāo)準(zhǔn)分析器
        Analyzer analyzer = new StandardAnalyzer();
        //創(chuàng)建indexwriterCofig對(duì)象
        //第一個(gè)參數(shù): Lucene的版本信息汽摹,可以選擇對(duì)應(yīng)的lucene版本也可以使用LATEST
        //第二根參數(shù):分析器對(duì)象
        IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer);
        //創(chuàng)建indexwriter對(duì)象
        IndexWriter indexWriter = new IndexWriter(directory, config);
        //原始文檔的路徑D:\傳智播客\01.課程\04.lucene\01.參考資料\searchsource
        File dir = new File("D:\\傳智播客\\01.課程\\04.lucene\\01.參考資料\\searchsource");
        for (File f : dir.listFiles()) {
            //文件名
            String fileName = f.getName();
            //文件內(nèi)容
            String fileContent = FileUtils.readFileToString(f);
            //文件路徑
            String filePath = f.getPath();
            //文件的大小
            long fileSize  = FileUtils.sizeOf(f);
            //創(chuàng)建文件名域
            //第一個(gè)參數(shù):域的名稱
            //第二個(gè)參數(shù):域的內(nèi)容
            //第三個(gè)參數(shù):是否存儲(chǔ)
            Field fileNameField = new TextField("filename", fileName, Store.YES);
            //文件內(nèi)容域
            Field fileContentField = new TextField("content", fileContent, Store.YES);
            //文件路徑域(不分析、不索引苦锨、只存儲(chǔ))
            Field filePathField = new StoredField("path", filePath);
            //文件大小域
            Field fileSizeField = new LongField("size", fileSize, Store.YES);
            
            //創(chuàng)建document對(duì)象
            Document document = new Document();
            document.add(fileNameField);
            document.add(fileContentField);
            document.add(filePathField);
            document.add(fileSizeField);
            //創(chuàng)建索引逼泣,并寫入索引庫(kù)
            indexWriter.addDocument(document);
        }
        //關(guān)閉indexwriter
        indexWriter.close();
    }


3.2.1. 功能二:查詢索引

sad.jpg

代碼實(shí)現(xiàn)


//查詢索引庫(kù)
    @Test
    public void searchIndex() throws Exception {
        //指定索引庫(kù)存放的路徑
        //D:\temp\0108\index
        Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index"));
        //創(chuàng)建indexReader對(duì)象
        IndexReader indexReader = DirectoryReader.open(directory);
        //創(chuàng)建indexsearcher對(duì)象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        //創(chuàng)建查詢
        Query query = new TermQuery(new Term("filename", "apache"));
        //執(zhí)行查詢
        //第一個(gè)參數(shù)是查詢對(duì)象,第二個(gè)參數(shù)是查詢結(jié)果返回的最大值
        TopDocs topDocs = indexSearcher.search(query, 10);
        //查詢結(jié)果的總條數(shù)
        System.out.println("查詢結(jié)果的總條數(shù):"+ topDocs.totalHits);
        //遍歷查詢結(jié)果
        //topDocs.scoreDocs存儲(chǔ)了document對(duì)象的id
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            //scoreDoc.doc屬性就是document對(duì)象的id
            //根據(jù)document的id找到document對(duì)象
            Document document = indexSearcher.doc(scoreDoc.doc);
            System.out.println(document.get("filename"));
            //System.out.println(document.get("content"));
            System.out.println(document.get("path"));
            System.out.println(document.get("size"));
        }
        //關(guān)閉indexreader對(duì)象
        indexReader.close();
    }

3.3 功能三:分析器

3.3.1常規(guī)分析器的分詞效果

//查看標(biāo)準(zhǔn)分析器的分詞效果
    public void testTokenStream() throws Exception {
        //創(chuàng)建一個(gè)標(biāo)準(zhǔn)分析器對(duì)象
        Analyzer analyzer = new StandardAnalyzer();
        //獲得tokenStream對(duì)象
        //第一個(gè)參數(shù):域名舟舒,可以隨便給一個(gè)
        //第二個(gè)參數(shù):要分析的文本內(nèi)容
        TokenStream tokenStream = analyzer.tokenStream("test", "The Spring Framework provides a comprehensive programming and configuration model.");
        //添加一個(gè)引用拉庶,可以獲得每個(gè)關(guān)鍵詞
        CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
        //添加一個(gè)偏移量的引用,記錄了關(guān)鍵詞的開(kāi)始位置以及結(jié)束位置
        OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
        //將指針調(diào)整到列表的頭部
        tokenStream.reset();
        //遍歷關(guān)鍵詞列表秃励,通過(guò)incrementToken方法判斷列表是否結(jié)束
        while(tokenStream.incrementToken()) {
            //關(guān)鍵詞的起始位置
            System.out.println("start->" + offsetAttribute.startOffset());
            //取關(guān)鍵詞
            System.out.println(charTermAttribute);
            //結(jié)束位置
            System.out.println("end->" + offsetAttribute.endOffset());
        }
        tokenStream.close();
    }

3.3.2 中文分析器

Lucene自帶中文分詞器
? StandardAnalyzer:
單字分詞:就是按照中文一個(gè)字一個(gè)字地進(jìn)行分詞氏仗。如:“我愛(ài)中國(guó)”,
效果:“我”莺治、“愛(ài)”廓鞠、“中”帚稠、“國(guó)”谣旁。
? CJKAnalyzer:
二分法分詞:按兩個(gè)字進(jìn)行切分。如:“我是中國(guó)人”滋早,效果:“我是”榄审、“是中”、“中國(guó)”“國(guó)人”杆麸。

上邊兩個(gè)分詞器無(wú)法滿足需求搁进。
? SmartChineseAnalyzer:
對(duì)中文支持較好,但擴(kuò)展性差昔头,擴(kuò)展詞庫(kù)饼问,禁用詞庫(kù)和同義詞庫(kù)等不好處理

第三方中文分析器
· paoding: 庖丁解牛最新版在 https://code.google.com/p/paoding/ 中最多支持Lucene 3.0,且最新提交的代碼在 2008-06-03揭斧,在svn中最新也是2010年提交莱革,已經(jīng)過(guò)時(shí),不予考慮。

· mmseg4j:最新版已從 https://code.google.com/p/mmseg4j/ 移至 https://github.com/chenlb/mmseg4j-solr盅视,支持Lucene 4.10捐名,且在github中最新提交代碼是2014年6月,從09年~14年一共有:18個(gè)版本闹击,也就是一年幾乎有3個(gè)大小版本镶蹋,有較大的活躍度,用了mmseg算法赏半。

· IK-analyzer: 最新版在https://code.google.com/p/ik-analyzer/上贺归,支持Lucene 4.10從2006年12月推出1.0版開(kāi)始, IKAnalyzer已經(jīng)推出了4個(gè)大版本断箫。最初牧氮,它是以開(kāi)源項(xiàng)目Luence為應(yīng)用主體的,結(jié)合詞典分詞和文法分析算法的中文分詞組件瑰枫。從3.0版本開(kāi) 始踱葛,IK發(fā)展為面向Java的公用分詞組件,獨(dú)立于Lucene項(xiàng)目光坝,同時(shí)提供了對(duì)Lucene的默認(rèn)優(yōu)化實(shí)現(xiàn)尸诽。在2012版本中,IK實(shí)現(xiàn)了簡(jiǎn)單的分詞 歧義排除算法盯另,標(biāo)志著IK分詞器從單純的詞典分詞向模擬語(yǔ)義分詞衍化性含。 但是也就是2012年12月后沒(méi)有在更新。

· ansj_seg:最新版本在 https://github.com/NLPchina/ansj_seg tags僅有1.1版本鸳惯,從2012年到2014年更新了大小6次商蕴,但是作者本人在2014年10月10日說(shuō)明:“可能我以后沒(méi)有精力來(lái)維護(hù)ansj_seg了”,現(xiàn)在由”nlp_china”管理芝发。2014年11月有更新绪商。并未說(shuō)明是否支持Lucene,是一個(gè)由CRF(條件隨機(jī)場(chǎng))算法所做的分詞算法辅鲸。

· imdict-chinese-analyzer:最新版在 https://code.google.com/p/imdict-chinese-analyzer/ 格郁, 最新更新也在2009年5月,下載源碼独悴,不支持Lucene 4.10 例书。是利用HMM(隱馬爾科夫鏈)算法。

· Jcseg:最新版本在git.oschina.net/lionsoul/jcseg刻炒,支持Lucene 4.10决采,作者有較高的活躍度。利用mmseg算法坟奥。

3.3.3 Analyzer使用時(shí)機(jī)

  1. 索引時(shí)使用Analyzer:對(duì)文檔域內(nèi)容進(jìn)行分析树瞭,需要經(jīng)過(guò)Analyzer分析器處理生成語(yǔ)匯單元(Token)暂幼。
  2. 搜索時(shí)使用Analyzer:對(duì)搜索關(guān)鍵字進(jìn)行分析、分詞處理移迫,使用分析后每個(gè)詞語(yǔ)進(jìn)行搜索
    注意:搜索使用的分析器要和索引使用的分析器一致旺嬉。

3.4 功能四:索引庫(kù)的維護(hù)

//添加索引
    @Test
    public void addDocument() throws Exception {
        //索引庫(kù)存放路徑
        Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index"));
        
        IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, new IKAnalyzer());
        //創(chuàng)建一個(gè)indexwriter對(duì)象
        IndexWriter indexWriter = new IndexWriter(directory, config);
        //創(chuàng)建一個(gè)Document對(duì)象
        Document document = new Document();
        //向document對(duì)象中添加域。
        //不同的document可以有不同的域厨埋,同一個(gè)document可以有相同的域邪媳。
        document.add(new TextField("filename", "新添加的文檔", Store.YES));
        document.add(new TextField("content", "新添加的文檔的內(nèi)容", Store.NO));
        document.add(new TextField("content", "新添加的文檔的內(nèi)容第二個(gè)content", Store.YES));
        document.add(new TextField("content1", "新添加的文檔的內(nèi)容要能看到", Store.YES));
        //添加文檔到索引庫(kù)
        indexWriter.addDocument(document);
        //關(guān)閉indexwriter
        indexWriter.close();
        
    }

3.4.1. 索引庫(kù)的添加

//添加索引
    @Test
    public void addDocument() throws Exception {
        //索引庫(kù)存放路徑
        Directory directory = FSDirectory.open(new File("D:\\temp\\0108\\index"));
        
        IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, new IKAnalyzer());
        //創(chuàng)建一個(gè)indexwriter對(duì)象
        IndexWriter indexWriter = new IndexWriter(directory, config);
        //創(chuàng)建一個(gè)Document對(duì)象
        Document document = new Document();
        //向document對(duì)象中添加域。
        //不同的document可以有不同的域荡陷,同一個(gè)document可以有相同的域。
        document.add(new TextField("filename", "新添加的文檔", Store.YES));
        document.add(new TextField("content", "新添加的文檔的內(nèi)容", Store.NO));
        document.add(new TextField("content", "新添加的文檔的內(nèi)容第二個(gè)content", Store.YES));
        document.add(new TextField("content1", "新添加的文檔的內(nèi)容要能看到", Store.YES));
        //添加文檔到索引庫(kù)
        indexWriter.addDocument(document);
        //關(guān)閉indexwriter
        indexWriter.close();
        
    }

3.4.3. 索引庫(kù)的刪除

  1. 刪除全部
//刪除全部索引
    @Test
    public void deleteAllIndex() throws Exception {
        IndexWriter indexWriter = getIndexWriter();
        //刪除全部索引
        indexWriter.deleteAll();
        //關(guān)閉indexwriter
        indexWriter.close();
    }

  1. 指定查詢條件刪除
//根據(jù)查詢條件刪除索引
    @Test
    public void deleteIndexByQuery() throws Exception {
        IndexWriter indexWriter = getIndexWriter();
        //創(chuàng)建一個(gè)查詢條件
        Query query = new TermQuery(new Term("filename", "apache"));
        //根據(jù)查詢條件刪除
        indexWriter.deleteDocuments(query);
        //關(guān)閉indexwriter
        indexWriter.close();
    }

  1. 索引庫(kù)的修改
//修改索引庫(kù)
    @Test
    public void updateIndex() throws Exception {
        IndexWriter indexWriter = getIndexWriter();
        //創(chuàng)建一個(gè)Document對(duì)象
        Document document = new Document();
        //向document對(duì)象中添加域极颓。
        //不同的document可以有不同的域狂秘,同一個(gè)document可以有相同的域破衔。
        document.add(new TextField("filename", "要更新的文檔", Store.YES));
        document.add(new TextField("content", "2013年11月18日 - Lucene 簡(jiǎn)介 Lucene 是一個(gè)基于 Java 的全文信息檢索工具包,它不是一個(gè)完整的搜索應(yīng)用程序,而是為你的應(yīng)用程序提供索引和搜索功能忠售。", Store.YES));
        indexWriter.updateDocument(new Term("content", "java"), document);
        //關(guān)閉indexWriter
        indexWriter.close();
    }

3.5.1 Lucene索引庫(kù)查詢

可通過(guò)兩種方法創(chuàng)建查詢對(duì)象:
1)使用Lucene提供Query子類
Query是一個(gè)抽象類泰佳,lucene提供了很多查詢對(duì)象,比如TermQuery項(xiàng)精確查詢,NumericRangeQuery數(shù)字范圍查詢等。
如下代碼:
Query query = new TermQuery(new Term("name", "lucene"));
2)使用QueryParse解析查詢表達(dá)式
QueryParse會(huì)將用戶輸入的查詢表達(dá)式解析成Query對(duì)象實(shí)例险绘。
如下代碼:
QueryParser queryParser = new QueryParser("name", new IKAnalyzer());
Query query = queryParser.parse("name:lucene");

3.5.2. 使用query的子類查詢
①M(fèi)atchAllDocsQuery

使用MatchAllDocsQuery查詢索引目錄中的所有文檔

@Test
    public void testMatchAllDocsQuery() throws Exception {
        IndexSearcher indexSearcher = getIndexSearcher();
        //創(chuàng)建查詢條件
        Query query = new MatchAllDocsQuery();
        //執(zhí)行查詢
        printResult(query, indexSearcher);
    }

②TermQuery

TermQuery渺氧,通過(guò)項(xiàng)查詢,TermQuery不使用分析器所以建議匹配不分詞的Field域查詢潮太,比如訂單號(hào)、分類ID號(hào)等景埃。
指定要查詢的域和要查詢的關(guān)鍵詞。

//使用Termquery查詢
    @Test
    public void testTermQuery() throws Exception {
        IndexSearcher indexSearcher = getIndexSearcher();
        //創(chuàng)建查詢對(duì)象
        Query query = new TermQuery(new Term("content", "lucene"));
        //執(zhí)行查詢
        TopDocs topDocs = indexSearcher.search(query, 10);
        //共查詢到的document個(gè)數(shù)
        System.out.println("查詢結(jié)果總數(shù)量:" + topDocs.totalHits);
        //遍歷查詢結(jié)果
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            Document document = indexSearcher.doc(scoreDoc.doc);
            System.out.println(document.get("filename"));
            //System.out.println(document.get("content"));
            System.out.println(document.get("path"));
            System.out.println(document.get("size"));
        }
        //關(guān)閉indexreader
        indexSearcher.getIndexReader().close();
    }

③NumericRangeQuery

可以根據(jù)數(shù)值范圍查詢。

//數(shù)值范圍查詢
    @Test
    public void testNumericRangeQuery() throws Exception {
        IndexSearcher indexSearcher = getIndexSearcher();
        //創(chuàng)建查詢
        //參數(shù):
        //1.域名
        //2.最小值
        //3.最大值
        //4.是否包含最小值
        //5.是否包含最大值
        Query query = NumericRangeQuery.newLongRange("size", 1l, 1000l, true, true);
        //執(zhí)行查詢
        printResult(query, indexSearcher);
    }

④BooleanQuery
可以組合查詢條件乞巧。

//組合條件查詢
    @Test
    public void testBooleanQuery() throws Exception {
        IndexSearcher indexSearcher = getIndexSearcher();
        //創(chuàng)建一個(gè)布爾查詢對(duì)象
        BooleanQuery query = new BooleanQuery();
        //創(chuàng)建第一個(gè)查詢條件
        Query query1 = new TermQuery(new Term("filename", "apache"));
        Query query2 = new TermQuery(new Term("content", "apache"));
        //組合查詢條件
        query.add(query1, Occur.MUST);
        query.add(query2, Occur.MUST);
        //執(zhí)行查詢
        printResult(query, indexSearcher);
    }
//Occur.MUST:必須滿足此條件,相當(dāng)于and
//Occur.SHOULD:應(yīng)該滿足摊鸡,但是不滿足也可以绽媒,相當(dāng)于or
//Occur.MUST_NOT:必須不滿足。相當(dāng)于not

3.5.3. 使用queryparser查詢
通過(guò)QueryParser也可以創(chuàng)建Query免猾,QueryParser提供一個(gè)Parse方法是辕,此方法可以直接根據(jù)查詢語(yǔ)法來(lái)查詢。Query對(duì)象執(zhí)行的查詢語(yǔ)法可通過(guò)System.out.println(query);查詢猎提。
需要使用到分析器获三。建議創(chuàng)建索引時(shí)使用的分析器和查詢索引時(shí)使用的分析器要一致。

程序?qū)崿F(xiàn)

@Test
    public void testQueryParser() throws Exception {
        IndexSearcher indexSearcher = getIndexSearcher();
        //創(chuàng)建queryparser對(duì)象
        //第一個(gè)參數(shù)默認(rèn)搜索的域
        //第二個(gè)參數(shù)就是分析器對(duì)象
        QueryParser queryParser = new QueryParser("content", new IKAnalyzer());
        Query query = queryParser.parse("Lucene是java開(kāi)發(fā)的");
        //執(zhí)行查詢
        printResult(query, indexSearcher);
    }

查詢語(yǔ)法
1锨苏、基礎(chǔ)的查詢語(yǔ)法疙教,關(guān)鍵詞查詢:

域名+“:”+搜索的關(guān)鍵字

例如:content:java

2、范圍查詢

域名+“:”+[最小值 TO 最大值]

例如:size:[1 TO 1000]

范圍查詢?cè)趌ucene中支持?jǐn)?shù)值類型伞租,不支持字符串類型贞谓。在solr中支持字符串類型。

3葵诈、組合條件查詢

1)+條件1 +條件2:兩個(gè)條件之間是并且的關(guān)系and

例如:+filename:apache +content:apache

2)+條件1 條件2:必須滿足第一個(gè)條件裸弦,應(yīng)該滿足第二個(gè)條件

例如:+filename:apache content:apache

3)條件1 條件2:兩個(gè)條件滿足其一即可。

例如:filename:apache content:apache

4)-條件1 條件2:必須不滿足條件1作喘,要滿足條件2

例如:-filename:apache content:apache

Occur.MUST 查詢條件必須滿足理疙,相當(dāng)于and → +(加號(hào))
Occur.SHOULD 查詢條件可選,相當(dāng)于or → 空(不用符號(hào))
Occur.MUST_NOT 查詢條件不能滿足徊都,相當(dāng)于not非 → -(減號(hào))

第二種寫法:

條件1 AND 條件2

條件1 OR 條件2

條件1 NOT 條件2

MultiFieldQueryParser
可以指定多個(gè)默認(rèn)搜索域

@Test
    public void testMultiFiledQueryParser() throws Exception {
        IndexSearcher indexSearcher = getIndexSearcher();
        //可以指定默認(rèn)搜索的域是多個(gè)
        String[] fields = {"filename", "content"};
        //創(chuàng)建一個(gè)MulitFiledQueryParser對(duì)象
        MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields, new IKAnalyzer());
        Query query = queryParser.parse("java AND apache");
        System.out.println(query);
        //執(zhí)行查詢
        printResult(query, indexSearcher);
        
    }

e.g. 本文僅供個(gè)人筆記使用沪斟,借鑒部分網(wǎng)上資料。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暇矫,一起剝皮案震驚了整個(gè)濱河市主之,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌李根,老刑警劉巖槽奕,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異房轿,居然都是意外死亡粤攒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門囱持,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)夯接,“玉大人,你說(shuō)我怎么就攤上這事纷妆】福” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵掩幢,是天一觀的道長(zhǎng)逊拍。 經(jīng)常有香客問(wèn)我,道長(zhǎng)际邻,這世上最難降的妖魔是什么芯丧? 我笑而不...
    開(kāi)封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮世曾,結(jié)果婚禮上缨恒,老公的妹妹穿的比我還像新娘。我一直安慰自己轮听,他們只是感情好肿轨,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蕊程,像睡著了一般椒袍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上藻茂,一...
    開(kāi)封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天驹暑,我揣著相機(jī)與錄音,去河邊找鬼辨赐。 笑死优俘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掀序。 我是一名探鬼主播帆焕,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了叶雹?” 一聲冷哼從身側(cè)響起财饥,我...
    開(kāi)封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎折晦,沒(méi)想到半個(gè)月后钥星,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡满着,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年谦炒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片风喇。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡宁改,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出魂莫,到底是詐尸還是另有隱情还蹲,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布豁鲤,位于F島的核電站秽誊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏琳骡。R本人自食惡果不足惜锅论,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望楣号。 院中可真熱鬧最易,春花似錦、人聲如沸炫狱。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)视译。三九已至嬉荆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酷含,已是汗流浹背鄙早。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留椅亚,地道東北人限番。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像呀舔,于是被迫代替她去往敵國(guó)和親弥虐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 1. 案例分析:什么時(shí)全文檢索,如何實(shí)現(xiàn)全文檢索 ? 1.1 案例 ? 實(shí)現(xiàn)一個(gè)文件的搜索功能霜瘪,通過(guò)關(guān)鍵字搜索文件...
    東方舵手閱讀 1,176評(píng)論 0 1
  • 目錄結(jié)構(gòu):1.全文檢索 2.Lucene入門3.Lucene進(jìn)階 全文檢索 一, 生活中的搜索:1.Win...
    CoderZS閱讀 1,663評(píng)論 0 12
  • 1. Lucene 官網(wǎng) 1). 概述 Lucene是一款高性能的珠插、可擴(kuò)展的信息檢索(IR)工具庫(kù)。信息檢索是指文...
    _凌浩雨閱讀 926評(píng)論 0 1
  • 也是項(xiàng)目需要用的框架之一,為了不讓自己輕易忘記它琳拭,在此記錄一系列的lucene學(xué)習(xí)筆記(基于lucene4.4训堆,I...
    JackFrost_fuzhu閱讀 2,000評(píng)論 4 27
  • (五) 林落珩離開(kāi)的日子,像是一張永遠(yuǎn)不上色的空白的紙白嘁,它堅(jiān)強(qiáng)坑鱼,是因?yàn)樗肋h(yuǎn)保持干凈,它脆弱絮缅,是因?yàn)樗荒苁羌埪沉ぃ瑩?..
    藜遠(yuǎn)閱讀 343評(píng)論 0 3