【Lucene4.8教程之二】索引

來源:互聯網
上載者:User

標籤:lan   互調   which   esc   play   apach   繼承   一個   arch   


一、基礎內容

0、官方文檔說明

(1)org.apache.lucene.index provides two primary classes: IndexWriter, which creates and adds documents to indices; and IndexReader, which accesses the data in the index.

(2)涉及的兩個主要包有:

org.apache.lucene.index:Code to maintain and access indices.
org.apache.lucene.document:Thelogical representation of a Document for indexing and searching.

1、建立一個索引時,涉及的重要類有下面幾個:

(1)IndexWriter:索引過程中的核心組件,用於建立新索引或者開啟已有索引。以及向索引中加入、刪除、更新被索引文檔的資訊。

(2)Document:代表一些域(field)的集合。

(3)Field及其子類:一個域,如文檔建立時間,作者。內容等。

(4)Analyzer:分析器。

(5)Directory:可用於描寫敘述Lucene索引的存放位置。

2、索引文檔的基本過程例如以下:

(1)建立索引庫IndexWriter
(2)依據檔案建立文檔Document
(3)向索引庫中寫入文檔內容

基本程式例如以下:

package org.jediael.search.index;import java.io.File;import java.io.FileReader;import java.io.IOException;import org.apache.lucene.analysis.standard.StandardAnalyzer;import org.apache.lucene.document.Document;import org.apache.lucene.document.Field;import org.apache.lucene.document.LongField;import org.apache.lucene.document.StringField;import org.apache.lucene.document.TextField;import org.apache.lucene.index.IndexWriter;import org.apache.lucene.index.IndexWriterConfig;import org.apache.lucene.store.Directory;import org.apache.lucene.store.FSDirectory;import org.apache.lucene.util.Version;import org.jediael.util.LoadProperties;// 1、建立索引庫IndexWriter// 2、依據檔案建立文檔Document// 3、向索引庫中寫入文檔內容public class IndexFiles {private IndexWriter writer = null;public void indexAllFileinDirectory(String indexPath, String docsPath)throws IOException {// 擷取放置待索引檔案的位置。若傳入參數為空白,則讀取search.properties中設定的預設值。

if (docsPath == null) {docsPath = LoadProperties.getProperties("docsDir");}final File docDir = new File(docsPath);if (!docDir.exists() || !docDir.canRead()) {System.out.println("Document directory '"+ docDir.getAbsolutePath()+ "' does not exist or is not readable, please check the path");System.exit(1);}// 擷取放置索引檔案的位置,若傳入參數為空白。則讀取search.properties中設定的預設值。if (indexPath == null) {indexPath = LoadProperties.getProperties("indexDir");}final File indexDir = new File(indexPath);if (!indexDir.exists() || !indexDir.canRead()) {System.out.println("Document directory '"+ indexDir.getAbsolutePath()+ "' does not exist or is not readable, please check the path");System.exit(1);}try {// 1、建立索引庫IndexWriterif(writer == null){initialIndexWriter(indexDir);}index(writer, docDir);} catch (IOException e) {e.printStackTrace();} finally{writer.close();}}//使用了最簡單的單例模式,用於返回一個唯一的IndexWirter。注意此處非安全執行緒,須要進一步最佳化。private void initialIndexWriter(File indexDir) throws IOException {Directory returnIndexDir = FSDirectory.open(indexDir);IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_48,new StandardAnalyzer(Version.LUCENE_48));writer = new IndexWriter(returnIndexDir, iwc);}private void index(IndexWriter writer, File filetoIndex) throws IOException {if (filetoIndex.isDirectory()) {String[] files = filetoIndex.list();if (files != null) {for (int i = 0; i < files.length; i++) {index(writer, new File(filetoIndex, files[i]));}}} else {// 2、依據檔案建立文檔Document,考慮一下是否能不用每次建立Document對象Document doc = new Document();Field pathField = new StringField("path", filetoIndex.getPath(),Field.Store.YES);doc.add(pathField);doc.add(new LongField("modified", filetoIndex.lastModified(),Field.Store.YES));doc.add(new StringField("title",filetoIndex.getName(),Field.Store.YES));doc.add(new TextField("contents", new FileReader(filetoIndex)));//System.out.println("Indexing " + filetoIndex.getName());// 3、向索引庫中寫入文檔內容writer.addDocument(doc);}}}


一些說明:

(1)使用了最簡單的單例模式。用於返回一個唯一的IndexWirter,注意此處非安全執行緒,須要進一步最佳化。

(2)注意IndexWriter,IndexReader等均須要耗費較大的資源用於建立執行個體。因此如非必要,使用單例模式建立一個執行個體後。


3、索引、Document、Filed之間的關係

簡而言之,多個Filed組成一個Document,多個Document組成一個索引。

它們之間通過下面方法相互調用:

Document doc = new Document();Field pathField = new StringField("path", filetoIndex.getPath(),Field.Store.YES);doc.add(pathField);writer.addDocument(doc);


二、關於Field

(一)建立一個域(field)的基本方法

1、在Lucene4.x前,使用下面方式建立一個Field:
Field field = new Field("filename", f.getName(),  Field.Store.YES, Field.Index.NOT_ANALYZED);Field field = new Field("contents", new FileReader(f));Field field = new Field("fullpath", f.getCanonicalPath(), Field.Store.YES, Field.Index.NOT_ANALYZED)
Filed的四個參數分別代表:域的名稱域的值是否儲存是否分析。對於檔案名稱,url。檔案路徑等內容。不須要對其進行分析。


2、在Lucene4後。定義了大量的Field的實作類別型。依據須要,直接使用當中一個,不再使用笼統的Field來直接建立域。Direct Known Subclasses:

BinaryDocValuesField, DoubleField, FloatField,IntField, LongField, NumericDocValuesField, SortedDocValuesField, SortedSetDocValuesField, StoredField, StringField,TextField
比如,對於上述三個Filed,可對應的改為:
<pre name="code" class="java">Field field = new StringField("path", filetoIndex.getPath(),Field.Store.YES);Field field = new LongField("modified", filetoIndex.lastModified(),Field.Store.NO);Field field = new TextField("contents", new FileReader(filetoIndex));
在4.x以後,StringField即為NOT_ANALYZED的(即不正確域的內容進行切割分析),而textField是ANALYZED的,因此,建立Field對象時。無需再指定此屬性。見http://stackoverflow.com/questions/19042587/how-to-prevent-a-field-from-not-analyzing-in-lucene即每個Field的子類均具有預設的是否INDEXED與ANALYZED屬性,不再須要顯式指定。官方文檔:StringField: A field that is indexed but not tokenized: the entire String value is indexed as a single token. For example this might be used for a ‘country‘ field or an ‘id‘ field, or any field that you intend to use for sorting or access through the field cacheTextField: A field that is indexed and tokenized,without term vectors. For example this would be used on a ‘body‘ field, that contains the bulk of a document‘s text.(二)有關於Field的一些選項1、Field.Store.Yes/No在建立一個Field的時候,須要傳入一個參數,用於指定內容是否須要儲存到索引中。

這些被儲存的內容能夠在搜尋結果中返回,呈現給使用者。二者最直觀的差異在於:使用document.get("fileName")時,能否夠返回內容。比方,一個檔案的標題通常都是Field.Store.Yes,由於其內容一般須要呈現給使用者。檔案的作者、摘要等資訊也一樣。但一個檔案的內容可能就不是必需儲存了。一方面是檔案內容太大。還有一方面是不是必需在索引中儲存其資訊,由於能夠引導使用者進入原有檔案就可以。2、加權能夠對Filed及Document進行加權。注意加權是影響返回結果順序的一個因素,但也不過一個因素,它和其他因素一起構成了Lucene的排序演算法。(三)對富文本(非純文字)的索引上述的對本文的索引語句:

Field field = new TextField("contents", new FileReader(filetoIndex));
僅僅對純文字有效。

對於word,excel,pdf等富文本。FileReader讀取到的內容僅僅是一些亂碼。並不能形成有效索引。

若須要對此類文本進行索引,須要使用Tika等工具先將其本文內容提取出來,然後再進行索引。
http://stackoverflow.com/questions/16640292/lucene-4-2-0-index-pdf
Lucene doesn‘t handle files at all, really. That demo handles plain text files, but core Lucene doesn‘t. FileStreamReader is a Java standard stream reader, and for your purposes, it will only handle plain text. This works on the Unix philosophy. Lucene indexes content. Tika extracts content from rich documents. I‘ve added links to a couple of examples using Tika, one with Lucene directly, the other using Solr (which you might want to consider as well). 
一個簡單示比例如以下:首先使用Tika提取word中的本文,再使用TextField索引文字。


doc.add(new TextField("contents", TikaBasicUtil.extractContent(filetoIndex),Field.Store.NO));
注意此處不能使用StringField。由於StringField限制了字串的大小不能超過32766,否則會報異常IllegalArgumentException:Document contains at least one immense term in field="contents" (whose UTF8 encoding is longer than the max length 32766)*/
使用Tika索引富文本的簡單示比例如以下:注意,此示範範例不僅能夠索引word。還能夠索引pdf,excel等。


package org.jediael.util;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import org.apache.tika.exception.TikaException;import org.apache.tika.metadata.Metadata;import org.apache.tika.parser.AutoDetectParser;import org.apache.tika.parser.ParseContext;import org.apache.tika.parser.Parser;import org.apache.tika.sax.BodyContentHandler;import org.xml.sax.ContentHandler;import org.xml.sax.SAXException;public class TikaBasicUtil {public static String extractContent(File f) {//1、建立一個parserParser parser = new AutoDetectParser();InputStream is = null;try {Metadata metadata = new Metadata();metadata.set(Metadata.RESOURCE_NAME_KEY, f.getName());is = new FileInputStream(f);ContentHandler handler = new BodyContentHandler();ParseContext context = new ParseContext();context.set(Parser.class,parser);//2、運行parser的parse()方法。parser.parse(is,handler, metadata,context);String returnString = handler.toString();System.out.println(returnString.length());return returnString;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (SAXException e) {e.printStackTrace();} catch (TikaException e) {e.printStackTrace();}finally {try {if(is!=null) is.close();} catch (IOException e) {e.printStackTrace();}}return "No Contents";}}



三、關於DocumentFSDocument RAMDocument 四、關於IndexWriter1、建立一個IndexWriter
Directory returnIndexDir = FSDirectory.open(indexDir);IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_48,new StandardAnalyzer(Version.LUCENE_48));iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);writer = new IndexWriter(returnIndexDir, iwc);System.out.println(writer.getConfig().getOpenMode()+"");System.out.println(iwc.getOpenMode());
建立一個IndexWriter時,須要2個參數,一個是Directory對象,用於指定所建立的索引寫到哪個地方。還有一個是IndexWriterConfig對象,用於指定writer的配置。
2、IndexWriterConfig(1)繼承關係
  • java.lang.Object
    • org.apache.lucene.index.LiveIndexWriterConfig
      • org.apache.lucene.index.IndexWriterConfig
  • All Implemented Interfaces:
    Cloneable
    (2)Holds all the configuration that is used to create an  IndexWriter. Once  IndexWriter has been created with this object, changes to this object will not affect the  IndexWriterinstance.
    (3)IndexWriterConfig.OpenMode:指明了開啟索引檔案夾的方式,有下面三種:
    APPEND:Opens an existing index. 若原來存在索引,則將本次索引的內容追加進來。無論文檔是否與原來是否反覆。因此若2次索引的文檔同樣,則返回結果數則為原來的2倍。
    CREATE:Creates a new index or overwrites an existing one. 若原來存在索引,則先將其刪除,再建立新的索引
    CREATE_OR_APPEND【預設值】:Creates a new index if one does not exist, otherwise it opens the index and documents will be appended.
3、索引的最佳化索引過程中,會將索引結果存放至多個索引檔案裡,這樣會回收索引的效率。但在搜尋時,須要將多個索引檔案裡的返回結果進行合并處理。因此效率較低。為了加快搜尋結果的返回。能夠將索引進行最佳化。
writer.addDocument(doc);writer.forceMerge(2);
索引的最佳化是將索引結果檔案歸為一個或者有限的多個,它加大的索引過程中的消耗,降低了搜尋時的消耗。



五、關於Analyzer此處主要關於和索引期間相關的analyzer,關於analyzer更具體的內容請參見 http://blog.csdn.net/jediael_lu/article/details/33303499  【Lucene4.8教程之四】分析在建立IndexWriter時。須要指定分析器。如:

IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_48,new StandardAnalyzer(Version.LUCENE_48));writer = new IndexWriter(IndexDir, iwc);

便在每次向writer中加入文檔時,能夠針對該文檔指定一個分析器,如
writer.addDocument(doc, new SimpleAnalyzer(Version.LUCENE_48));




六、關於Directory

【Lucene4.8教程之二】索引

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.