一、概述
lucene是一个全文搜索引擎,在全文索引工具中,都是由这样的但部分组成:
- 1、索引部分
- 2、分词部分
- 3、搜索部分
二、入门程序
2.1 入门程序
这里我们需要导入lucene
的jar
包,注意:这里使用的是3.5.0版本,lucene
的各个版本差异较大。
下面看入门程序,看lucene如何创建索引和搜索索引(工程lucene01
):
HelloLucene.java
package cn.lucene.test;
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.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
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.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
public class HelloLucene {
//建立索引
public void index(){
IndexWriter writer = null;
try {
//1、创建Directory
//Directory directory = new RAMDirectory();//索引是建立在内存中的
Directory directory = FSDirectory.open(new File("E:/myeclipse/Lucene/index"));//创建在硬盘上
//2、创建IndexWriter
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35));
writer = new IndexWriter(directory, iwc);
//3、创建Document对象
Document doc = null;
//4、为Document添加Field,是Document的一个子元素
File file = new File("E:/myeclipse/Lucene/somefile");
for(File f : file.listFiles()){
doc = new Document();
doc.add(new Field("content", new FileReader(f)));
doc.add(new Field("filename", f.getName(), Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new Field("path", f.getAbsolutePath(), Field.Store.YES, Field.Index.NOT_ANALYZED));
//5、通过IndexWriter添加文档到索引中
writer.addDocument(doc);
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//搜索
public void search(){
Directory directory;
try {
//1、创建Directory
directory = FSDirectory.open(new File("E:/myeclipse/Lucene/index"));
//2、创建IndexReader
IndexReader reader = IndexReader.open(directory);
//3、根据IndexReader创建IndexSearcher
IndexSearcher searcher = new IndexSearcher(reader);
//4、创建搜索的Query
//创建QueryParser来确定要搜索文件的内容,第二个参数表示搜索的域
QueryParser parser = new QueryParser(Version.LUCENE_35, "content", new StandardAnalyzer(Version.LUCENE_35));
//创建Query,表示搜索域为content中包含java的文档
Query query = parser.parse("java");
//5、根据searcher搜索并且返回TopDocs
TopDocs tdoc = searcher.search(query, 10);//只会显示10条内容
//6、根据TopDocs获取ScoreDoc对象
ScoreDoc sdocs[] = tdoc.scoreDocs;
for(ScoreDoc s : sdocs){
//7、根据searcher行业ScoreDoc获取具体的Document对象
Document document = searcher.doc(s.doc);
//8、根据Document对象获取所需要的值
System.out.println(document.get("filename") + "[" + document.get("path") + "]");
}
//9、关闭reader
reader.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
说明:这里我们存储的文档放在E:/myeclipse/Lucene/somefile
中,创建的搜索我们放在E:/myeclipse/Lucene/index
中,这里方法index()
是创建文档索引的方法,而search()
是搜索文档索引的方法。
2.2 测试
TestLucene.java
package cn.lucene.test;
import org.junit.Test;
public class TestLucene {
@Test
public void testIndex(){
HelloLucene hLucene = new HelloLucene();
hLucene.index();
}
@Test
public void testSearch(){
HelloLucene hLucene = new HelloLucene();
hLucene.search();
}
}
说明:这里我们在创建文档之后再次创建生成的索引不会覆盖,而是会增加,这是因为lucene
索引是一种增量索引,每次生成索引都不会将前面生成的索引删除,而是添加,于是每次搜索出来的结果会有重复。这里我们搜索关键字为java
,会打印出相关的文件路径,这里我们先不深究程序的具体实现。
三、相关概念
3.1 建立索引时最重要的几个术语
Document
:一个要进行索引的单元,相当于数据库的一行纪录,任何想要被索引的数据,都必须转化为Document
对象存放。Field
:Document
中的一个字段,相当于数据库中的Column
,Field
是lucene
比较多概念一个术语。IndexWriter
:负责将Document
写入索引文件。通常情况下,IndexWriter
的构造函数包括了以下3个参数:索引存放的路径,分析器和是否重新创建索引。特别注意的一点,当IndexWriter
执行完addDocument
方法后,一定要记得调用自身的close
方法来关闭它。只有在调用了close
方法后,索引器才会将存放在内在中的所有内容写入磁盘并关闭输出流。Analyzer
:分析器,主要用于文本分词(可以这样理解,就是将一段话分成单个的词语,然后为单个的词语建立标识,便于搜索,就像一个超链接一样)。常用的有StandardAnalyzer
分析器,StopAnalyzer
分析器,WhitespaceAnalyzer
分析器等。Directory
:索引存放的位置。lucene
提供了两种索引存放的位置,一种是磁盘,一种是内存。一般情况将索引放在磁盘上;相应地lucene
提供了FSDirectory
和RAMDirectory
两个类。-
段:
Segment
是Lucene
索引文件的最基本的一个单位。Lucene
说到底就是不断加入新的Segment
,然后按一定的规则算法合并不同的Segment
以合成新的Segment
。我们在上面测试时从建立的索引文件中就可以看出有如
图中使用0,1标号表示的就是段,而这里我们可以看到每次创建索引都是增加而不是覆盖。 最后
lucene
建立索引的过程就是将待索引的对象转化为Lucene
的Document
对象,使用IndexWriter
将其写入lucene
自定义格式的索引文件中。待索引的对象可以来自文件、数据库等任意途径,用户自行编码遍历目录读取文件或者查询数据库表取得ResultSet
,Lucene
的API
只负责和字符串打交道。
3.2 存储域选项
存储域选项有Field.Store.YES
或Field.Store.NO
,设置为YES
表示把这个域中的内容完全存储到文件中,方便进行文本的还原,设置为NO
表示不把这个域中的内容完全存储到文件中,但是可以被索引,此时内容无法完全还原。比如一篇文章,我们可以建立文章的索引(此索引就是用来搜索这篇文章的一个标签),但是我们可以不将整片文章内容全部存储下来,但是这样我们虽然能搜索到这篇文章,但是却不能将其还原。
3.3 索引域选项:
-
Field.Index.ANALYZED
:进行分词和索引,适用于标题、内容等。 -
Field.Index. ANALYZED_NO_NORMS
:进行分词但是不存储norms
信息,这个norms
中包括创建索引的时间和权值等信息 -
Field.Index. NOT_ANALYZED
:进行索引,但是不进行分词,如身份证号、姓名、ID等,试用于精确索引 -
Field.Index. NOT_ANALYZED_NO_NORMS
:即不进行分词也不存储norms
信息 -
Field.Index.NO
:不进行索引
3.4 最佳实践
域选项 | 存储与否 | 最佳实践 |
---|---|---|
NOT_ANALYZED_NO_NORMS |
YES |
标识符(主键、文件名),电话号码,身份证号,姓名,日期 |
ANALYZED |
YES |
文档标题和摘要 |
ANALYZED |
NO |
文档正文 |
NO |
YES |
文档类型,数据库主键(不进行索引) |
NOT_ANALYZED |
NO |
隐藏关键字 |