Lucene3.6 入门指南

From HERE

一、 简介


Lucene是什么:Lucene是apache软件基金会jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。

Lucene是一个基于Java的全文搜索,不是一个完整的搜索应用,而是一个代码库和API,可以方便地为应用提供搜索功能。 实际上Lucene的功能就是将开发人员提供的若干个字符串建立索引,然后提供一个全文搜索服务,用户将搜索的关键词提供给搜索服务,搜索服务告诉用户关键词出现的各字符串。

二、 基本流程


可见,lucene包含两部分:建立索引和搜索服务。建立索引是将源(本质是字符串)写入索引或者将源从索引中删除;进行搜索是向用户提供全文搜索服务,用户可以通过关键词定位源。

1. 建立索引的流程

  • 使用analyzer处理源字符串,包括:分词,即分成一个个单词;去除stopword(可选)。
  • 将源中的有效信息以不同Field的形式加入Document中,并把Document加入索引,从而在索引中记录有效的Field。
  • 将索引写入存储器(内存或磁盘)。

2. 检索的流程

  • 用户提供搜索关键词,经过analyzer处理。
  • 对处理后的关键词搜索索引找出对应的Document。
  • 用户根据需要从找到的Document中提取需要的Field。

三、 基本概念


1. Analyzer

Analyzer的作用是分词,并去除字符串中的无效词语。

分词的目的是把字符串按某种语义规则划分为若干个词。英文中比较容易实现分词,因为英文本身就是以单词为单位,已经用空格分开;而中文则必须以某种方法将连成一片的句子划分成一个个词。 无效词语,如英文中的“of”、“the”和中文中的“的”、“地”等,这些词语在文章中大量出现。但是本身不包含关键信息,去掉后有利于缩小索引文件、提高命中率和执行效率。

2. Document

用户提供的源可以是文本文件、字符串或者数据库表中的一条记录等。一个源字符串经过索引之后,以一个Document的形式存储在索引文件中。搜索服务的结果也是以Document列表的形式返回。

 Index
Document 1

Field A (name/value)
Field B (name/value)
Document 2

Field A (name/value)
Field B (name/value)

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和sandbox两部分,其中core是lucene的核心,sandbox包含了一些附加功能,如highlighter、各种分析器等。 Lucene core包含8个包:analysis、collation、document、index、queryParser、search、store、util。

1. analysis包

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包中是公共工具类,例如时间和字符串之间的转换工具。

五、 环境搭建


下载:

  1. http://lucene.apache.org/core/downloads.html
  2. http://mirror.bjtu.edu.cn/apache/lucene/java/3.6.1/lucene-3.6.1.zip

把lucene-core-3.6.1.jar加到项目中。

快速入门(Helloworld)

在开始helloworld之前,以lucene创建索引的流程辅助我们来了解几个概念。

  1. 信息源:要采集,必须有信息源,在这里我们就以读取硬盘中的文件(File)充当信息源。
  2. 加工:要把采集的信息,以lucene规定的形式存放到索引库中,所以要创建相应的文档(Document)对象。在这个文档中,我们要存放哪些信息才能达到完整且辟免垃圾信息,例如网页,我们可以要存储的是他的标题、内容、URL等,那些广告是不用存储的。在这里我们用到Field来存储各项目内容。
  3. 分析:对于加工好的了文档,我们是不是应该对其进行分词,答案是肯定的。用什么分词器呢?对英文和中文使用的分词器有可能不一样吧,这个得看后续分解了。在这里我们就用标准的分词器(StandardAnalyzer)
  4. 索引库:要把文档写入到索引库,并且根据分词器进行分词、建立索引,这得建索引库吧,在lucene中对应的是Directory,它可以建立在内存中,也可以建立在硬盘中。
  5. 一切具备,只缺把文档写入到索引库了,用什么呢?当然是IndexWriter。

好了,这就是lucene创建索引的过程,下面看看代码是怎样表现的。

六、 代码示例


Lucene在lucene-3.6.1-src/contrib/demo/src/java/org/apache/lucene/demo中提供了入门的示例代码。 

  • IndexFiles.java是关于建立索引的示例。 
  • SearchFiles.java是关于进行检索的示例。

1. 在文件系统中建立索引的代码

String indexPath = "/lucene/myindex"; 
 Directory dir = FSDirectory.open(new File(indexPath));  
 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36); 
 IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, analyzer); 
 iwc.setOpenMode(OpenMode.CREATE); //即创建新索引文件OpenMode.CREATE_OR_APPEND表示创建或追加到已有索引文件 
 IndexWriter writer = new IndexWriter(dir, iwc); 
 Document doc = new Document();  
 doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.ANALYZED));  
 doc.add(new Field("content", "lucene works well", Field.Store.YES, Field.Index. ANALYZED));  
 writer.addDocument(doc);  
 writer.close()

2. 直接在内存中建立索引的代码

Directory dir = new RAMDirectory();  
 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36); 
 IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, analyzer); 
 iwc.setOpenMode(OpenMode.CREATE); //即创建新索引文件OpenMode.CREATE_OR_APPEND表示创建或追加到已有索引文件 
 IndexWriter writer = new IndexWriter(dir, iwc); 
 Document doc = new Document();  
 doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.ANALYZED));  
 doc.add(new Field("content", "lucene works well", Field.Store.YES, Field.Index. ANALYZED));  
 writer.addDocument(doc);  
 writer.close();

3. 对整个文本文件my.txt建立索引的代码

… 
 File file = new File(“/home/hanxb/my.txt”); 
 FileInputStream fis = new FileInputStream(file);
 Document doc = new Document();   
 Field pathField = new Field("path", file.getPath(), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS); 
 pathField.setIndexOptions(IndexOptions.DOCS_ONLY); 
 doc.add(pathField);  
 NumericField modifiedField = new NumericField("modified");//索引key为modified 
 modifiedField.setLongValue(file.lastModified());//文件的最后修改时间 
 doc.add(modifiedField);  
 doc.add(new Field("contents", new BufferedReader(new InputStreamReader(fis, "UTF-8"))));  
 writer.addDocument(doc);//这里为创建新的索引文件 
 //如果为创建或追加索引文件, 则writer.updateDocument(new Term("path", file.getPath()), doc);  
 fis.close(); 
 writer.close()

4. 检索“Cloud Computing”关键词的代码

IndexReader reader = IndexReader.open(FSDirectory.open(new File(index))); 
 IndexSearcher searcher = new IndexSearcher(reader); 
 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36); 
 QueryParser parser = new QueryParser(Version.LUCENE_36, field, analyzer); 
 Query query = parser.parse("Cloud Computing"); //搜索关键词“Cloud Computing” 
 searcher.search(query, null, 100); 
 TopDocs results = searcher.search(query, 10); //只取排名前10的搜索结果 
 ScoreDoc[] hits = results.scoreDocs; 
 Document doc = null; 
 for (int i = start; i < end; i++) { 
     doc = searcher.doc(hits[i].doc); 
     String path = doc.get("path"); 
     long modifiedtime = doc.get("modified"); 
     String contents = doc.get("contents"); 
 } 
 searcher.close(); 
 reader.clos
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s