本文部分内容来自:http://www.ibm.com/developerworks/cn/java/j-lo-lucene1/ 原文链接
一、Lucene 软件包分析
Lucene 软件包里面的主要的 JAVA 包,使读者对之有个初步的了解:
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 , IndexSearcher 定义了在指定的索引上进行搜索的方法。
二、建立索引
为了对文档进行索引,Lucene 提供了五个基础的类,他们分别是 Document, Field, IndexWriter, Analyzer, Directory。下面我们分别介绍一下这五个类的用途:
Document
Document 是用来描述文档的,这里的文档可以指一个 HTML 页面,一封电子邮件,或者是一个文本文件。一个 Document
对象由多个 Field 对象组成的。可以把一个 Document 对象想象成数据库中的一个记录,而每个 Field 对象就是记录的一个字段。
Field
Field 对象是用来描述一个文档的某个属性的,比如一封电子邮件的标题和内容可以用两个 Field 对象分别描述。
Analyzer
在一个文档被索引之前,首先需要对文档内容进行分词处理,这部分工作就是由 Analyzer 来做的。Analyzer
类是一个抽象类,它有多个实现。针对不同的语言和应用需要选择适合的 Analyzer。Analyzer 把分词后的内容交给
IndexWriter 来建立索引。注意:在分词时,如果用来进行索引的文档内容不是纯文本形式,首先得转换成纯文本形式才能再进行操作。还有对同一索引,用来分词建立索引的分词器与用来进行查询的分词器必须是同一个,这样才能保证能得到正确的查询结果。
IndexWriter
IndexWriter 是 Lucene 用来创建索引的一个核心的类,他的作用是把一个个的 Document 对象加到索引中来。
Directory
这个类代表了 Lucene 的索引的存储的位置,这是一个抽象类,它目前有两个实现,第一个是 FSDirectory,它表示一个存储在文件系统中的索引的位置。第二个是 RAMDirectory,它表示一个存储在内存当中的索引的位置。
图1描述了这五个类在建立索引时所扮演的作用:
为了更进一步的理解lucene建立索引的过程,请仔细读下图:
一个简单的示例如下所示,运行此程序需要lucene核心jar和junit4jar包:
import static org.junit.Assert.*;
public class IndexingTest {
protected String[] ids = { "1", "2" };
protected String[] unindexed = { "Netherlands", "Italy" };
protected String[] unstored = { "Amsterdam has lots of bridges",
"Venice has lots of canals" };
protected String[] text = { "Amsterdam", "Venice" };
// 保存索引的目录
private Directory directory;
@Before
public void setUp() throws Exception {
directory = new RAMDirectory();
IndexWriter writer = getWriter();
for (int i = 0; i < ids.length; i++) {
Document doc = new Document();
//将Field 对象加入到 Document 对象中
//Field传入四个参数,第一个参数为Field(字段)的名字(name - The name of the field)
//第二个参数为用来进行处理的文本信息(value - The string to process)
//第三个参数为表示此文本信息是否要存储在索引中(store - Whether value should be stored in the index)
//第四个参数表示这个字段是否要被索引(index - Whether the field should be indexed, and if so, if it should be tokenized before indexing)
//存储此文本,且直接索引,不经过分词器
doc.add(new Field("id", ids[i], Field.Store.YES,
Field.Index.NOT_ANALYZED));
//此文本只存储,不索引
doc.add(new Field("country", unindexed[i], Field.Store.YES,
Field.Index.NO));
//此文本不存储,但通过分词器进行索引
doc.add(new Field("contents", unstored[i], Field.Store.NO,
Field.Index.ANALYZED));
//此文本存储,同时通过分词器进行索引
doc.add(new Field("city", text[i], Field.Store.YES,
Field.Index.ANALYZED));
//用 IndexWriter 类的 add 方法加入到索引中去。这样我们便完成了索引的创建
writer.addDocument(doc);
}
writer.close();
}
private IndexWriter getWriter() throws IOException {
return new IndexWriter(directory, new WhitespaceAnalyzer(),
IndexWriter.MaxFieldLength.UNLIMITED);
}
@Test
public void testIndexWriter() throws IOException {
IndexWriter writer = getWriter();
assertEquals(ids.length, writer.numDocs());
writer.close();
}
@Test
public void testIndexReader() throws IOException {
IndexReader reader = IndexReader.open(directory);
assertEquals(ids.length, reader.maxDoc());
assertEquals(ids.length, reader.numDocs());
reader.close();
}
}
三、搜索文档
利用Lucene进行搜索就像建立索引一样也是非常方便的。Lucene提供了几个基础的类来完成这个过程,它们分别是IndexSearcher, Term,
Query, TermQuery, TopDocs. 下面我们分别介绍这几个类的功能。
Query
这是一个抽象类,他有多个实现,比如TermQuery, BooleanQuery, PrefixQuery. 这个类的目的是把用户输入的查询字符串封装成Lucene能够识别的Query。
Term
Term是搜索的基本单位,一个Term对象有两个String类型的域组成,与Field对象非常的相似。生成一个Term对象可以用如下一条语句来完成:Term
term = new Term(“fieldName”,”queryWord”);
其中第一个参数代表了要在文档的哪一个Field上进行查找,第二个参数代表了要查询的关键词。它一般结合TermQuery一起使用,如下所示:
Query q = new TermQuery(new Term("contents", "lucene"));
TopDocs hits = searcher.search(q, 10);
上面的这段代码表明了lucene将查询document对象包含为名为contents的Field对象,且contents对象中包含有lucene这个字符串的前十个document对象,然后降序排列这十个document对象。
TermQuery
TermQuery是抽象类Query的一个子类,它同时也是Lucene支持的最为基本的一个查询类。生成一个TermQuery对象由如下语句完成:
TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”));
它的构造函数只接受一个参数,那就是一个Term对象。
IndexSearcher
IndexSearcher是用来在建立好的索引上进行搜索的。它只能以只读的方式打开一个索引,所以可以有多个IndexSearcher的实例在一个索引上进行操作。一种很曲型的使用方式如下所示:
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();
在上面的程序中,类IndexSearcher的构造函数接受一个类型为Directory的对象,Directory是一个抽象类,它目前有两个子类:FSDirctory和RAMDirectory. 我们的程序中传入了一个FSDirctory对象作为其参数,代表了一个存储在磁盘上的索引的位置。构造函数执行完成后,代表了这个 IndexSearcher以只读的方式打开了一个索引。然后我们程序构造了一个Term对象,通过这个Term对象,我们指定了要在文档的内容中搜索包含关键词”lucene”的文档。接着利用这个Term对象构造出TermQuery对象并把这个TermQuery对象传入到 IndexSearcher的search方法中进行查询,返回的结果保存在TopDocs对象中。
TopDocs
TopDocs是用来保存搜索的结果的。
一个索引和查询的综合示例,此示例只处理简单的txt文件,HelloWorld程序如下:
public class HelloWorld {
String filePath = ".\\luceneDatasource\\IndexWriter addDocument's a javadoc .txt";
String indexPath = ".\\luceneIndex";
//使用lucene标准的分词器
Analyzer analyzer = new StandardAnalyzer();
/**
* 创建索引
*
* IndexWriter 是用来操作(增、删、改)索引库的
*/
@Test
public void createIndex() throws Exception {
// file --> doc
Document doc = File2DocumentUtils.file2Document(filePath);
// 建立索引
// 我们注意到类 IndexWriter 的构造函数中传入的四个参数,第一个参数指定了所创建的索引要存放的位置,他可以是一个 File
// 对象,也可以是一个 FSDirectory 对象或者 RAMDirectory 对象。
// 第二个参数指定了 Analyzer 类的一个实现,也就是指定这个索引是用哪个分词器对文挡内容进行分词。
// 第三个参数是一个布尔型的变量,如果为 true 的话就代表创建一个新的索引,为 false 的话就代表在原来索引的基础上进行操作。
// 第四个参数是一个IndexWriter.MaxFieldLength,表示Field(字段)中的term/token(令牌)的数目,它有UNLIMITED(它的值为2147483647,表示没有限制),LIMITED(值为10000)两个已定义的值,
//也可new一个新对象,如:new IndexWriter.MaxFieldLength(2000),表示最大数目是2000个
IndexWriter indexWriter = new IndexWriter(indexPath, analyzer, true,
MaxFieldLength.LIMITED);
//最后把document用 IndexWriter 类的 add 方法加入到索引中去。
indexWriter.addDocument(doc);
indexWriter.close();
}
/**
* 搜索
*
* IndexSearcher 是用来在索引库中进行查询的
*/
@Test
public void search() throws Exception {
String queryString = "document";
//String queryString = "adddocument";
// 1,把要搜索的文本解析为 Query
//在名为name和content的字段中搜索queryString
String[] fields = { "name", "content" };
QueryParser queryParser = new MultiFieldQueryParser(fields, analyzer);
Query query = queryParser.parse(queryString);
// 2,进行查询
IndexSearcher indexSearcher = new IndexSearcher(indexPath);
//Filter暂进不使用
Filter filter = null;
TopDocs topDocs = indexSearcher.search(query, filter, 10000);
System.out.println("总共有【" + topDocs.totalHits + "】条匹配结果");
// 3,打印结果
for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
int docSn = scoreDoc.doc; // 文档内部编号
Document doc = indexSearcher.doc(docSn); // 根据编号取出相应的文档
File2DocumentUtils.printDocumentInfo(doc); // 打印出文档信息
}
}
}
File2DocumentUtils 类如下所示:
public class File2DocumentUtils {
// 文件:name, content, size, path
public static Document file2Document(String path) throws IOException {
File file = new File(path);
//并为每一个文本文档创建了一个 Document 对象
Document doc = new Document();
doc.add(new Field("name", file.getName(), Store.YES, Index.ANALYZED));
doc.add(new Field("content", readFileContent(file), Store.YES, Index.ANALYZED));
doc.add(new Field("size", NumberTools.longToString(file.length()), Store.YES, Index.NOT_ANALYZED));
doc.add(new Field("path", file.getCanonicalPath(), Store.YES, Index.NOT_ANALYZED));
return doc;
}
/**
* 读取文件内容
*/
public static String readFileContent(File file) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
StringBuffer content = new StringBuffer();
for (String line = null; (line = reader.readLine()) != null;) {
content.append(line).append("\n");
}
return content.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* <pre>
* 获取 name 属性的值的两种方法:
* 1,Field f = doc.getField("name");
* f.stringValue();
* 2,doc.get("name");
* </pre>
* 打印Document信息
* @param doc
*/
public static void printDocumentInfo(Document doc) {
// Field f = doc.getField("name");
// f.stringValue();
System.out.println("------------------------------");
System.out.println("name = " + doc.get("name"));
System.out.println("content = " + doc.get("content"));
System.out.println("size = " + NumberTools.stringToLong(doc.get("size")));
System.out.println("path = " + doc.get("path"));
}
}
在此项目中的luceneDataSource下有一个名为:IndexWriter addDocument's a javadoc .txt的文本文件,内容如下所示:
Adds room a document to this room index. If the room document contains room more than setMaxFieldLength(int) terms for a given field, the remainder are discarded.
room
1.当搜索程序搜索document时,程序运行结果如下所示,因为在content(文本内容)中有document这个词.
总共有【1】条匹配结果
------------------------------
name = IndexWriter addDocument's a javadoc .txt
content = Adds room a document to this room index. If the room document contains room more than setMaxFieldLength(int) terms for a given field, the remainder are discarded.
room
size = 169
path = E:\datas\MyEclipseWorkspace\LuceneDemo\luceneDataSource\IndexWriter addDocument's a javadoc .txt
2.当搜索程序搜索adddocument时,程序运行结果如下所示,因为在name(文本标题)中有addDocument's这个词,而标准分词器StandardAnalyzer对文本文件标题进行分词,首先会得到addDocument's,然后将里面的大写D转化为小写,最后再进行形态还原就能得到adddocument,所以也能得到一条记录结果,如下所示:
总共有【1】条匹配结果
------------------------------
name = IndexWriter addDocument's a javadoc .txt
content = Adds room a document to this room index. If the room document contains room more than setMaxFieldLength(int) terms for a given field, the remainder are discarded.
room
size = 169
path = E:\datas\MyEclipseWorkspace\LuceneDemo\luceneDataSource\IndexWriter addDocument's a javadoc .txt
看到上面的内容,有人肯定会想,那进行索引时,将addDocument's索引成了adddocument那么我搜索addDocument或addDocument's能否同样得到一条记录呢,答案是肯定的.因为你索引和搜索是使用的是同一个分词器,所以进行搜索时,也会将你的搜索文本addDocument's转化为adddocument.
附件是整个项目工程文件,是基于MyEclipse的,你只要将其导入MyEclipse的项目空间中就可以使用的,虽然是一个java project工程,我为了大家的方便,已把lucene的核心jar包加入到的工程,你不用再为其导入这些jar,只需把junit4 lib导入即可使用.
- 大小: 17.4 KB
- 大小: 37.8 KB
分享到:
相关推荐
创建一个indexwriter // 1)指定索引库的存放位置Directory对象 // 2)指定一个分析器,对文档内容进行分析 Directory directory = FSDirectory.open(new File("D:\\temp\\index")); Analyzer analyzer = ...
首先,建立索引是Lucene工作流程中的第一步。索引是Lucene为了快速查找文档而创建的一种数据结构。在Lucene 3.5中,我们通常会使用`IndexWriter`类来创建或更新索引。这个过程包括读取源文档,使用分词器(Analyzer...
描述中的“asp.net 所需要的 lucene.net 的一些 *.dll 应用程序扩展”指的是开发者可能需要下载并引用 Lucene.NET 的相关 DLL 文件,这些文件包含 Lucene.NET 的核心库以及可能的第三方扩展。这些 DLL 文件是将 ...
第一版发布之后,由于其内容的全面性和实用性,获得了广泛的好评,因此第二版的推出对于希望学习最新版本Lucene的读者来说非常有价值。 ### 描述知识点: 描述中提到的“有很多简单明了的demo”,指的是这本书中...
第1部分Lucene的核心,着重于Lucene的核心API介绍,并按照把Lucene集成到程序中的顺序宋组织;第2部分Lucene的应用,通过对Lucene内置工具的介绍,展示了Lucene技术的高级应用和在各种程序语言上的移植。. 本书既可...
《Lucene实战 第2版 》基于Apache的Lucene 3 0 从Lucene核心 Lucene应用 案例分析3个方面详细系统地介绍了Lucene 包括认识Lucene 建立索引 为应用程序添加搜索功能 高级搜索技术 扩展搜索 使用Tika提取文本 Lucene...
第1部分lucene的核心 着重于lucene的核心 api介绍 并按照把lucene集成到程序中的顺序宋组织;第2部分lucene的应用 通过对lucene内置工具的介绍 展示了lucene技术的高级应用和在各种程序语言上的移植 本书既可作为...
【标题】:“第一个Lucene 3.6 (3.X) 入门实例” 【内容详解】 Lucene是一个高性能、全文本搜索库,由Apache软件基金会开发。它为Java开发者提供了强大的文本检索功能,广泛应用于搜索引擎、信息检索系统等场景。...
它提供了一个简单但功能强大的API,用于索引和搜索文本数据,使得开发者可以轻松地在应用程序中实现复杂的全文检索功能。 ### 一、Lucene基本概念 1. **索引**:Lucene首先对文本进行索引,将文本内容转换为一系列...
Lucene是一个开源的Java库,它提供了一个高级的文本搜索程序接口,可以方便地集成到各种应用程序中。Lucene的核心功能包括文档索引、查询解析、评分以及结果排序。通过这本书,读者可以学习如何使用Lucene进行文本...
《Lucene实战(第2版)》基于Apache的Lucene 3.0,从Lucene核心、Lucene应用、案例分析3个方面详细系统地介绍了Lucene,包括认识Lucene、建立索引、为应用程序添加搜索功能、高级搜索技术、扩展搜索、使用Tika提取文本...
标题"第一个lucene的简单实例...." 暗示我们将要讨论的是如何使用Apache Lucene库创建一个基础的全文搜索引擎。Lucene是一个开源的Java库,用于构建高性能、可扩展的信息检索应用程序。这个"简单实例"可能是针对初学...
Lucene是一个流行的全文检索库,由Apache软件基金会开发,它提供了一个强大的索引和搜索功能。在处理中文文档时,Lucene需要一个分词器(Tokenizer)来对输入的文本进行分词,以便后续的索引和查询操作。基于词典的...
Apache Lucene是一个高性能、可伸缩的全文检索引擎库,它是完全用Java写成的,并作为Apache软件基金会的一个开源项目。Lucene可用于为应用程序添加全文搜索功能。全文搜索不同于简单的关键词匹配,它能够在数据中...
根据提供的信息,“Lucene实战中文版第2版.pdf”似乎是一本关于Apache Lucene的实践指南书籍。由于具体内容部分没有提供实际的章节或段落文本,我们只能基于标题、描述和标签来推断这本书可能涉及的关键知识点。下面...