Lucene创建和查询索引库的HelloWorld(含详细注释)

来源:互联网 发布:淘宝优惠券小程序制作 编辑:程序博客网 时间:2024/05/24 06:22

本案例使用的是Lucene-3.6.2版本,Lucene官方网站:http://lucene.apache.org/。

案例说明:

本例模拟了贴吧中检索帖子的功能,通过创建Article类来模拟帖子对象。用户输入检索信息,Lucene就可以根据检索信息来获取与之相关的Article对象,并返回给用户。

一、建立工程

首先在我们的MyEclipse中创建一个Java工程即可,在里面创建一个lib文件夹用于存放我们开发时用的jar包。


二、导入jar包

本案例需要Lucene的4个基本jar包。如下:

    lucene-core-3.6.2.jar

    contrib\analyzers\common\lucene-analyzers-3.6.2.jar(分词器)

    contrib\highlighter\lucene-highlighter-3.6.2.jar(高亮)

    contrib\memory\lucene-memory-3.6.2.jar(高亮)

然后将lib中的四个jar包Build Path。


三、创建HelloWorld类

在src下自创建一个包,并在包中创建HelloWorld.java文件。

这个文件中不需要main函数,我们将通过jUnit来测试程序。

所以在我们的方法中需要添加@Test注解。

public class HelloWorld {//创建索引库@Testpublic void createIndex() {}//搜索索引库@Testpublic void seacherIndex() {}}

四、创建检索类PO

创建我们需要检索的类Article(模拟帖子对象),里面有三个字段:id,title,content,

分别表示:编号、标题、内容。

public class Article {private Integer id;//idprivate String title;//标题private String content;//内容public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String toString() {return "Article [id=" + id + ", title=" + title + ", content="+ content + "]";}}

五、编写HelloWorld,实现创建和查询索引库

这里需要记住创建和查询的两个核心API:

向索引库中增删改的时候,使用IndexWriter对象。

   其主要方法为:addDocument()、updateDocument()、deleteDocument()。

从索引库中搜索的时候,使用IndexSearcher对象。

   其主要方法为:search()

里面的一些API的体系结构图会在最后的附件中列出,可对照查看。

程序中的步骤是按照编号走的,由于需要准备各种参数,所以显得有些凌乱,只要按照步骤参考即可。

import java.io.File;import java.io.IOException;import java.util.ArrayList;import java.util.List;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.Index;import org.apache.lucene.document.Fieldable;import org.apache.lucene.document.Field.Store;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.MultiFieldQueryParser;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.util.Version;import org.junit.Test;import lucene.a_domain.Article;public class HelloWorld {//创建索引库/** * 执行这个方法会将这个方法中创建的Article对象中的属性:id,title,content转换成Document字段, * 索引库中只能存放Document类型对象,不能存放我们创建的对象,将Article转成Document后, * 通过IndexWriter的addDocument方法将转换后的Document对象添加到索引库中, * 执行这个方法后,将会在指定的索引库目录中创建索引文件,这是一堆二进制文件。 * 因为用到了IO,所以最后需要将IndexWriter关闭。 * @throws Exception */@Testpublic void createIndex() throws Exception {/* * 2.创建索引库目录,这是IndexWriter构造器的第一个参数。 * 这个Directory是个抽象类,按住ctrl+t可以查看这个类的继承体系, * 会发现他有一个子抽象类,叫做FSDirectory, * 我们需要使用这个类的实例当作我们的Directory, * 但他是抽象的,无法new, * FSDirectory里面有一个open方法, open方法接收一个File, * 这个open方法就可以获取FSDirectory实例, * 而File是我们指定的存放目录的路径,在当前工程创建一个indexDir文件夹作为路径即可, * 至此,索引库目录配置完成,将这个引用添加到IndexWriter的第一个参数的位置。 */Directory directory = FSDirectory.open(new File("./indexDir/"));/* * 4.创建IndexWriterConfig构造器的第二个参数,analyzer分词器。 * 这个Analyzer也是一个抽象类,ctrl+t查看其继承体系可以发现它有很多子类。 * 这里先使用它的标准分词器,StandardAnalyzer。 * new这个类需要一个版本号参数,同样通过Version的静态常量给出。 * 分词器创建完成。添加到IndexWriterConfig的第二个参数上。 */Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);/* * 3.创建IndexWriter构造器的第二个参数,配置。 * 直接new,发现报错,它的构造器需要两个参数, * 一个是Version,一个是Analyzer, * Version通过Version.LUCENE_36即可创建,这时Version类中的一个静态常量。 * Analyzer是分词器,这是Lucene自带的分词器,这个分词器不支持中文 */IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36,analyzer);//1.这里需要两个参数,第一个是索引库目录,第二个是配置,在上面提供这两个参数即可IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig);/* * 6.创建要存入索引库的对象Article, * 创建完成后,我们需要将Article中的属性转换成Document的字段 */Article article = new Article();article.setId(1);article.setTitle("Lucene是什么");article.setContent("Lucene,速度快捷方式离开减肥啦实际得分卡设计大方");/* * 7.将Article转换成Document对象, * 需要将Article中的属性转换成Document的字段 * 直接new一个Document,再通过Document的add方法添加字段, * add方法需要一个Fieldable类型的参数,Fieldable是一个接口, */Document doc = new Document();/* * 8.创建Fieldable的子类,ctrl+t查看继承体系,发现有个Field子类 * 创建Field需要四个参数,String name,String value,Store store,Index index * 第一个参数表示索引库的字段名称; * 第二个参数表示存放到该字段上的值; * 第三个参数表示是否存储 * 第四个参数表示分词 * 在add方法里直接new,Article有三个属性,需要添加三个字段到Document中,所以add三次 *///Fieldable field = new Field("id",article.getId().toString(),Store.YES,Index.ANALYZED);doc.add(new Field("id",article.getId().toString(),Store.YES,Index.ANALYZED));doc.add(new Field("title", article.getTitle(), Store.YES, Index.ANALYZED));doc.add(new Field("content", article.getContent(), Store.YES, Index.ANALYZED));/* * 5.创建索引库,使用IndexWriter的addDocument方法。 * 这个方法需要一个Document参数。这个Document就是放入索引库的数据, * 但是我们需要放入的是Article对象,这就需要将我们的Article类型转换成Document类型。 */indexWriter.addDocument(doc);/* * 9.关闭流 */indexWriter.close();}//搜索索引库/** * 搜索索引库时,开始先创建了一个List集合来存储最终查询的结果。 * 这个程序中,将查询条件写死了,真正开发的时候是不可能写死的,所以开发时这个查询条件是需要获取的。 * 根据查询条件就可以从索引库的到最终的结果集,但是索引库中存放的是Document对象,所以获取的结果集也是Document对象集合。 * 还需要将Document对象转换成我们需要的Article对象,根据document对象的get方法获取即可,get(name)参数为字段名称。 * 最后我们调用了showResults(List list)方法将获取的结果集遍历取出,显示在控制台上。 * @throws Exception */@Testpublic void seacherIndex() throws Exception {//创建一个集合,存放查询出来的数据。List<Article> list = new ArrayList<Article>();/* * 2.创建索引库目录,指定索引库目录路径,提供给IndexSearcher */Directory directory = FSDirectory.open(new File("./indexDir/"));/* * 1.创建IndexSearcher对象,这个对象的构造器需要接收一个IndexReader对象 * 这个IndexReader是一个抽象类,它里面有一个抽象方法:open。 * open方法的参数是Directory,即索引库目录,需要指定它从那个索引库目录中读取数据。 * 在上面创建这个目录,跳到第2步。 */IndexSearcher indexSearcher = new IndexSearcher(IndexReader.open(directory));/* * 4.创建查询条件 * QueryParser只能指定在一个字段上进行检索,例如如果指定了id字段就只能查询id字段。是单字段检索。 * QueryParser有三个参数, * 参数1:版本 * 参数2:表示对哪个字段进行检索,这里传入一个字段名称 * 参数3:分词器 * 这里查询条件是"Lucene"表示在某个字段中查询"Lucene"。 */String queryString = "Lucene";//6.准备分词器:Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);//5.创建解析器QueryParser queryParser = new QueryParser(Version.LUCENE_36,"title",analyzer);//7.将查询条件放入解析器中。这里返回的是query对象,这个对象作为IndexSearcher的search方法的第一个参数Query query = queryParser.parse(queryString);/* * 3.通过IndexSearcher的search方法创建查询 * 参数1:表示查询条件 * 参数2:表示返回的前多少条记录 * search返回值为TopDocs类型,这是查询完的结果集。 */TopDocs topDocs = indexSearcher.search(query, 100);System.out.println("总记录数:" + topDocs.totalHits);//这个字段获取查询到的总记录数。//8.获取结果集数组ScoreDoc[] scoreDocs = topDocs.scoreDocs;//遍历scoreDocs,if(scoreDocs!=null && scoreDocs.length>0) {for (int i = 0; i < scoreDocs.length; i++) {ScoreDoc scoreDoc = scoreDocs[i];System.out.println("获取这个记录的得分:" + scoreDoc.score);//获取检索出的记录在索引库中的唯一编号,根据这个编号就可以获取需要的数据int doc = scoreDoc.doc;//IndexSearcher的doc方法可以通过刚获取的唯一编号从索引库中获取我们需要的数据Document document = indexSearcher.doc(doc);//获取了Document对象,还需要将Document对象转成Article对象。Article article = new Article();/* * 通过document对象的get方法,根据字段名称获取值, * 这里的名称是通过上面的 * doc.add(new Field("id",article.getId().toString(),Store.YES,Index.ANALYZED)); * 这个方法设置的字段名称 */article.setId(Integer.parseInt(document.get("id")));article.setTitle(document.get("title"));article.setContent(document.get("content"));//添加到存放结果的集合中。list.add(article);}}//9.关闭流indexSearcher.close();//10.遍历输出最终获取的结果集合if(list != null && list.size() > 0) {showResults(list);}}private void showResults(List<Article> list) {for(Article article : list) {System.out.println("文章编号:" + article.getId());System.out.println("文章标题:" + article.getTitle());System.out.println("文章内容:" + article.getContent());System.out.println("------------------------------------------------");}}}
先执行createIndex方法,这样我们先建立的索引库就有数据了,然后再执行seacherIndex方法,就可以将索引库获取的数据显示在控制台上。


六、查看索引库中生成的文件

我们将索引库定义在了工程的根目录下:


进入这个目录,可以看到生成的文件,这都是一些二进制文件。


七、附件

这里提供了一些类的继承体系信息。

Directory类:


Analyzer类:



2 0
原创粉丝点击