初识Lucene

     以前听过Lucene的大名,但是实际项目中一直没机会用到。直到今天,无事看看,发现者东西真是厉害,很多知名公司都已经在用了,包括google和apple。
这篇文章将分3部分介绍lucene, 1. Lucene简单的介绍  2.如何创建索引  3.如何搜索
 
1. Lucene简单的介绍
 
     Lucene是一个全文检索引擎,官网是http://lucene.apache.org 当前最新版是4.4
官网除了介绍Lucene外,还在显目位置放了Solr的东西,看介绍说是基于Lucene core的高性能搜索服务器,日后有空再去研究他。
后来又去弄了本Lucene in action 2nd, 准备走走经典流程Hello World。
     和预想的一样,搜索引擎,逃脱不了这样的套路:
     创建索引的时候
     用web爬虫等数据内容获取工具拿到数据    接着    将内容进行分词处理,留下有意义的词    然后创建索引保存起来
     在搜索的时候
     得到用户的搜索词,解析分词,找到索引文件,搜索,返回搜索结果。
     Lucene in action中是这样描述的:
 
     大体是相同的,从资料中获取数据,构造文档,分析文档进行分词,然后生成索引文档,然后保存。当搜索的时候,用户通过搜索UI输入关键字,应用程序创建搜索对象,搜索索引,然后返回结果。
     
     接下来,我们先走一遍Hello World,再介绍下各个重要部分。
 
2. 创建索引
     下面是创建索引的代码:
     
/**
 * 
 */
package demo;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
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;

/**
 * @author 
 * 
 */
publicclass Indexer {
private IndexWriter writer;

/**
*
* @param indexDir
* @throws IOException
*/
public Indexer(String indexDir) throws IOException {
// 定义索引的存放目录为File System
Directory dir = FSDirectory.open(new File(indexDir));
// 配置创建创建方式,使用标准的Analyzer
IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_44,
new StandardAnalyzer(Version.LUCENE_44));
writer = new IndexWriter(dir, conf);
}

publicint index(String dataDir, FileFilter filter) throws Exception {
// 遍历数据目录
File[] files = new File(dataDir).listFiles();
for (File f : files) {
if (!f.isDirectory() && !f.isHidden() && f.exists() && f.canRead() && (filter == null || filter.accept(f))) { // 得到符合条件的txt文件 indexFile(f); }
}
return writer.numDocs();
}
privatevoid indexFile(File f) throws Exception {
System.out.println("Indexing " + f.getCanonicalPath());
Document doc = getDocument(f);
writer.addDocument(doc);
}
// 为Document 添加 Field
protected Document getDocument(File f) throws Exception {
Document doc = new Document();
doc.add(new TextField("content", new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"))));
doc.add(new StringField("filename", f.getName(), Field.Store.YES));
doc.add(new StringField("fullpath", f.getCanonicalPath(),
Field.Store.YES));
return doc;
}
/**
* @throws IOException
*/
publicvoid close() throws IOException {
writer.close();
}
// 过滤文件 privatestaticclass TextFilesFilter implements FileFilter {
publicboolean accept(File path) {
return path.getName().toLowerCase().endsWith(".txt");
}
}
/**
* @param args
* @throws Exception
*/
publicstaticvoid main(String[] args) throws Exception {
// 索引存放路径
String indexDir = "/Users/apple/Documents/index";
// 数据文件路径
String dataDir = "/Users/apple/Documents/data";
long start = System.currentTimeMillis();
Indexer indexer = new Indexer(indexDir);
int numIndexed;
try {
// 调用自己写得index方法创建索引
numIndexed = indexer.index(dataDir, new TextFilesFilter());
} finally {
indexer.close();
}
long end = System.currentTimeMillis();
System.out.println("Indexing " + numIndexed + " files took " + (end - start) + " milliseconds");
}
}
 
     这段代码是这样:
     
     首先定义了数据存放目录,以及索引目录,后者空,前者包含几个txt文档,文档里面有几句英文句子(当然支持中文,但代码会复杂,不在hello world范畴了)
     定义了2个目录后,接下来就是读取文档,获取内容了,这一步大家可以按照自己的方法写,只要能够遍历txt文档,并取得内容即可。
     
接着,
这2个方法是把File对象创建成Document,也就是把内容存入到Document中,然后添加到IndexWriter中。一个Document对象包含若干个Field。你可以这么理解:一个Document对象想象成数据库表中得一行,而Field就是某列。
说到IndexWriter,她是这样创建的:
StandardAnalyzer,按照字面理解是标准分词解析器,按照我的猜想,如果要解析中文,估计也是在这里动手脚。她帮助IndexWriter解析你传进来的Field的内容,进行分词,词加权等操作。IndexWriter负责将生成的索引写入到FSDirectory中。也可以是RAM,你可以修改38行的代码。
这样,一个索引的创建过程就完成了。如果你的代码报错,尤其是StandardAnalyzer找不到,你需要导入Analyzer / common包下的那个jar包。
运行一遍,即可在index目录下生成索引了:
 
 
3. 搜索
     有了索引后,就是搜索了,搜索相对简单些,构造搜索对象,然后搜索并显示结果。
 
这个是她的运行结果
 
至于那个为什么是null,Lucene in action没说,按照我的猜测,因为她是一个TextField对象,从文本读取出来的,她可能很大很大,如果把这个内容也放入索引,那么索引库的体积将会非常大,所以默认是不保存TextField,至于我的猜想是否正确,需待深入了解。热心的网友也可给我留言。
 
 
就这样,一个Hello World就完成了。
 
总结:
创建索引的核心类:IndexWriter,Directory,Analyzer,Document,Field
 
IndexWriter是创建索引的核心组件,她负责创建一个新索引货打开已经存在的索引,以及添加,删除更新索引中得文档。她是负责写索引的,所以也要给他指定一个Directory,告诉她索引存哪。
 
Directory代表了Lucene 索引的存放地址,她又多种方式可用存,File System, RAM等
 
Analyzer,在文本被索引前,将会被Analyzer处理。做分词处理,去掉一些无意义的词,如空格,停顿,the,之类的词。有多种Analyzer,自由选择以解析富文本对象等。
 
Document,代表field的集合。可被认为是web page,email message,数据表某一行,而field就是元数据了,比如标题,内容,创建时间,路径等等,自由自定。不过你要记住的是,Lucene只能处理文本和数字。所以你要利用各种方法先将非文本转成文本。
 
Field就是Lucene将要索引的值
 
搜索的关键对象:
IndexSearcher,负责搜索INdexWriter写得索引。

Directory dir = FSDirectory.open(new File("/tmp/index"));
IndexSearcher searcher = new IndexSearcher(dir);
Query q = new TermQuery(new Term("contents", "lucene"));
TopDocs hits = searcher.search(q, 10);

searcher.close();
这是她的典型用法
Term,是搜索的基本单元,与Field对象类似。包含用于搜索的Field name和value
Query,搜索对象,和JDBC中得Query功能一样,Lucene有很多实现方式,例子中用到的是TermQuery
TermQuery基本的搜索方式
TopDoc,也就是搜索结果,她包含一个docID,你可以通过她取得document对象。 
原文地址:https://www.cnblogs.com/dycg/p/3211076.html