Lucene初步应用

先来一段百度百科解答:

Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供。Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在Java开发环境里Lucene是一个成熟的免费开源工具。就其本身而言,Lucene是当前以及最近几年最受欢迎的免费Java信息检索程序库。人们经常提到信息检索程序库,虽然与搜索引擎有关,但不应该将信息检索程序库与搜索引擎相混淆

再来开始该博文的主要内容咯—如何使用Lucene咯

1、所需资源:

a、lucene-4.4.0.zip下的三个jar包:lucene-core-4.4.0.jar、lucene-queryparser-4.4.0.jar、lucene-analyzers-common-4.4.0.jar

b、IK Analyzer 2012FF_hf1.zip(庖丁分词器)下的一个包:IKAnalyzer2012FF_u1.jar

c、jdk运行环境

d、Eclipse运行环境

2、建立Java Project,并将所需的4个jar包导入

3、庖丁分词器需要配置的三个文件:

a、IKAnalyzer.cfg.xml

文本内容:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE properties SYSTEM “http://java.sun.com/dtd/properties.dtd”>  
<properties>  

    <comment>IK Analyzer 扩展配置</comment>
    <!–在这里配置自己的扩展字典–>
    <entry key=”ext_dict”>mydict.dic;</entry>
    
     <!–在这里配置自己的扩展停止词字典–>
    <entry key=”ext_stopwords”>ext_stopword.dic</entry>

</properties>

 

b、mydict.dic;

文本内容:

且行且珍惜

c、ext_stopword.dic(可自行填加)

文本内容:






使



4、创建工具类(1)LuceneUtils,负责获取IndexWriter和IndexSearcher

首先需要创建接口类,存放常量

package top.einino.utils;

public interface Constant {

    //在这目录下存放创建的索引
    public static final String INDEX_DIR = “G:\\java\\index”;

}

 

package top.einino.utils;

import java.io.File;
import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class LuceneUtils {

    
    public static Directory directory = null;
    public static IndexWriterConfig indexWriterConfig = null;
    public static Version matchVersion = null;
    public static Analyzer analyzer = null;
    
    static {

        try {

            //索引写入的目录
            directory = FSDirectory.open(new File(Constant.INDEX_DIR));
            //Lucene的版本号
            matchVersion = Version.LUCENE_44;
            //使用庖丁分词器
            analyzer = new IKAnalyzer();
            //索引写入的配置
            indexWriterConfig = new org.apache.lucene.index.IndexWriterConfig(matchVersion, analyzer);

        } catch (IOException e) {
            e.printStackTrace();
        }

        
    }
    
    public static IndexWriter getIndexWriter() throws IOException{

        
        //创建索引类
        IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
        return indexWriter;

        
    }
    
    
    public static IndexSearcher getIndexSearcher() throws IOException{

        //读取索引目录类
        IndexReader indexReader = DirectoryReader.open(directory);
        //创建索引类
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);
        return indexSearcher;

        
    }
    
    //方便引用
    public static Version getMatchVersion() {

        return matchVersion;

    }
    //方便引用
    public static Analyzer getAnalyzer() {

        return analyzer;

    }

}

 

5、创建工具类(2)BlogDocumentUtils,负责pojo对象与document对象的转换

首先需要创建一个pojo对象

package top.einino.bean;

import java.util.Date;

public class Blog {

    private Integer id;
    private String author;
    private String title;
    private String content;
    private Date date;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    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;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    

}

 

package top.einino.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.queryparser.flexible.core.util.StringUtils;

import top.einino.bean.Blog;

public class BlogDocumentUtils {

/**
* 将对象转换成document
* @param blog
* @return
*/
public static Document blogToDocument(Blog blog){

Document document = new Document();
//第一个参数是Blog属性,第二个参数是pojo属性值,第三个参数是是否作为索引存储
if(blog.getId() != null){
document.add(new IntField(“id”, blog.getId(), Store.YES));
}
//StringField不支持分词,表示不再进行分词
if(blog.getAuthor() != null){
document.add(new StringField(“author”, blog.getAuthor(), Store.YES));
}
//StringField支持分词
if(blog.getTitle() != null){
document.add(new TextField(“title”, blog.getTitle(), Store.YES));
}
if(blog.getContent() != null){
document.add(new TextField(“content”, blog.getContent(), Store.YES));
}
if(blog.getDate() != null){
document.add(new StringField(“date”, new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(blog.getDate()), Store.YES));
}
return document;

}
/**
* 将document转换成pojo对象
* @param document
* @return
* @throws ParseException
*/
public static Blog documentToBlog(Document document) throws ParseException{

Blog blog = new Blog();
blog.setId(Integer.parseInt(document.get(“id”)));
blog.setAuthor(document.get(“author”));
blog.setTitle(document.get(“title”));
blog.setContent(document.get(“content”));
blog.setDate(new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).parse(document.get(“date”)));
return blog;

}

}

6、创建LuceneDao,实现增删改查即分页操作

package top.einino.lucene;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.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 top.einino.bean.Blog;
import top.einino.utils.BlogDocumentUtils;
import top.einino.utils.LuceneUtils;

public class LuceneDao {

//添加索引
public void addIndex(Blog blog) throws IOException{

//使用工具类获得索引创建类
IndexWriter indexWriter = LuceneUtils.getIndexWriter();
//使用工具类将blog对象转换成document对象
Document document = BlogDocumentUtils.blogToDocument(blog);
//创建索引
indexWriter.addDocument(document);
//关闭
indexWriter.close();

}

//根据关键词多字段检索索引
public List<Blog> findBlogList(String keyword) throws Exception{

List<Blog> blogList = new ArrayList<Blog>();
//使用工具类创建索引
IndexSearcher indexSearcher = LuceneUtils.getIndexSearcher();
//需要检索字段
String[] fields = {“title”, “content”};
//String[] fields = {“id”};
//创建多字段检索规则,并配置Lucene版本和分词器使用规则、需要跟创建索引时对应上!
QueryParser queryParser = new MultiFieldQueryParser(LuceneUtils.getMatchVersion(), fields, LuceneUtils.getAnalyzer());
//传入检索关键词
Query query = queryParser.parse(keyword);
//第一次检索:主要是检索出索引、获得检索结果,第一个参数是检索规则,第二个参数是获得前100条符合的结果
TopDocs topDocs = indexSearcher.search(query, 100);
//输出总记录数,主要是为了测试
System.out.println(“总记录数:”+topDocs.totalHits);
//获得检索命中结果集
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
if(scoreDocs != null && scoreDocs.length > 0){

for(ScoreDoc scoreDoc : scoreDocs){

//获得存储id
int docId = scoreDoc.doc;
//第二次检索,通过存储id获得document对象
Document document = indexSearcher.doc(docId);
//使用工具类将document对象转换成blog对象
Blog blog = BlogDocumentUtils.documentToBlog(document);
//将blog对象放入 集合中
blogList.add(blog);

}

}
return blogList;

}

//根据关键词多字段检索索引并使用分页,startRow表示起始行,rows表示每页行数
public List<Blog> findBlogListWithPage(String keyword, int startRow, int rows) throws Exception{

List<Blog> blogList = new ArrayList<Blog>();
//使用工具类创建索引
IndexSearcher indexSearcher = LuceneUtils.getIndexSearcher();
//需要检索字段
String[] fields = {“title”, “content”};
//创建多字段检索规则,并配置Lucene版本和分词器使用规则、需要跟创建索引时对应上!
QueryParser queryParser = new MultiFieldQueryParser(LuceneUtils.getMatchVersion(), fields, LuceneUtils.getAnalyzer());
//传入检索关键词
Query query = queryParser.parse(keyword);
//第一次检索:主要是检索出索引、获得检索结果,第一个参数是检索规则,第二个参数是获得前100条符合的结果
TopDocs topDocs = indexSearcher.search(query, 100);
//输出总记录数,主要是为了测试
System.out.println(“总记录数:”+topDocs.totalHits);
//获得检索命中结果集
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
//分页,能遍历到的最终行,但结果集可能没有这么多行
int finalRow = startRow + rows;
//取两者最小值,如果最终行大于结果集数,则只需要遍历到结果集,如果最终行小于结果集,则遍历到最终行
int min = Math.min(finalRow, scoreDocs.length);
if(scoreDocs != null && scoreDocs.length > 0){

for(int i=startRow; i<min; i++){

//获得存储id
int docId = scoreDocs[i].doc;
//第二次检索,通过存储id获得document对象
Document document = indexSearcher.doc(docId);
//使用工具类将document对象转换成blog对象
Blog blog = BlogDocumentUtils.documentToBlog(document);
//将blog对象放入 集合中
blogList.add(blog);

}

}
return blogList;

}
//删除文档,第一个参数为删除的字段名,第二个参数为删除的符合的字段值
public void deleteIndex(String fileName, String fileValue) throws IOException{

IndexWriter indexWriter = LuceneUtils.getIndexWriter();
indexWriter.deleteDocuments(new Term(fileName, fileValue));
indexWriter.commit();
indexWriter.close();

}

//更新文档
public void updateIndex(String fileName, String fileValue, Blog blog) throws IOException {

IndexWriter indexWriter = LuceneUtils.getIndexWriter();
//执行过程:是先删除字段名为fileName,符合fileValue的文档,然后再创建索引文档
indexWriter.updateDocument(new Term(fileName, fileValue), BlogDocumentUtils.blogToDocument(blog));
indexWriter.commit();
indexWriter.close();

}

}

7、创建测试用例TestLuceneDao,可以一边实现方法,一边调测试用例

package top.einino.junit;

import java.io.IOException;
import java.util.Date;
import java.util.List;

import org.junit.Test;

import top.einino.bean.Blog;
import top.einino.lucene.LuceneDao;

public class TestLuceneDao {

private LuceneDao luceneDao = new LuceneDao();
//测试添加索引方法、调用该方法即在G:\\java\\index目录下会生成索引文件
@Test
public void testAddIndex() throws IOException{

//为测试分页
for(int i=1; i<35; i++){

Blog blog = new Blog();
blog.setId(i);
blog.setAuthor(“郑先生”);
blog.setTitle(“Lucene应用”);
blog.setContent(“该博文内容主要是讲如何使用Lucene创建索引,和检索索引”);
blog.setDate(new Date());
luceneDao.addIndex(blog);

}

}

//测试查询检索方法
@Test
public void testFindBlogIndex() throws Exception{

String keyword = “医药应用”;
List<Blog> blogList = luceneDao.findBlogList(keyword);
if(blogList != null && blogList.size() > 0){

for(Blog blog : blogList){

System.out.println(“id:”+blog.getId()
+” author:”+blog.getAuthor()
+” title:”+blog.getTitle()
+” content:”+blog.getContent()
+” date:”+blog.getDate());

}

}

}

//测试分页查询检索方法
@Test
public void testFindBlogIndexWithPage() throws Exception{

String keyword = “Lucene”;
List<Blog> blogList = luceneDao.findBlogListWithPage(keyword, 30, 10);
if(blogList != null && blogList.size() > 0){

for(Blog blog : blogList){

System.out.println(“id:”+blog.getId()
+” author:”+blog.getAuthor()
+” title:”+blog.getTitle()
+” content:”+blog.getContent()
+” date:”+blog.getDate());

}

}

}

//测试删除索引方法
@Test
public void testDeleteIndex() throws IOException{

luceneDao.deleteIndex(“author”, “郑先生”);

}

//测试更新方法
@Test
public void testUpdateIndex() throws IOException{

Blog blog = new Blog();
blog.setId(35);
blog.setAuthor(“张女士”);
blog.setTitle(“医药应用”);
blog.setContent(“医药应用”);
blog.setDate(new Date());
luceneDao.updateIndex(“author”, “郑先生”, blog);

}

}

 

小结一下:

Lucene主要通过IndexWriter创建索引,创建索引时需要配置分词器,决定如何分词创建索引,通过IndexWriter检索索引,检索索引时要配置查询规则,决定如何检索索引。

在学习Lucene,可得用lukeall-4.4.0-ALPHA.jar这样一个jar工具查看生成的整个索引目录,查看分词情况,文档情况等等,方便自己学习与实现lucene方法。

 

 

如果有疑问或者对该博文有何看法或建议或有问题的,欢迎评论,恳请指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值