天天看點

(1)認識Lucene:建構索引

參考官網://http://lucene.apache.org/core/5_3_1/demo/overview-summary.html#overview_description

package example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

import org.apache.lucene.analysis.Analyzer;
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.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;


//http://lucene.apache.org/core/5_3_1/demo/overview-summary.html#overview_description
public class FileIndex {
	
	public static void main(String[] args) throws Exception
	{
		boolean create=false;
		String docsPath="E:\\LuceneDocument";
		String indexPath="E:\\LuceneIndex";
		final Path docDir = Paths.get(docsPath);
		if (!Files.isReadable(docDir)) 
		{
			System.out.println("Document directory '" +docDir.toAbsolutePath()+ "' does not exist or is not readable");
			System.exit(1);
		}
		
		//Directory這個類代表了Lucene的索引的存儲的位置,這是一個抽象類,它目前有兩個實作:
		//第一個是FSDirectory,它表示一個存儲在檔案系統中的索引的位置,
		//第二個是RAMDirectory,它表示一個存儲在記憶體當中的索引的位置。
		Directory directory = FSDirectory.open(Paths.get(indexPath));
		//在一個文檔被索引之前,首先需要對文檔内容進行分詞處理,這部分工作就是由 Analyzer來做的。
		//Analyzer類是一個抽象類,它有多個實作。針對不同的語言和應用需要選擇适合的 Analyzer。
		//Analyzer把分詞後的内容交給 IndexWriter來建立索引。
		Analyzer analyzer = new StandardAnalyzer();
		IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
		//IndexWriter是Lucene用來建立索引的一個核心的類,他的作用是把一個個的Document對象加到索引中來。
		IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
		
		if(create)
		{
			indexWriterConfig.setOpenMode(OpenMode.CREATE);
		}
		else
		{
			indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);			
		}
		IndexDocs(indexWriter, docDir);
		
		indexWriter.close();
	}
	
	static void IndexDocs(final IndexWriter writer, Path path) throws IOException 
	{
		if(Files.isDirectory(path))
		{
			Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
				@Override
				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
				{
					try
					{
						IndexDoc(writer, file, attrs.lastModifiedTime().toMillis());
					}
					catch(IOException ignore)
					{
						//don't index files that can't be read.
					}
					return FileVisitResult.CONTINUE;
				}
			});
		}
		else
		{
			IndexDoc(writer, path, Files.getLastModifiedTime(path).toMillis());
		}
	}
	
	public static void IndexDoc(IndexWriter writer, Path file, long lastModified) throws IOException
	{
		try(InputStream stream=Files.newInputStream(file))
		{
			//Document是用來描述文檔的,這裡的文檔可以指一個 HTML 頁面,一封電子郵件,或者是一個文本檔案。
			//一個 Document對象由多個 Field對象組成的。
			//可以把一個Document對象想象成資料庫中的一個記錄,而每個 Field對象就是記錄的一個字段。
			Document document=new Document();
			//Field對象是用來描述一個文檔的某個屬性的,比如一封電子郵件的标題和内容可以用兩個 Field對象分别描述。
			/*
			Add the path of the file as a field named "path". Use a field that is indexed (i.e. searchable), 
			but don't tokenize the field into separate words and don't index term frequency or positional information
			*/
			Field pathField=new StringField("path", file.toString(), Field.Store.YES);
			document.add(pathField);
			document.add(new LongField("modified", lastModified, Field.Store.NO));
			//Add the contents of the file to a field named "contents".
			//Specify a Reader, so that the text of the file is tokenized and indexed, but not stored.
			document.add(new TextField("contents", new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))));
			
			if(writer.getConfig().getOpenMode()==OpenMode.CREATE)
			{
				//New index, so we just add the document (no old document can be there):
				System.out.println("adding "+file);
				writer.addDocument(document);
			}
			else
			{
				//Existing index (an old copy of this document may have been indexed) so
				//we use updateDocument instead to replace the old one matching the exact path, if present:
				System.out.println("updating "+file);
				/*
				Term是搜尋的基本機關,一個 Term對象有兩個 String類型的域組成。
				生成一個 Term對象可以有如下一條語句來完成:Term term = new Term(“fieldName”,”queryWord”); 
				其中第一個參數代表了要在文檔的哪一個 Field上進行查找,第二個參數代表了要查詢的關鍵詞。
				*/
				writer.updateDocument(new Term("path", file.toString()), document);
			}
		}
	}
}
           

關于如何檢索,等待下一篇文章。

自己補理論,可以參考:http://www.cnblogs.com/xing901022/p/3933675.html

參考文獻:

[1] Mendes, Pablo N, Jakob, Max, Garc&#, et al. DBpedia spotlight: Shedding light on the web of documents[C]// Proceedings of the 7th International Conference on Semantic Systems. ACM, 2011:1-8.

[2] Han X, Sun L. A Generative Entity-Mention Model for Linking Entities with Knowledge Base.[J]. Proceeding of Acl, 2011:945-954.

[3] http://lucene.apache.org/

[4] http://alias-i.com/lingpipe/demos/tutorial/ne/read-me.html

[5] http://wiki.dbpedia.org/Downloads2014

[6] http://www.oschina.net/p/jieba(結巴分詞)