天天看點

第二章 索引

<a href="http://s3.51cto.com/wyfs02/M02/3F/96/wKiom1PLSmbAmtyJAAEaooBMvy8979.jpg" target="_blank"></a>

1.建立Directory

<code>package</code> <code>com.mzsx.write;</code>

<code> </code> 

<code>import</code> <code>java.io.File;</code>

<code>import</code> <code>java.io.IOException;</code>

<code>import</code> <code>org.apache.lucene.store.Directory;</code>

<code>import</code> <code>org.apache.lucene.store.FSDirectory;</code>

<code>public</code> <code>class</code> <code>DirectoryConext {</code>

<code>         </code><code>privatestatic Directory directory=</code><code>null</code><code>;</code>

<code>         </code><code>privateDirectoryConext(){}</code>

<code>         </code><code>publicstatic Directory getDirectory(String fileName){</code>

<code>                   </code><code>if</code><code>(directory==</code><code>null</code><code>) {</code>

<code>                            </code><code>synchronized</code><code>(DirectoryConext.</code><code>class</code><code>){</code>

<code>                                     </code><code>if</code><code>(directory==</code><code>null</code><code>) {</code>

<code>                                               </code><code>try</code><code>{</code>

<code>                                                        </code><code>directory=FSDirectory.open(</code><code>new</code> <code>File(fileName));</code>

<code>                                               </code><code>}</code><code>catch</code> <code>(IOException e) {</code>

<code>                                                        </code><code>e.printStackTrace();</code>

<code>                                               </code><code>}</code>

<code>                                     </code><code>}</code>

<code>                            </code><code>}</code>

<code>                   </code><code>}</code>

<code>                   </code><code>returndirectory;</code>

<code>         </code><code>}</code>

<code>}</code>

2. 建立Writer

<code>import</code> <code>org.apache.lucene.analysis.Analyzer;</code>

<code>import</code> <code>org.apache.lucene.index.CorruptIndexException;</code>

<code>import</code> <code>org.apache.lucene.index.IndexWriter;</code>

<code>import</code> <code>org.apache.lucene.index.IndexWriterConfig;</code>

<code>importorg.apache.lucene.store.LockObtainFailedException;</code>

<code>import</code> <code>org.apache.lucene.util.Version;</code>

<code>public</code> <code>class</code> <code>IndexWriterContext {</code>

<code>         </code><code>privatestatic IndexWriter indexWrite=</code><code>null</code><code>;</code>

<code>         </code><code>privatestatic Analyzer analyzer=</code><code>null</code><code>;</code>

<code>         </code><code>privateIndexWriterContext(){}</code>

<code>         </code><code>publicstatic IndexWriter getIndexWrite(String fileName,Analyzer a){</code>

<code>                   </code><code>try</code><code>{</code>

<code>                            </code><code>if</code><code>(indexWrite==</code><code>null</code><code>) {</code>

<code>                                     </code><code>directory=DirectoryConext.getDirectory(fileName);</code>

<code>                                     </code><code>synchronized</code><code>(IndexWriterContext.</code><code>class</code><code>){</code>

<code>                                               </code><code>if</code><code>(indexWrite==</code><code>null</code><code>) {</code>

<code>                                                        </code><code>indexWrite=newIndexWriter(directory,</code><code>new</code> <code>IndexWriterConfig(Version.LUCENE_35,a));</code>

<code>                                                        </code><code>//indexWrite.commit();</code>

<code>                   </code><code>}</code><code>catch</code> <code>(CorruptIndexException e) {</code>

<code>                            </code><code>e.printStackTrace();</code>

<code>                   </code><code>}</code><code>catch</code> <code>(LockObtainFailedException e) {</code>

<code>                   </code><code>}</code><code>catch</code> <code>(IOException e) {</code>

<code>                   </code> 

<code>                   </code><code>returnindexWrite;</code>

<code>         </code><code>publicstatic IndexWriter getIndexWrite(Directory dir,Analyzer a){</code>

<code>                                     </code><code>directory=dir;</code>

3. 建立文檔并且添加索引

<code>         </code><code>// 建立索引</code>

<code>         </code><code>publicvoid createdIndex(String fName) {</code>

<code>                            </code><code>indexWriter.deleteAll();</code>

<code>                            </code><code>Filefile = </code><code>new</code> <code>File(fName);</code>

<code>                            </code><code>if</code><code>(!file.isDirectory()) {</code>

<code>                                     </code><code>try</code><code>{</code>

<code>                                               </code><code>thrownew Exception(</code><code>"您傳入的不是一個目錄路徑。。。"</code><code>);</code>

<code>                                     </code><code>}</code><code>catch</code> <code>(Exception e) {</code>

<code>                                               </code><code>e.printStackTrace();</code>

<code>                            </code><code>for</code><code>(File f : file.listFiles()) {</code>

<code>                                     </code><code>Document doc =getDocument(f);</code>

<code>                                     </code><code>indexWriter.addDocument(doc);</code>

<code>                            </code><code>indexWriter.commit();</code>

<code>                   </code><code>}</code><code>catch</code> <code>(Exception e) {</code>

<code>// 周遊檔案生産document</code>

<code>         </code><code>protectedDocument getDocument(File f) </code><code>throws</code> <code>Exception {</code>

<code>                   </code><code>//System.out.println(FileUtils.readFileToString(f));</code>

<code>                   </code><code>Documentdoc = </code><code>new</code> <code>Document();</code>

<code>                   </code><code>doc.add(newField(</code><code>"id"</code><code>, (</code><code>""</code> <code>+ (id++)), Field.Store.YES,</code>

<code>                                     </code><code>Field.Index.NOT_ANALYZED));</code>

<code>                   </code><code>doc.add(newField(</code><code>"contents"</code><code>, FileUtils.readFileToString(f),</code>

<code>                                     </code><code>Field.Store.YES,Field.Index.ANALYZED_NO_NORMS));</code>

<code>                   </code><code>doc.add(newField(</code><code>"filename"</code><code>, f.getName(), Field.Store.YES,</code>

<code>                                     </code><code>Field.Index.ANALYZED));</code>

<code>                   </code><code>doc.add(newField(</code><code>"fullpath"</code><code>, f.getCanonicalPath(), Field.Store.YES,</code>

<code>                   </code><code>doc.add(newNumericField(</code><code>"size"</code><code>, Field.Store.YES,</code><code>true</code><code>).setLongValue(f.length()));</code>

<code>                   </code><code>doc.add(newNumericField(</code><code>"date"</code><code>, Field.Store.YES,</code><code>true</code><code>).setLongValue(f.lastModified()));</code>

<code>                   </code><code>returndoc;</code>

4. 查詢索引的基本資訊

<code>// 查詢檔案數量</code>

<code>         </code><code>publicvoid queryNum() {</code>

<code>                            </code><code>IndexReaderindexReader=IndexReader.open(directory);</code>

<code>                            </code><code>IndexSearchersearcher = </code><code>new</code> <code>IndexSearcher(indexReader);</code>

<code>                            </code><code>System.out.println(</code><code>"searcher.maxDoc="</code><code>+ searcher.maxDoc());</code>

<code>                            </code><code>System.out.println(</code><code>"indexReader.maxDoc="</code><code>+indexReader.maxDoc());</code>

<code>                            </code><code>System.out.println(</code><code>"indexReader.numDocs="</code><code>+ indexReader.numDocs());</code>

<code>                            </code><code>System.out.println(</code><code>"indexReader.numDeletedDocs="</code>

<code>                                               </code><code>+indexReader.numDeletedDocs());</code>

<code>                            </code><code>searcher.close();</code>

5. 删除和更新索引

索引的删除主要包含了IndexWriter和IndexReader删除。但是IndexWriter是2.9版本周出現的其本質還是調用IndexReader進行删除操作。

<code>         </code><code>// 更新索引</code>

<code>         </code><code>publicvoid update(String field, String name) {</code>

<code>                   </code><code>Documentdocu = </code><code>new</code> <code>Document();</code>

<code>                   </code><code>docu.add(newField(</code><code>"id"</code><code>, </code><code>"2222"</code><code>, Field.Store.YES,</code>

<code>                   </code><code>docu.add(newField(</code><code>"contents"</code><code>, </code><code>"修改後的檔案内容"</code><code>, Field.Store.NO,</code>

<code>                                     </code><code>Field.Index.ANALYZED_NO_NORMS));</code>

<code>                   </code><code>docu.add(newField(</code><code>"filename"</code><code>, </code><code>"這是修改後的檔案名"</code><code>, Field.Store.YES,</code>

<code>                   </code><code>docu.add(newField(</code><code>"fullpath"</code><code>, </code><code>"這是修改後的檔案後的檔案路徑"</code><code>, Field.Store.YES,</code>

<code>                            </code><code>indexWriter.updateDocument(newTerm(field, name), docu,analyzer);</code>

<code>//删除指定ID</code>

<code>         </code><code>publicvoid deleteByIndexWriter(String field, String value){</code>

<code>                            </code><code>indexWriter.deleteDocuments(newTerm(field,value));</code>

<code>                            </code><code>//indexWriter.close();</code>

<code>         </code><code>publicvoid deleteByIndexReader(String field, String value){</code>

<code>                            </code><code>indexReader.deleteDocuments(newTerm(field,value));</code>

<code>                            </code><code>//必須close()</code>

<code>                            </code><code>indexReader.close();</code>

<code>//删除恢複</code>

<code>         </code><code>publicvoid unDelete(){</code>

<code>                            </code><code>indexReader.undeleteAll();</code>

1. 域索引選項

使用Field.Index.*來進行操作

Index.ANALYZED:進行分詞和索引,适用于标題、内容等

Index.NOT_ANALYZED:進行索引,但是不進行分詞,如果***号,姓名,ID等,适用于精确搜尋

Index.ANALYZED_NOT_NORMS:進行分詞但是不存儲norms資訊,這個norms中包括了建立索引的時間和權值等資訊

Index.NOT_ANALYZED_NOT_NORMS:即不進行分詞也不存儲norms資訊

Index.NO:不進行索引

注:沒有norms意味着索引階段禁用了文檔boost和域的boost及長度标準化。好處在于節省記憶體,不用在搜尋階段為索引中的每篇文檔的每個域都占用一個位元組來儲存norms資訊了。但是對norms資訊的禁用是必須全部域都禁用的,一旦有一個域不禁用,則其他禁用的域也會存放預設的norms值。因為為了加快norms的搜尋速度,Lucene是根據文檔号乘以每篇文檔的norms資訊所占用的大小來計算偏移量的,中間少一篇文檔,偏移量将無法計算。也即norms資訊要麼都儲存,要麼都不儲存。

2. 域存儲選項

Field.Store.*

YES:将會存儲域值,原始字元串的值會儲存在索引,以此可以進行相應的恢複操作,對于主鍵,标題可以是這種方式存儲

NO:不會存儲域值,通常與Index.ANAYLIZED合起來使用,索引一些如文章正文等不需要恢複的文檔

3.最佳實踐

NOT_ANALYZED_NOT_NORMS

YES

辨別符(主鍵、檔案名),電話号碼,***号,姓名,日期

ANAYLZED

文檔标題和摘要

NO

文檔正文

文檔類型,資料庫主鍵(不進行索引)

NOT_ANALYZED

隐藏關鍵字

1. 對數字和日期進行索引

(1)、對數字進行索引可以使用分詞器進行不同的索引

     ·WhitespaceAnalyzer和StandardAnalyzer會索引數字

     ·SimpleAnalyzer和StopAnalyzer不會索引數字

(2)、在3.0之後添加了數字域來完成數字和日期的索引

<code>doc.add(</code><code>new</code> <code>NumericField(</code><code>"size"</code><code>, Field.Store.YES, </code><code>true</code><code>).setLongValue(f.length()));</code>

<code>doc.add(</code><code>new</code> <code>NumericField(</code><code>"date"</code><code>, Field.Store.YES,</code><code>true</code><code>).setLongValue(f.lastModified()));</code>

2.常用的Directory

       FSDDirectory.open會根據目前的運作環境打開一個最合理的基于File的Directory

new RAMDirectory()會從記憶體中打開directory,好處是速度快,缺點是無法持久化

3. IndexReader和IndexWriter的生命周期

對于IndexReader而言,反複使用Index.open打開會有很大的開銷,是以一般在整個程式的生命周期中隻會打開一個IndexReader,通過這個IndexReader來建立不同的IndexSearcher,如果使用單例模式,可能出現的問題有:

(1)、當使用Writer修改了索引之後不會更新資訊,是以需要使用IndexReader.openIfChange方法操作

如果IndexWriter在建立完成之後,沒有關閉,需要進行commit操作之後才能送出

本文轉自 夢朝思夕 51CTO部落格,原文連結:http://blog.51cto.com/qiangmzsx/1440487