什么是Lucene?
Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引和查询索引,以及部分文本分析的引擎,Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎,Lucene在全文检索领域是一个经典的祖先,现在很多检索引擎都是在其基础上创建的,思想是相通的。
即:Lucene是根据关健字来搜索的文本搜索工具,只能在某个网站内部搜索文本内容,不能跨网站搜索
Lucene通常用在什么地方?
Lucene通常用在站内搜索中,例如:
Lucene在MVC的位置是dao层
Lucene存的是什么内容?
Lucene中存的就是一系列的二进制压缩文件和一些控制文件,它们位于计算机的硬盘上,
这些内容统称为索引库,索引库有二部份组成:
(1)原始记录
存入到索引库中的原始文本,例如:中国好室友,没错,正是在下
(2)词汇表
按照一定的拆分策略(即分词器)将原始记录中的每个字符拆开后,存入一个供将来搜索的表
为何网站的内部搜索要使用Lucene而不使用SQL?
(1)SQL只能针对数据库表搜索,不能直接针对硬盘上的文本搜索
(2)SQL没有相关度排名
(3)SQL搜索结果没有关健字高亮显示
(4)SQL需要数据库的支持,数据库本身需要内存开销较大,例如:Oracle
(5)SQL搜索有时较慢,尤其是数据库不在本地时,超慢,例如:Oracle
如何使用?
流程如下:
创建索引库:
1) 创建JavaBean对象
2) 创建Docment对象
3) 将JavaBean对象所有的属性值,均放到Document对象中去,属性名可以和JavaBean相同或不同
4) 创建IndexWriter对象
5) 将Document对象通过IndexWriter对象写入索引库中
6) 关闭IndexWriter对象
根据关键字查询索引库中的内容:
1) 创建IndexSearcher对象
2) 创建QueryParser对象
3) 创建Query对象来封装关键字
4) 用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准
5) 获取符合条件的编号
6) 用indexSearcher对象去索引库中查询编号对应的Document对象
7) 将Document对象中的所有属性取出,再封装回JavaBean对象中去,并加入到集合中保存,以备将之用
下面就来开始第一个Lucene的案例吧
首先引入jar包,jar包可以直接去apache的官网下载
我们将以下jar包引入
首先创建一个Article对象
package cn.qblank.lucene;
/**
* 文章
* @author Administrator
*
*/
public class Article {
private Integer id;
private String title;
private String content;
public Article(){}
public Article(Integer id, String title, String content) {
super();
this.id = id;
this.title = title;
this.content = 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;
}
@Override
public String toString() {
return "编号:" + id + "\n标题:" + title + "\n内容:" +content;
}
}
然后创建一个索引库,将相应的内容存入进去
public void createIndexDB() throws IOException {
//1.创建文章对象
Article article = new Article(2, "中国好室友", "中国好室友,没错,正是在下");
//2.创建document对象
Document document = new Document();
//3.将Aracle中的属性词绑定到document对象中
/*
* 参数一:document中的属性名叫xid,article对象中的属性名是id,一般docuemnt属性名是在实体类的属性名前面加个x
* 参数二:document对象中属性名的值,与article对象中相同
* 参数三:是否将(xid)属性值存入由原始记录表中的转存入词汇表中
* Store.YES表示会存入词汇表
* Store.No表示不会存入词汇表
* 参数四: 是否将(xid)属性值进行分词算法
* Index.ANALYZED表示该属性值会进行词汇拆分
* Index.NOT_ANALYZED表示不进行拆分(提倡非id值都进行拆分)
*/
document.add(new Field("xid", article.getId().toString(), Store.YES,Index.NOT_ANALYZED));
document.add(new Field("xtitle", article.getTitle(), Store.YES,Index.ANALYZED));
document.add(new Field("xcontent", article.getContent(), Store.YES,Index.ANALYZED));
//最多将文本拆分出多少个词汇,LIMITED表示1w个,即只取前1w个词汇,如果不足1w个词汇,以实际为准
MaxFieldLength maxFieldlength = MaxFieldLength.LIMITED;
//Lucene索引库最终存入硬盘中的目录,例如:F:/LuceneDB
FSDirectory directory = FSDirectory.open(new File("F:/LuceneDB"));
//采用的分词策略
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
//4.创建IndexWriter对象
IndexWriter indexWriter = new IndexWriter(directory, analyzer, maxFieldlength);
//将document写入Lucene索引库
indexWriter.addDocument(document);
//5.关闭IndexWriter
indexWriter.close();
}
这时候,就会在F:/Lucene的目录下创建相应的文件,如果没有这个文件夹,将会自动创建
这样,一个Lucene索引库就创建好了,接下来我们就来查询一下
public static void findIndexDB() throws Exception{
//准备输入的值
String keywords = "好";
//创建Article对象的集合
ArrayList<Article> arrayList = new ArrayList<Article>();
//Lucene索引库的目录
FSDirectory directory = FSDirectory.open(new File("F:/LuceneDB"));
//采用的分词策略
Version version = Version.LUCENE_30;
Analyzer analyzer = new StandardAnalyzer(version);
//1.创建IndexSearcher自符流对象
IndexSearcher indexSearcher = new IndexSearcher(directory);
//2.创建查询解析器
/*
* 参数一: 使用分词器的版本
* 参数二: 对document的属性进行搜索
*/
QueryParser queryParser = new QueryParser(version,"xcontent", analyzer);
//3.创建Query对象封装查询的关键字
Query query = queryParser.parse(keywords);
//根据关键字去索引里面搜索
/*
* 参数一: 表示关键字查询对象,其他QueryParser表示查询器
* 参数二: MAX_RECORD表示如果根据关键字搜索出来的字段较多,只取前MAX_RECORD个内容,不足MAX_RECORD个的话,以实际为准
*/
int MAX_RECORD = 100;
//使用indexSearcher查询前MAX_RECORD调记录
TopDocs topDocs = indexSearcher.search(query, MAX_RECORD);
//4.迭代出词汇表中符合条件的编号
for (int i = 0; i < topDocs.scoreDocs.length; i++) {
//取出封装编号和分数的ScoreDoc对象
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
//取出每一个编号
int no = scoreDoc.doc;
//5.根据编号去原始记录表中查询对应的document对象
Document document = indexSearcher.doc(no);
//获取document的属性值
String xid = document.get("xid");
String xtitle = document.get("xtitle");
String xcontent = document.get("xcontent");
//6.封装到对象中
Article article = new Article(Integer.parseInt(xid), xtitle, xcontent);
//添加到集合中
arrayList.add(article);
}
//遍历出来
for (Article article : arrayList) {
System.out.println("---------");
System.out.println(article);
}
indexSearcher.close();
}
运行结果如下: