Lucene 3.0.2 使用入门

最近在做一个大作业,主要是用到Heritrix 1.14.4 + Lucene 3.0.2
主要是兴趣所在,所以之前对Heritrix进行了一些些皮毛的学习,这次的作业要更实质些,对用Heritrix爬下来的那1.5G文件进行索引的建立和搜索的实现。还有自己写下新的排序算法,提高搜索的质量和结果。

其他的先不说,先从Lucene的入门级别开始。
3.0版本是重大的版本,改动很大。在API上做了很多的调整,已经删除了很多之前废弃的方法以及类,并支持了很多Java5 的新特性:包括泛型、可变参数、枚举和autoboxing等。因此,此版本和2.x版本不能兼容,如要使用3.0版本,最好是在新项目中去使用,而不是去升级2.x或之前的版本!

1. Lucene的配置安装
Lucene官方网站: http://lucene.apache.org/
Lucene的文档链接: http://lucene.apache.org/java/3_0_1/
Lucene的Jar文件下载地址: http://www.apache.org/dyn/closer.cgi/lucene/java/
其他帖子:
1 http://www.360doc.com/content/10/0818/14/87000_46942239.shtml
2 http://forfuture1978.iteye.com/category/89151
3 http://code.google.com/p/ik-analyzer/
4
Lucene的使用: 使用起来很简单,将core 和 demos两个jar文件加到自己的项目中即可使用Lucene强大的功能。

2. Lucene中包的分析
Lucene 软件包的发布形式是一个 JAR 文件,其中core部分是比较重要的。
Package: org.apache.lucene.document 这个包提供了一些为封装要索引的文档所需要的类,比如 Document, Field。这样,每一个文档最终被封装成了一个 Document 对象。
Package: org.apache.lucene.analysis 这个包主要功能是对文档进行分词,因为文档在建立索引之前必须要进行分词,所以这个包的作用可以看成是为建立索引做准备工作。
Package: org.apache.lucene.index 这个包提供了一些类来协助创建索引以及对创建好的索引进行更新。这里面有两个基础的类:IndexWriter 和 IndexReader,其中 IndexWriter 是用来创建索引并添加文档到索引中的,IndexReader 是用来删除索引中的文档的。
Package: org.apache.lucene.search 这个包提供了对在建立好的索引上进行搜索所需要的类。比如 IndexSearcher 和 Hits, IndexSearcher 定义了在指定的索引上进行搜索的方法,Hits 用来保存搜索得到的结果。
Package: org.apache.lucene.util 这个包提供了一些常用的帮助类


3. 下面是使用Lucene 3.0.2对一个目录下的文档进行索引建立并进行搜索的一个实例,具体的使用介绍注释中已经很详细。
package com.eric.lucene;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;

public class LuceneApp {
	private File baseDir;
	private File indexDir;

	public LuceneApp() {
		this.baseDir = new File("E:\\Study\\Lectuer\\lucene\\files_indexed");
		this.indexDir = new File("E:\\Study\\Lectuer\\lucene\\lucene_index");
		if (!this.baseDir.exists() || !this.indexDir.exists()) {
			System.err.println("The directory does not exist!!!!");
			return;
		}
	}

	public LuceneApp(String dir) {
		this.baseDir = new File(dir);
		this.indexDir = new File("E:\\Study\\Lectuer\\lucene\\lucene_index");
		if (!this.baseDir.exists() || !this.indexDir.exists()) {
			System.err.println("The directory or file you specified does not exist!!!!");
			return;
		}
	}

	public LuceneApp(String dir, String indexDir) {
		this.baseDir = new File(dir);
		this.indexDir = new File(indexDir);
		if (!this.baseDir.exists() || !this.indexDir.exists()) {
			System.err.println("The directory or file you specified does not exist!!!!");
			return;
		}
	}

	/**
	 * 索引文件是否已经建立.因为索引建立的过程是非常耗时的
	 * @return
	 */
	private boolean isIndexCreated(){
		String[] files = this.indexDir.list();
		if(files.length == 0){
			return false;
		}
		return true;
	}
	
	/**
	 * 对baseDir目录以及子目录下的文件创建索引
	 */
	public void createIndex() {
		if(!this.isIndexCreated()){
			try {
				IndexWriter writer = new IndexWriter(
						FSDirectory.open(this.indexDir), new StandardAnalyzer(
								Version.LUCENE_30), true, IndexWriter.MaxFieldLength.LIMITED);
				indexDirectory(writer, baseDir);
				writer.optimize();// 在建立索引之后调用此函数。引自API“It is recommended that this method be called upon completion of indexing.”
				writer.close();
			} catch (CorruptIndexException e) {
				e.printStackTrace();
			} catch (LockObtainFailedException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 给一个指定的目录下的所有文件创建索引
	 * 
	 * @param writer
	 * @param dir
	 */
	private void indexDirectory(IndexWriter writer, File dir) {
		if (!dir.exists() || !dir.isDirectory()) {
			System.err.println("The dir does not exist or it is not a directory!!!!");
			return;
		}
		File[] files = dir.listFiles();
		for (int i = 0; i < files.length; i++) {
			File file = files[i];
			if (file.isDirectory()) {
				indexDirectory(writer, file);
			} else {
				indexFile(writer, file);
			}
		}
	}

	/**
	 * 用writer来对f进行索引的建立
	 * 
	 * @param writer
	 * @param file
	 */
	private void indexFile(IndexWriter writer, File file) {
		if (file.isHidden() || !file.exists() || !file.canRead()) {
			System.err.println("The file is hidden file, or does not exist, or can not be read!!!!");
			return;
		}

		try {
			Document doc = new Document();
			doc.add(new Field("contents", new FileReader(file)));//对整个文件内容建立索引
			doc.add(new Field("filename", file.getCanonicalPath(),
					Field.Store.YES, Field.Index.ANALYZED));//对文件名建立索引
			writer.addDocument(doc);//调用addDocument()方法,Lucene会建立doc的索引
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 在之前建立过的索引中,对keyword进行搜索
	 * @param keyword
	 */
	public void search(String keyword) {
		try {
			IndexSearcher is = new IndexSearcher(FSDirectory.open(this.indexDir), true);
			QueryParser parser = new QueryParser(Version.LUCENE_30, "contents",	new StandardAnalyzer(Version.LUCENE_30));//对Document中的哪个Field进行QueryParser
			Query query = parser.parse(keyword);
			TopScoreDocCollector collector = TopScoreDocCollector.create(100, false);
			
			long start = new Date().getTime();
			is.search(query, collector);//IndexSearcher对Query进行索引,并将结果保存在TopScoreDocCollector中
			ScoreDoc[] hits = collector.topDocs().scoreDocs;

			System.out.println(hits.length);
			for (int i = 0; i < hits.length; i++) {
				Document doc = is.doc(hits[i].doc);
				System.out.println(doc.getField("filename") + "\t" + hits[i].toString());//得到doc中的filename的Field
			}
			long end = new Date().getTime();

			System.out.println("Found " + collector.getTotalHits()
					+ " document(s) (in " + (end - start)
					+ " milliseconds) that matched query '" + keyword + "'");
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		LuceneApp lucene = new LuceneApp();
		lucene.createIndex();
		lucene.search("model");
	}
}


E:\Study\Lectuer\lucene\files_indexed\目录下的文件列表为:
内容都相同,为:



引用
1. Document-term incidence matrix
2. inverted index
输出: <Modified token, Document ID> 元组序列
Sort by terms(Core step)
合并一个文档中的多次出现,添加term的Frequency信息.
结果split 为一个Dictionary 文件和一个Postings 文件.
3. Bag of words model
Vector representation doesn’t consider the ordering of words in a document.John is quicker than Mary and Mary is quicker than John have the same vectors

Solution:
记录term的field property
记录term在docs中的position information
4. Query Processing
Document-at-a-time
Calculates complete scores for documents by processing all term lists, one document at a time
Term-at-a-time
Accumulates scores for documents by processing term lists one at a time
5. Scoring and Ranking(Beyond Boolean Search)
用户会期待结果按某种 order 返回,most likely to be useful 的文档在结果的前面

TF scoring(Term Frequecy)
problem
没有区分词序(Positional information index)
长文档具有优势(除以文档的总次数)
出现的重要程度其实与出现次数不成正比关系(对次数 取对数,为了不让过高的频率而使得重要程度过高)
不同的词,其重要程度其实不一样(Discrimination of terms)



6.
7.
8.
9.
10.


运行结果如下:
12
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia.txt>   doc=0 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia1.txt>   doc=1 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia2.txt>   doc=2 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia3.txt>   doc=3 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia4.txt>   doc=4 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia5.txt>   doc=5 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia6.txt>   doc=6 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia7.txt>   doc=7 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia8.txt>   doc=8 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia9.txt>   doc=9 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia10.txt>   doc=10 score=0.05749733 
stored,indexed,tokenized<filename:E:\Study\Lectuer\lucene\files_indexed\wbia11.txt>   doc=11 score=0.05749733 
Found 12 document(s) (in 16 milliseconds) that matched query 'model'

4.
5.
6.
7.

猜你喜欢

转载自hanyuanbo.iteye.com/blog/812135