19高級(jí)進(jìn)階版lucene全文檢索老師什么是_第1頁(yè)
19高級(jí)進(jìn)階版lucene全文檢索老師什么是_第2頁(yè)
19高級(jí)進(jìn)階版lucene全文檢索老師什么是_第3頁(yè)
19高級(jí)進(jìn)階版lucene全文檢索老師什么是_第4頁(yè)
19高級(jí)進(jìn)階版lucene全文檢索老師什么是_第5頁(yè)
已閱讀5頁(yè),還剩173頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、Lucene 的概述:1.1 什么是 lucene這是一篇很好的文章。下面便是取自這里。Lucene 是一個(gè)全文搜索框架,而不是應(yīng)用。因此它并不像 或者Desktop 那么拿來(lái)就能用,它只是提供了一種工具讓你能實(shí)現(xiàn)這些。1.2 lucene 能做什么要回答這個(gè)問(wèn)題,先要了解 lucene 的本質(zhì)。實(shí)際上 lucene 的功能很單一,說(shuō)到底,就是你給它若干個(gè)字符串,然后它為你提供一個(gè)全文搜索服務(wù),告訴你你要搜索的出現(xiàn)在哪里。知道了這個(gè)本質(zhì),你就可以發(fā)揮想象做任何符合這個(gè)條件的事情了。你可以把站內(nèi)都索引了,做個(gè)資料庫(kù);你可以把一個(gè)數(shù)據(jù)庫(kù)表的若干個(gè)字段索引起來(lái),那就不用再擔(dān)心因?yàn)椤?like%”而鎖

2、表了;你也可以寫(xiě)個(gè)的搜索引擎1.3 你該不該選擇 lucene下面給出一些測(cè)試數(shù)據(jù),如果你覺(jué)得可以接受,那么可以選擇。測(cè)試一:250 萬(wàn),300M 左右文本,生成索引 380M 左右,800 線程下平均處理時(shí)間 300ms。測(cè)試二:37000,索引數(shù)據(jù)庫(kù)中的兩個(gè) varchar 字段,索引文件 2.6M,800 線程下平均處理時(shí)間 1.5ms。2 lucene 的工作方式lucene 提供的服務(wù)實(shí)際包含兩部分:一入一出。所謂入是寫(xiě)入,即將你提供的源(本質(zhì)是字符串)寫(xiě)入索引或者將其從索引中刪除;所謂出是讀出,即向用戶提供全文搜索服務(wù),讓用戶可以通過(guò)源。2.1 寫(xiě)入流程源字符串首先經(jīng)過(guò) analy

3、zer 處理,包括:分詞,分成一個(gè)個(gè)單詞;去除 stopword(可選)。將源中需要的信息加入 Document 的各個(gè) Field 中,并把需要索引的 Field 索引起來(lái),把需要的 Field起來(lái)。將索引寫(xiě)入器,器可以是內(nèi)存或磁盤(pán)。2.2 讀出流程用戶提供搜索,經(jīng)過(guò) analyzer 處理。對(duì)處理后的搜索索引找出對(duì)應(yīng)的 Document。用戶根據(jù)需要從找到的 Document 中提取需要的 Field。3 一些需要知道的概念lucene 用到一些概念,了解它們的含義,有利于下面的講解。3.1 analyzerAnalyzer 是分析器,它的作用是把一個(gè)字符串按某種規(guī)則劃分成一個(gè)個(gè)詞語(yǔ),并去

4、除其中的無(wú)效詞語(yǔ),這里說(shuō)的無(wú)效詞語(yǔ)是指英文中的“ of”、 “the”,中文中的 “的”、“地”等詞語(yǔ),這些詞語(yǔ)在文章中大量出現(xiàn),但是本身不包含什么關(guān)鍵信息,去掉有利于縮小索引文件、提高效率、提高。分詞的規(guī)則千變?nèi)f化,但目的只有一個(gè):按語(yǔ)義劃分。這點(diǎn)在英文中比較容易實(shí)現(xiàn),因?yàn)橛⑽谋旧砭褪且詥卧~為的,已經(jīng)用空格;而中文則必須以某種方法將連成一片的句子劃分成一個(gè)個(gè)詞語(yǔ)。具體劃分方法下面再詳細(xì)介紹,這里只需了解分析器的概念即可。3.2 document用戶提供的源是一條條,它們可以是文本文件、字符串或者數(shù)據(jù)庫(kù)表的一條等等。一條經(jīng)過(guò)索引之后,就是以一個(gè) Document 的形式在索引文件中的。用戶進(jìn)行

5、搜索,也是以 Document 列表的形式返回。3.3 field一個(gè) Document 可以包含多個(gè)信息域,例如一篇文章可以包含“標(biāo)題”、“正文”、“最后修改時(shí)間”等信息域,這些信息域就是通過(guò) Field 在 Document 中的。Field 有兩個(gè)屬性可選:和索引。通過(guò)屬性你可以是否對(duì)這個(gè)Field 進(jìn)行;通過(guò)索引屬性你可以是否對(duì)該 Field 進(jìn)行索引。這看起來(lái)似乎有些廢話,事實(shí)上對(duì)這兩個(gè)屬性的正確組合很重要,下面舉例說(shuō)明:還是以剛才的文章為例子,我們需要對(duì)標(biāo)題和正文進(jìn)行全文搜索,所以我們要把索引屬性設(shè)置為真,同時(shí)我們希望能直接從搜索結(jié)果中提取文章標(biāo)題,所以我們把標(biāo)題域的屬性設(shè)置為真,

6、但是由于正文域太大了,我們?yōu)榱丝s小索引文件大小,將正文域的屬性設(shè)置為假,當(dāng)需要時(shí)再直接文件;我們只是希望能從搜索解果中提取最后修改時(shí)間,不需要對(duì)它進(jìn)行搜索,所以我們把最后修改時(shí)間域的屬性設(shè)置為真,索引屬性設(shè)置為假。上面的三個(gè)域涵蓋了兩個(gè)屬性的三種組合,還有一種全為沒(méi)有用到,事實(shí)上 Field 不你那么設(shè)置,因?yàn)榧炔挥植凰饕挠蚴菦](méi)有意義的。3.4 termterm 是搜索的最小,它表示文檔的一個(gè)詞語(yǔ), term 由兩部分組成:它表示的詞語(yǔ)和這個(gè)詞語(yǔ)所出現(xiàn)的 field。3.5 tockentocken 是 term 的一次出現(xiàn),它包含 trem 文本和相應(yīng)的起止偏移,以及一個(gè)類(lèi)型字符串。一句話

7、中可以出現(xiàn)多次相同的詞語(yǔ),它們都用同一個(gè) term 表示,但是用不同的 tocken,每個(gè) tocken 標(biāo)記該詞語(yǔ)出現(xiàn)的地方。3.6 segment添加索引時(shí)并不是每個(gè) document 都馬上添加到同一個(gè)索引文件,它們首先被寫(xiě)入到不同的小文件,然后再合并成一個(gè)大索引文件,這里每個(gè)小文件都是一個(gè) segment。4 lucene 的結(jié)構(gòu)lucene 包括 core 和 sandbox 兩部分,其中 core 是 lucene 穩(wěn)定的部分,sandbox 包含了一些附加功能,例如 highlighter、各種分析器。 Lucene core 有七個(gè)包:analysis,document,ind

8、ex,queryParser,search,store,util。對(duì)于 4.5 版本不是這 7 個(gè)包,而是如下:關(guān)于這些的詳細(xì)介紹,后面再說(shuō)。環(huán)境的準(zhǔn)備:1.先開(kāi)發(fā)的 jar 包: 我們把 zip 和 src下來(lái)就可以了。2. 對(duì)于開(kāi)源的框架,一般使用都有 2 個(gè)步驟a) 添加 jar 包為了項(xiàng)目的可移植性,我們應(yīng)該建立一個(gè) lib 文件夾,專(zhuān)門(mén)放外部的 jar 包,然后把需要的 jar 包放入到這個(gè)目錄,最后在進(jìn)項(xiàng)目里面b) 配置文件3. 根據(jù)開(kāi)檔搭建環(huán)境a)先讀 readme 文件,他會(huì)告訴你怎么用,告訴你這項(xiàng)目是什么b)再根據(jù) a)的指導(dǎo),相應(yīng)的文件,也就是 docs/index.htm

9、lc)Index 只指導(dǎo)我們看 demon,于是只能網(wǎng)上搜索 demo 怎么用下面是 demon 的使用方法:我們按照這個(gè)做法做就是了(預(yù)告:最后沒(méi)有找到怎么搭建工程的方法)i) 定義環(huán)境變量:CLASSPATH 的值如下:D:soft_framework_utileslucene-4.5.0lucene-4.5.0corelucene-core-4.5.0.jar;D:soft_framework_utileslucene-4.5.0lucene-4.5.0demolucene-demo-4.5.0.jar;D:soft_framework_utileslucene-4.5.0lucene-

10、4.5.0queryparserlucene-queryparser-4.5.0.jar;D:soft_framework_utileslucene-4.5.0lucene-4.5.0analysiscommonlucene-analyzers-common-4.5.0.jar;把這個(gè) 4 個(gè) jar 放進(jìn)去就是了。j) 開(kāi)始測(cè)試 demonà建立索引java org.apache.lucene.demo.IndexFiles -indexindexfolder-docsdocs folder設(shè)置要生成的索引的文件夾和要的 docs我們的 doc 目錄用:demolf_test_do

11、cs_dir生成的 index 目錄用:demolf_test_index_dir下面就是執(zhí)行過(guò)程:我們可以去看 index 目錄的生成的文件:k) 開(kāi)始測(cè)試 demonà執(zhí)行java org.apache.lucene.demo.SearchFiles將會(huì)出現(xiàn)“Query:”提示符,在其后輸入關(guān)鍵字,回車(chē),即可得到結(jié)果由于 SearchFiles 是查找當(dāng)前目錄下面的 index 目錄作為索引文件目錄,所以這里報(bào)錯(cuò)了,我們可以用-index 參數(shù)指定我們的 index 目錄:可以看到mozilla 得到 3 個(gè)文檔有這個(gè)關(guān)鍵字。4. 到教學(xué)的東西,那么我們就查資料吧,下面是做法需要

12、的 jar 包是:Ølucene-core-4.5.0.jar包Ølucene-analyzers-common-4.5.0.jar分詞器Ølucene-highlighter-4.5.0.jar高亮器添加到項(xiàng)目 buildpath:如下顯示就對(duì)了:5. 寫(xiě)我們的代碼了先生成索引:(代碼插件挺好用?。〥ocument document=LuceneUtiles.getDocument(filePath);/存放索引的目錄Directory indexDirectory=FSDirectory.open( new File(indexPath);/這里默認(rèn)使用的模式

13、是:openMode = OpenMode.CREATE_OR_APPEND;/IndexWriterConfig 的父類(lèi)構(gòu)造是初始化的IndexWriterConfig indexWriterConfig=newIndexWriterConfig(Version.LUCENE_45, analyzer);/索引的維護(hù)是用 IndexWriter 來(lái)做的,把 doc 添加進(jìn)去,更新,刪除就行了IndexWriter indexWriter=newIndexWriter(indexDirectory,indexWriterConfig);indexWriter.addDocument(docum

14、ent);/所有 io 操作的,最后都應(yīng)該關(guān)閉,比如file,network,database 等indexWriter.close();:publicvoidsearchFromIndex()throwsIOException /只能全小寫(xiě)才可以!因?yàn)槲覀?term 沒(méi)有經(jīng)過(guò)分詞器處理!/所以只能用直接跟索引庫(kù)的關(guān)鍵字一一對(duì)應(yīng)的值/以后講解把索引字符串也處理的方法String queryString="binary"/1.收索字符串->Query 對(duì)象Query query=null; /注意:/因?yàn)槲募诮⑺饕臅r(shí)候(分詞器那里),就已經(jīng)做了一次大小寫(xiě)轉(zhuǎn)換了,/

15、存的索引全是小寫(xiě)的/而我們這里搜索的時(shí)候沒(méi)有通過(guò)分詞器,所以我們的數(shù)據(jù)沒(méi)有轉(zhuǎn)化,/那么如果這里是大寫(xiě)類(lèi)型就搜不到任何東西!Term term=newTerm("fileContent",queryString);/至于這里用什么 Query,以后再說(shuō)query=newTermQuery(term); /2.進(jìn)行TopDocs topDocs=null; IndexSearcher searcher=null; IndexReader indexReader=null; /指定索引的文件位置indexReader=DirectoryReader.open(FSDirector

16、y.open(newFile(indexPath); searcher=newIndexSearcher(indexReader); Filter filter=null;/搜索/過(guò)濾器,可以過(guò)濾一些文件,null 就是不用過(guò)濾器/數(shù)字代表每次多少條,也就是一次數(shù)據(jù)的讀多少條,/1000,10000 等比較合適,默認(rèn)是 50/topDocs=searcher.search(query, filter,1000); /3.打印結(jié)果 System.out.println("總共有【"+topDocs.totalHits+"】條匹配結(jié)果");/這是返回的數(shù)據(jù)f

17、or(inti=0; i<topDocs.scoreDocs.length; i+6. 講解點(diǎn)擊類(lèi)名,使用 ctrl+T 實(shí)現(xiàn)該類(lèi)的子類(lèi),即繼承關(guān)系!下面是 Lucene 的大體結(jié)構(gòu)圖:原理是先把文章根據(jù)需求用分詞器拆分,然后建立好每一個(gè)到文章的關(guān)系,這就是索引表,索引表存放的就是關(guān)鍵字到文章的,注意這里的不是直接就持有了對(duì)應(yīng)的文章,而是持有的內(nèi)部對(duì)文章編號(hào)的一個(gè) id。所以索引是關(guān)鍵字到文章 Id 的一個(gè)。當(dāng)用戶時(shí),也用之前的分詞器,把分詞,然后每一個(gè)詞都挨著找索引,把匹配的返回出來(lái)就完畢了。) intdocId=topDocs.scoreDocsi.doc; Document hit

18、tedDocument=searcher.doc(docId); LuceneUtiles.print(hittedDocument); indexReader.close(); (別人的圖片)a) Analysis:分詞器Analysis 包含一些內(nèi)建的分析器,例如按空白字符分詞的 WhitespaceAnalyzer,添加了 stopwrod 過(guò)濾的 StopAnalyzer,最常用的 StandardAnalyzer。b) Documet:文檔就是我們的源數(shù)據(jù)的封裝結(jié)構(gòu),我們需要把源數(shù)據(jù)分成不同的域,放入到 documet 里面,到時(shí)搜索時(shí)也可以指定搜索哪些域( Field)了。c) D

19、irectory : 目錄,這是對(duì)目錄的一個(gè)抽象,這個(gè)目錄可以是文件系統(tǒng)上面的一個(gè) dir(FSDirectory),也可以是內(nèi)存的一塊(RAMDirectory),MmapDirectory 為使用內(nèi)存的索引。放在內(nèi)存的話就會(huì)避免 IO 的操作耗時(shí)了,根據(jù)需要選擇就是了。d) IndexWriter : 索引書(shū)寫(xiě)器,也就是維護(hù)器,對(duì)索引進(jìn)行和刪除操作的類(lèi)e) IndexReader : 索引器,用于指定目錄的索引。f) IndexSearcher : 索引的搜索器,就是把用戶輸入拿到索引列表中搜索的一個(gè)類(lèi)需要注意的是,這個(gè)搜索出來(lái)的就是( TopDocs)索引號(hào),還不是真正的文章。g) Qu

20、ery :語(yǔ)句,我們需要把我們的String 封裝成 Query 才可以交給 Searcher 來(lái)搜索 ,的最小單元是 Term,Lucene 的 Query有很多種,根據(jù)不同的需求選用不同的 Query 就是了.i. TermQuery:如果你想執(zhí)行一個(gè)這樣的:“在 content 域中包含lucene的 document”,那么你可以用 TermQuery:Term t=ii. BooleanQuery:多個(gè) query 的【與或】關(guān)系的如果你想這么:“在 content 域中包含 java 或 perl 的 document”,那么你可以建立兩個(gè) TermQuery 并把它們用 Bool

21、eanQuery 連接起來(lái):TermQuery termQuery1=new Term("content","lucene"); Query query=new TermQuery(t);newTermQuery(newTerm("content","java"); TermQuery termQuery2=newTermQuery(newTerm("content","perl"); BooleanQuery booleanQuery=iii. WildcardQuery

22、: 通配符的如果你想對(duì)某單詞進(jìn)行通配符,你可以用 WildcardQuery,通配符包括?匹配一個(gè)任意字符和*匹配零個(gè)或多個(gè)任意字符,例如你搜索use*,你可能找到useful或者useless:Query query = new WildcardQuery(new Term("content", "use*");iv. PhraseQuery : 在指定的文字距離內(nèi)出現(xiàn)的詞的你可能對(duì)關(guān)系比較感,想查找中和日挨得比較近( 5 個(gè)字的距離內(nèi))的文章,超過(guò)這個(gè)距離的不予考慮,你可以:PhraseQuery query = new PhraseQuery();

23、query.setSlop(5);query.add(new Term("content ", “中”);query.add(new Term(“content”, “日”);newBooleanQuery(); booleanQuery.add(termQuery1, BooleanClause.Occur.SHOULD); booleanQuery.add(termQuery2, BooleanClause.Occur.SHOULD);那么它可能搜到“合作”、“中方和日方”,但是搜不到“中國(guó)某說(shuō)欠扁”。v. PrefixQuery :詞語(yǔ)是以某字符開(kāi)頭的如果你想搜以中開(kāi)

24、頭的詞語(yǔ),你可以用 PrefixQuery:PrefixQuery query = new PrefixQuery(new Term("content ", " 中");vi. FuzzyQuery : 相似的搜索FuzzyQuery 用來(lái)搜索相似的 term,使用 Levenshtein 算法。假設(shè)你想搜索跟wuzza相似的詞語(yǔ),你可以:Query query = new FuzzyQuery(new Term("content", "wuzza");你可能得到fuzzy和wuzzy。vii. TermRange

25、Query : 范圍內(nèi)搜索你也許想搜索時(shí)間域從 20060101 到 20060130 之間的 document,你可以用 TermRangeQuery:TermRangeQuery query2 = TermRangeQuery.newStringRange("time", "20060101", "20060130", true, true);最后的 true 表示用閉合區(qū)間。viii.h) TopDocs :結(jié)果集,就是 searcher 搜索的結(jié)果,里面就是一些 ScoreDoc,這個(gè)對(duì)象的 doc 成員就是這個(gè) Id 了!要

26、想得到文章,那么就得需要用這個(gè) Id 去取文章了,searcher 提供了用 id 得到 document 的方法,于是就取到了數(shù)據(jù)了i)7.使用多個(gè) Directory因?yàn)槲覀冎懒?FSDirectory 是從文件系統(tǒng)的目錄中數(shù)據(jù),我們總不可能每次都從文件中一次索引吧,所以我們的做法應(yīng)該是程序啟動(dòng)時(shí)就把所以載入到內(nèi)存,時(shí)再回寫(xiě),如下面的示意圖:(也是別人的圖片)使用內(nèi)存的目錄:RAMDirectory這樣可以加快速度/* 測(cè)試使用RAMDirectroy,也就是把生成的索引寫(xiě)到內(nèi)存而不是磁盤(pán). * 運(yùn)行這個(gè)方法, 不報(bào)錯(cuò)就代表了。 *我們是把索引文件寫(xiě)道文件系統(tǒng)的,這里就是寫(xiě)道 RAM 中

27、,以后也 * 可以在這個(gè)目錄,快速! *throws IOException*/Test publicvoid testWriteInToRam() throwsIOException Directory directory=從文件系統(tǒng)的目錄載入到 ram 中,然后進(jìn)行操作,最后保存回去下面是實(shí)例代碼:/*newRAMDirectory(); IndexWriterConfig config=newIndexWriterConfig(Version.LUCENE_45, analyzer); IndexWriter indexWriter=newIndexWriter(directory, c

28、onfig); indexWriter.addDocument(LuceneUtiles.getDocument(filePath); indexWriter.close(); * 從磁盤(pán)的索引文件中放入到 RAM 目錄,* 然后進(jìn)行一系列的其他操作。* 退出時(shí)再把 RAM 的寫(xiě)回文件系統(tǒng)。*throwsIOException*/TestpublicvoidtestLoadIntoRamAndWriteBacktoFS()throwsIOException /1.啟動(dòng)時(shí)載入Directory fsDir=FSDirectory.open(newFile(indexPath); RAMDirec

29、tory ramDir=newRAMDirectory(fsDir,newIOContext();/中途操作內(nèi)存中的數(shù)據(jù)IndexWriterConfig ramIndexWriterConfig=newIndexWriterConfig(Version.LUCENE_45, analyzer); IndexWriter ramIndexWriter=newIndexWriter(ramDir, ramIndexWriterConfig);/添加一個(gè)文件,這好像沒(méi)有寫(xiě)進(jìn)去!/不是沒(méi)寫(xiě)進(jìn)去,而是這個(gè)方法沒(méi)有執(zhí)行!因?yàn)?test 方法一定要加Test 注解!ramIndexWriter.addDo

30、cument( LuceneUtiles.getDocument(filePath);ramIndexWriter.close();/要先關(guān)閉,因?yàn)檫€有緩存。/2.時(shí)保存寫(xiě)回,因?yàn)槟J(rèn)是 CREATE_OR_APPEND/所以這里就會(huì)把AABBCC 讀出來(lái)之后,加上 DD/那么寫(xiě)回去的數(shù)據(jù)時(shí) AABBCCDD,但是已經(jīng)本地有了,/所以是 append 的方式,于是最后的結(jié)果是/AABBCCAABBCCDD,就是重復(fù)的了。可以 search 同一個(gè)關(guān)鍵字,/看結(jié)果數(shù)量就知道了/會(huì) 1 條變 3 條,3 條變 7 條,這種*2+1 的形式/我們可以每次都重寫(xiě),就能解決了合并索引因?yàn)槊刻砑右粋€(gè)文檔的

31、索引,都會(huì)建立多個(gè)小的文件存放索引,所以文檔多了之后,IO 操作就很費(fèi)時(shí)間了,于是我們需要合并小文件,每一個(gè)小文件就是 segment。合并代碼如下,需要注意的是:IndexWriterConfig fsIndexWriterConfig=newIndexWriterConfig(Version.LUCENE_45, analyzer);/設(shè)置每次重寫(xiě)fsIndexWriterConfig.setOpenMode(OpenMode.CREATE); IndexWriter fsIndexWriter=newIndexWriter(fsDir, fsIndexWriterConfig); fsI

32、ndexWriter.addIndexes(ramDir); fsIndexWriter.close(); a) 我們不能直接把索引庫(kù)打開(kāi),用 Creat_OR_Append 的方式強(qiáng)制寫(xiě)回他會(huì)出現(xiàn)疊加的問(wèn)題b) 要每次都用 Create 的方式寫(xiě)回但是不能再寫(xiě)回的目錄,因?yàn)橥粋€(gè)目錄不支持又讀又寫(xiě),必須指定其他的目錄c) 指定其他目錄存放 Merge 的索引,在寫(xiě)回之前,應(yīng)該把之前的索引添加到 IndexWriter 中,這樣才把會(huì)有數(shù)據(jù)/* 索引庫(kù)文件優(yōu)化,貌似沒(méi)有提供保存優(yōu)化的接口 * 多半內(nèi)部封裝好的,外界不用管。只有一個(gè)強(qiáng)制合并的接口。 * 這就是用于合并。 *throws IOEx

33、ception*/Test publicvoidtestYouHua()throwsIOException Directory fsDirectory_Merged=FSDirectory.open(newFile(indexPathMerged); Directory fsDirectory=FSDirectory.open(newFile(indexPath); IndexWriterConfig indexWriterConfig=newIndexWriterConfig(Version.LUCENE_45, analyzer);indexWriterConfig.setOpenMode

34、(OpenMode.CREATE); IndexWriter indexWriter=newIndexWriter(fsDirectory_Merged, indexWriterConfig);/forceMerge(1)可以把所以的段合并成 1 個(gè),但是每次都會(huì)增加一份,/就是像拷貝了一份加入一樣/難道是該指定 OpenMode.CREATE,如果指定了 CREATE,/但是呢 IndexWriter 里面沒(méi)有添加 doc 索引(即 addDoc 等方法),/所以寫(xiě)進(jìn)去就編程空索引庫(kù)了,于是需要先讀出來(lái)再寫(xiě)回/于是還應(yīng)該把索引加到 writer 里面/把加入進(jìn)去,然后再用每次都 create

35、 的辦法保持新增/注意不能添加到,所以還得新建一個(gè)庫(kù)才可以,這樣就疊加了indexWriter.addIndexes(fsDirectory); indexWmit();indexWriter.forceMerge(1); indexWriter.close(); 分詞器(Analyzer)在前面的概念介紹中我們已經(jīng)知道了分析器的作用,就是把句子按照語(yǔ)義切分成一個(gè)個(gè)詞語(yǔ)。英文切分已經(jīng)有了很成分析器: StandardAnalyzer,很多情況下 StandardAnalyzer 是個(gè)不錯(cuò)的選擇。甚至你會(huì)發(fā)現(xiàn) StandardAnalyzer 也能對(duì)中文進(jìn)行分詞。但是我們的焦點(diǎn)是中文分詞,Sta

36、ndardAnalyzer 能支持中文分詞嗎?實(shí)踐證明是可以的,但是效果并不好,搜索“如果” 會(huì)把“牛奶不如果汁好喝”也搜索出來(lái),而且索引文件很大。那么我們手頭上還有什么分析器可以使用呢?core 里面沒(méi)有,我們可以在 sandbox 里面找到兩個(gè):Analyzer 和 CJKAnalyzer。但是它們同樣都有分詞的問(wèn)題。相比之下用 StandardAnalyzer 和Analyzer 建立索引時(shí)間差不多,索引文件大小也差不多,CJKAnalyzer 表現(xiàn)會(huì)差些,索引文件大且耗時(shí)比較長(zhǎng)。要解決問(wèn)題,首先分析一下這三個(gè)分析器的分詞方式。StandardAnalyzer和Analyzer 都是把句

37、子按單個(gè)字切分,也就是說(shuō) “牛奶不如果汁好喝”會(huì)被它們切分成“牛 奶 不 如 果 汁 好 喝”;而 CJKAnalyzer則會(huì)切分成“牛奶 奶不 不如 如果 果汁 汁好好喝”。這也就解釋了為什么搜索“果汁”都能匹配這個(gè)句子。以上分詞的缺點(diǎn)至少有兩個(gè):匹配確和索引文件大。我們的目標(biāo)是將上面的句子分解成 “牛奶 不如 果汁好喝”。這里的關(guān)鍵就是語(yǔ)義識(shí)別,我們?nèi)绾巫R(shí)別“牛奶”是一個(gè)詞而“奶不”不是詞語(yǔ)?我們很自然會(huì)想到基于詞庫(kù)的分詞法,也就是我們先得到一個(gè)詞庫(kù),里面列舉了大部分詞語(yǔ),我們把句子按某種方式切分,當(dāng)?shù)玫降脑~語(yǔ)與詞庫(kù)中的項(xiàng)匹配時(shí),我們就認(rèn)為這種切分是正確的。這樣切詞的過(guò)程就轉(zhuǎn)變成匹配的過(guò)程

38、,而匹配的方式最簡(jiǎn)單的有正向最大匹配和逆向最大匹配兩種,說(shuō)白了就是一個(gè)從句子開(kāi)頭向后進(jìn)行匹配,一個(gè)從句子末尾向前進(jìn)行匹配?;谠~庫(kù)的分詞詞庫(kù)非常重要,詞庫(kù)的容量直接影響搜索結(jié)果,在相同詞庫(kù)的前提下,據(jù)說(shuō)逆向最大匹配優(yōu)于正向最大匹配。當(dāng)然還有別的分詞方法,這本身就是一個(gè)學(xué)科,我這里也沒(méi)有深入研究。回到具體應(yīng)用,我們的目標(biāo)是能找到成、現(xiàn)成的分詞工具,避免重新發(fā)明車(chē)輪。經(jīng)過(guò)網(wǎng)上搜索,用的比較多的是的 ICTCLAS 和一個(gè)不開(kāi)放源碼但是的 JE-Analysis。ICTCLAS 有個(gè)問(wèn)題是它是一個(gè)動(dòng)態(tài)庫(kù), java 調(diào)用需要本地方法調(diào)用,不方便也有安全隱患,而且口碑也確實(shí)不大好。JE-Analysi

39、s 效果還不錯(cuò),當(dāng)然也會(huì)有分詞的地方,相比比較方便放心。下面就是分詞器的例子:/* <pre> * 測(cè)試分詞器的,分詞器分出來(lái)的關(guān)鍵字我們叫做 Token * 分詞器一般需要完成的工作是: * 1.詞組拆分 * 2.去掉停用詞 * 3.大小寫(xiě)轉(zhuǎn)換 * 4.詞根還原 * * 對(duì)于中文分詞,通常有 3 種:?jiǎn)卧~分詞,二分法,詞典分詞。 * 單詞分詞:就分成一個(gè)一個(gè)的單個(gè)字,比如linkStandardAnalyzer, * 如分成 我-們-是-* 二分法分詞:按 2 個(gè)字分詞,即我們-們是-是中-中國(guó)-國(guó)人,實(shí)現(xiàn)是是 * linkCJKAnalyzer * 詞典分詞:按照某種算法構(gòu)造詞

40、,然后把詞拿到詞典里面找,如果是詞,就算對(duì)了。 * 這是目前的好用的,可以分詞成 我們-, * 好用的有【極易分詞:MMAnalyzer】,還有就是【庖丁分詞】目前沒(méi)有找到適用于 4.5 的。 * 還有一個(gè)牛的,是院的。能分出帽子和服裝。這些需要外界提供,需要jar 包 * </pre> * *authorLiFeng */publicclassAnalyzerTest String enString="it must be made available under this Agreement,”+”formore information : infor.doc&quo

41、t;String zhString="你好,我是,名字是李鋒。"/這個(gè)分詞器用于英文的,沒(méi)有形態(tài)還原/如果拿去分中文的話,每一個(gè)字都被拆開(kāi)了,測(cè)試下就曉得了Analyzer enAnalyzer=newStandardAnalyzer(Version.LUCENE_45);/可以按點(diǎn),沒(méi)有形態(tài)還原/對(duì)于中文的話,他也只按標(biāo)點(diǎn)分:你好 我是名字是李鋒這 3 個(gè) tokenAnalyzer simpleAnalyzer=newSimpleAnalyzer(Version.LUCENE_45);/分中文就是二分法/分英文就是:?jiǎn)卧~就完了Analyzer cjkAnalyzer=n

42、ewCJKAnalyzer(Version.LUCENE_45);/lucene4.5 使用je-analysis-1.5.3.jar 會(huì),因?yàn)楹枚喽几牧薃nalyzer jeAnalyzer=newMMAnalyzer();/詞庫(kù)分詞,比如極易String testString=enString; Analyzer testAnalyzer=jeAnalyzer;/* 得到分詞器拆分出來(lái)的關(guān)鍵字(Token) * *throwsIOException*/TestpublicvoidtestGetTokens()throwsIOException /得到分出來(lái)的詞流/fileName 就是我們

43、當(dāng)時(shí)創(chuàng)建 document 時(shí)一樣的意思/我們這里是要得到分出的詞,跟他要?dú)w屬哪個(gè) filed 無(wú)關(guān),所以不用管/查看 enAnalyzer 的 tokenStream 的幫助,他叫們參考:/See the Analysis package documentation for some examples/demonstrating this./于是打開(kāi)對(duì)于的文檔如下:/docs/core/org/apache/lucene/analysis/package-summary.html#package_description/這里面會(huì)有例子的!/下面是文檔的例子/分詞器把文本分詞 token 流T

44、okenStream tokenStream=testAnalyzer.tokenStream("myfield",newStringReader(testString); OffsetAttribute offsetAtt=tokenStream.addAttribute(OffsetAttribute.class);try/Resets this stream to the beginning. (Required)tokenStream.reset();while(tokenStream.incrementToken() /這里傳入 true 就可以看到更詳細(xì)的信息,

45、調(diào)試用很好/打印 token 的信息System.out.println("token:"+tokenStream.refleString(false);/可以去除 token 存放的開(kāi)始和結(jié)束/System.out.println("token start offset: "/+ offsetAtt.startOffset();/System.out.println(" token end offset: "/+ offsetAtt.endOffset(); tokenStream.end(); finally/Release re

46、sources associated with this stream.tokenStream.close(); 高亮器 highlighter高亮器幫我們做兩件事,第一件就是搜索結(jié)果的摘要,第二件事就是整體內(nèi)容的關(guān)鍵字高亮。高亮的原理就是在關(guān)鍵字周?chē)由?html就是了。String indexPath="D:WorkspacesForAllLuceneLucene-00010-HelloWorldlf_index " Analyzer analyzer=newStandardAnalyzer(Version.LUCENE_45); Test publicvoidtest

47、Hightlight()throwsIOException, InvalidTokenOffsetsException /fileContent 字段的reproduce 關(guān)鍵字/這里的 filed 指定就是用于找到符合的document/在高亮器初始化的時(shí)候 Scorer 類(lèi)也用到了這個(gè) query/其實(shí)過(guò)程就是:/1.先把某個(gè)域出現(xiàn)關(guān)鍵字的 doc 全部找出來(lái)/2.再用高亮器,在找到的文章中,/把指定域的內(nèi)容提取一部分有關(guān)鍵字的文本,加上高亮就完畢了Query query=newTermQuery(newTerm("fileContent","reproduc

48、e");/高亮器的初始化準(zhǔn)備Highlighter highlighter=null; Formatter formatter=newSimpleHTMLFormatter("<font color='red'>","</font>"); Scorer fragmentScorer=newQueryScorer(query); highlighter=newHighlighter(formatter, fragmentScorer);/摘要只取 50 個(gè)字符Fragmenter fragmenter=ne

49、wSimpleFragmenter(50); highlighter.setTextFragmenter(fragmenter); IndexReader indexReader=DirectoryReader.open( FSDirectory.open(newFile(indexPath); IndexSearcher searcher=newIndexSearcher(indexReader); TopDocs topDocs=searcher.search(query,null,1000); System.out.println("找到【"+topDocs.tota

50、lHits+"】個(gè):");for(inti=0; i<topDocs.scoreDocs.length; i+) intdocId=topDocs.scoreDocsi.doc; Document document=searcher.doc(docId);/用高亮器返回摘要/參數(shù) 1 就是用指定的分詞器,/參數(shù) 2 目前不知道咋用/參數(shù) 3 就是我們需要處理哪一段文本的數(shù)據(jù),把這段文件實(shí)現(xiàn)高亮并返回摘要/返回的就是高亮之后的摘要了,沒(méi)有就是 nullString ret=highlighter.getBestFragment( analyzer,"anySt

51、ring",document.get("fileContent") );/String ret = highlighter.getBestFragment(/analyzer, "anyString",document.get("noThisFiled") );if(ret!=null) System.out.println(ret); else String defaultString=document.get("fileContent有兩種大類(lèi):第一種是使用字符串,有語(yǔ)法的。就像直接輸入 sql 語(yǔ)句一樣。第二

52、種就是對(duì)象,即用 query 類(lèi)來(lái)組復(fù)雜。這個(gè)在概述的時(shí)候已經(jīng)講過(guò)了。對(duì)象:常用的有:TermQuery,BooleanQuery,WildcardQuery,PhraseQuery,PrefixQuery,TermRangeQuery 等。對(duì)象對(duì)應(yīng)的語(yǔ)法可以直接打印出來(lái) system.out.println(query);TermQuery:"); System.out.println( "不高亮:"+defaultString); 如果你想執(zhí)行一個(gè)這樣的:“在 content 域中包含lucene的 document”,那么你可以用 TermQuery:Term t = new Term("content", " lucene");Query query = new TermQuery(t);BooleanQuery多個(gè) query 的【與或】關(guān)系的如果你想這么:“在 content 域中包含 java 或 pe

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論