一、简介 Lucene是什么:Lucene是apache软件基金会jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。 Lucene是一个基于Java的全文搜索,不是一个完整的搜索应用,而是一个代码库和API,可以方便地为应用提供搜索功能。 实际上Lucene的功能就是将开发人员提供的若干个字符串建立索引,然后提供一个全文搜索服务,用户将搜索的关键词提供给搜索服务,搜索服务告诉用户关键词出现的各字符串。
二、 基本流程
lucene包含两部分:建立索引和搜索服务。建立索引是将源(本质是字符串)写入索引或者将源从索引中删除;进行搜索是向用户提供全文搜索服务,用户可以通过关键词定位源。
1. 建立索引的流程
- 使用analyzer处理源字符串,包括:分词,即分成一个个单词;去除stopword(可选)。
- 将源中的有效信息以不同Field的形式加入Document中,并把Document加入索引,从而在索引中记录有效的Field。
- 将索引写入存储器(内存或磁盘)。
- 用户提供搜索关键词,经过analyzer处理。
- 对处理后的关键词搜索索引找出对应的Document。
- 用户根据需要从找到的Document中提取需要的Field。
2. 检索的流程
- 用户提供搜索关键词,经过analyzer处理。
- 对处理后的关键词搜索索引找出对应的Document。
- 用户根据需要从找到的Document中提取需要的Field。
三、 基本概念
1. Analyzer
Analyzer的作用是分词,并去除字符串中的无效词语。
分词的目的是把字符串按某种语义规则划分为若干个词。英文中比较容易实现分词,因为英文本身就是以单词为单位,已经用空格分开;而中文则必须以某种方法将连成一片的句子划分成一个个词。 无效词语,如英文中的“of”、“the”和中文中的“的”、“地”等,这些词语在文章中大量出现。但是本身不包含关键信息,去掉后有利于缩小索引文件、提高命中率和执行效率。
2. Document
用户提供的源可以是文本文件、字符串或者数据库表中的一条记录等。一个源字符串经过索引之后,以一个Document的形式存储在索引文件中。搜索服务的结果也是以Document列表的形式返回。
3. Field
一个Document可以包含多个信息域,如一篇文章可以包含“标题”、“正文”、“最后修改时间”等信息域,这些信息域以Field的形式保存在Document中。
Field有两个属性:存储和索引。存储属性可以控制是否对这个Field进行存储;索引属性可以控制是否对该Field进行索引。这似乎多此一举,但事实上对这两个属性的正确组合很重要。
下面举例说明:一篇文章需要对标题和正文进行全文搜索,所以把这两个Field的索引属性设置为真;同时希望能直接从搜索结果中提取文章标题,所以把标题Field的存储属性设置为真。但是正文Field太大了,为了缩小索引文件,将正文Field的存储属性设置为假,需要访问时再直接读取文件正文;希望能从搜索结果中提取最后修改时间;但是不需要对它进行搜索,所以把最后修改时间Field的存储属性设置为真,索引属性设置为假。
Field的两个属性禁止全为假的情况因为这对建立索引没有意义。
4. segment
建立索引时,并不是每个document都马上添加到同一个索引文件,它们首先被写入到不同的小文件,然后再合并成一个大索引文件,每个小文件都是一个segment。
5. term
term表示文档的一个词,是搜索的最小单位。term由两部分组成:所表示的词语和这个词语所出现的field。
6. token
token是term的一次出现,它包含trem文本和相应的起止偏移,以及一个类型字符串。一句话中可以出现多次相同的词语,它们都用同一个term表示,但是用不同的token,每个token标记该词语出现的位置。
四、 Lucene的组成结构
Lucene core包含8个包:analysis、collation、document、index、queryParser、search、store、util。
1. analysis包(文本解析库)
这个库是对文本进行解析,得到相应的Term对象,在Index与Searcher的时候都会用到,在索引过程中,它会对被索引的文件进行解析,而在搜索过程中,它会对查询条件进行解析。
Analysis提供自带的各种Analyzer,如按空白字符分词的WhitespaceAnalyzer,添加了stopword过滤的StopAnalyzer,支持中文分词的SmartChineseAnalyzer,以及最常用的StandardAnalyzer。
2. collation包
包含collationKeyFilter和collationKeyAnalyzer两个相同功能的类,将所有token转换为CollationKey,并将CollationKey与IndexableBinaryStringTools一起编码存储为一个term。
3. document包(文档的一个对象模型抽象库)
document包中是Document相关的各种数据结构,如Document类、Field类等。
4. index包(索引库)
index包中是索引的读写操作类,常用的是对索引文件的segment进行写、合并和优化的IndexWriter类和对索引进行读取和删除操作的IndexReader类。IndexWriter只关心如何将索引写入一个个segment并将它们合并优化;IndexReader关注索引文件中各个文档的组织形式。它主要是用来对文档建立索引,对索引进行维护(更新索引,优化索引等),为查询提供访问接口。
5. queryParser包
queryParser包中是解析查询语句相关的类(常用的是QueryParser类)以及Token类。
6. search包(查询库)
search包中是从索引中进行搜索的各种不同的Query类(如TermQuery、BooleanQuery等)和搜索结果集Hits类。 它主要是为用户提供查询接口的,对用户的查询结果进行评估,并返回与用户最相关的查询信息。
7. store包(存储库)
store包中是索引的存储相关类,如Directory类定义了索引文件的存储结构,FSDirectory是存储在文件系统(即磁盘)中的索引存储类,RAMDirectory为存储在内存中的索引存储类,MmapDirectory为使用内存映射的索引存储类。它主要是用来存储索引内容的,这里提供了两种存储方式,一种是磁盘存储,另一个是内存存储。
8. util包(工具库)
util包中是公共工具类,例如时间和字符串之间的转换工具。
五、 环境搭建及测试
在项目中引入lucene的两个核心包:lucene-core-3.6.2.jar和lucene-core-3.6.2-javadoc.jar;
在windows系统下的的D盘,建一个名叫lucene的文件夹,lucene文件夹下建个temp文件夹,temp下建两个文件夹,名字分别为docs(存放文本文件)和index(存放索引文件)。在docs文件夹里创建三个txt文件,如:1.txt,2.txt,3.txt;3个txt文件里随便写些内容。
1.建立索引:
package com.javaeye.lucene;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
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.Field.TermVector;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
@SuppressWarnings("deprecation")
public class LuceneTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/** 指明要索引文件夹的位置,这里是D:\lucene\temp\docs文件夹下 */
File fileDir=new File("D:"+File.separator+"lucene"+File.separator+"temp"+File.separator+"docs");
/**放索引文件的位置*/
File indexDir=new File("D:"+File.separator+"lucene"+File.separator+"temp"+File.separator+"index");
Analyzer luceneAnalyer=new StandardAnalyzer(Version.LUCENE_36);
Directory dir=FSDirectory.open(indexDir);
IndexWriterConfig iwc=new IndexWriterConfig(Version.LUCENE_36,luceneAnalyer);
iwc.setOpenMode(OpenMode.CREATE);
IndexWriter indexWriter=new IndexWriter(dir,iwc);
// 在索引库没有建立并且没有索引文件的时候首先要commit一下让他建立一个,索引库的版本信息 ,如果第一次没有commit就打开一个索引读取器的话就会报异常
//indexWriter.commit();
File[] textFiles=fileDir.listFiles();
long startTime=new Date().getTime();
//增加document到索引去
for(int i=0;i<textFiles.length;i++){
if(textFiles[i].isFile() && textFiles[i].getName().endsWith(".txt")){
System.out.println("File"+textFiles[i].getCanonicalPath()+"正在被索引。");
String temp=FileReaderAll(textFiles[i].getCanonicalPath(),"GBK");
System.out.println(temp);
Document document=new Document();
//创建一个字段
Field fieldPath=new Field("path",textFiles[i].getPath(),Field.Store.YES,Field.Index.NO);
Field fieldBody=new Field("body",temp,Field.Store.YES,Field.Index.ANALYZED,TermVector.WITH_POSITIONS_OFFSETS);
document.add(fieldPath);
document.add(fieldBody);
indexWriter.addDocument(document);
}
}
indexWriter.close();
long endTime=new Date().getTime();
System.out.println("这花费了"+(endTime-startTime)+"毫秒来把文档增加到索引里面去!"+fileDir.getPath());
}
public static String FileReaderAll(String filename,String charset)throws IOException{
BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream(filename),charset));
String line=new String();
String temp=new String();
while((line=reader.readLine())!=null){
temp+=line;
}
reader.close();
return temp;
}
}
运行结果:
FileD:\lucene\temp\docs\1.txt正在被索引。
给我你的爱
FileD:\lucene\temp\docs\2.txt正在被索引。
爱情来得如此微妙-Yeah!
FileD:\lucene\temp\docs\3.txt正在被索引。
Because守护我们的爱情...
这花费了419毫秒来把文档增加到索引里面去!D:\lucene\temp\docs
package com.javaeye.lucene;
import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexReader;
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.FSDirectory;
import org.apache.lucene.util.Version;
public class QueryTest {
/**
* @param args
*/
@SuppressWarnings("deprecation")
public static void main(String[] args) throws IOException,ParseException {
String index="D:\\lucene\\temp\\index";
File file=new File(index);
if(file!=null){
System.out.println(file.getCanonicalPath());
}
IndexReader reader=IndexReader.open(FSDirectory.open(file));
IndexSearcher searcher=new IndexSearcher(reader);
ScoreDoc[] hits=null;
String queryStr="爱情";//搜索的关键词
Query query=null;
Analyzer analyzer=new StandardAnalyzer(Version.LUCENE_36);;
try{
QueryParser qp=new QueryParser(Version.LUCENE_36,"body",analyzer);
query=qp.parse(queryStr);
}catch(ParseException e){
e.printStackTrace();
}
if(searcher!=null){
TopDocs results=searcher.search(query,10);
hits=results.scoreDocs;
if(hits.length>0){
System.out.println("找到"+hits.length+"结果");
for(int i=0;i<hits.length;i++){
System.out.println(searcher.doc(hits[i].doc).get("body"));
}
}
searcher.close();
}
}
}
运行结果:
D:\lucene\temp\index
找到3结果
爱情来得如此微妙-Yeah!
Because守护我们的爱情...
给我你的爱
到此测试成功完毕!!!!!
PS:
Lucene其实很简单的,它最主要就是做两件事:建立索引和进行搜索
来看一些在lucene中使用的术语,这里并不打算作详细的介绍,只是点一下而已----因为这一个世界有一种好东西,叫搜索。
IndexWriter:lucene中最重要的的类之一,它主要是用来将文档加入索引,同时控制索引过程中的一些参数使用。
Analyzer:分析器,主要用于分析搜索引擎遇到的各种文本。常用的有StandardAnalyzer分析器,StopAnalyzer分析器,WhitespaceAnalyzer分析器等。
Directory:索引存放的位置;lucene提供了两种索引存放的位置,一种是磁盘,一种是内存。一般情况将索引放在磁盘上;相应地lucene提供了FSDirectory和RAMDirectory两个类。
Document:文档;Document相当于一个要进行索引的单元,任何可以想要被索引的文件都必须转化为Document对象才能进行索引。
Field:字段。
IndexSearcher:是lucene中最基本的检索工具,所有的检索都会用到IndexSearcher工具;
Query:查询,lucene中支持模糊查询,语义查询,短语查询,组合查询等等,如有TermQuery,BooleanQuery,RangeQuery,WildcardQuery等一些类。
QueryParser:是一个解析用户输入的工具,可以通过扫描用户输入的字符串,生成Query对象。
Hits:在搜索完成之后,需要把搜索结果返回并显示给用户,只有这样才算是完成搜索的目的。在lucene中,搜索的结果的集合是用Hits类的实例来表示的。