一) 什么是Lucene?
Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引和查询索引,以及部分文本分析的引擎,Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎,Lucene在全文检索领域是一个经典的祖先,现在很多检索引擎都是在其基础上创建的,思想是相通的。
即:Lucene是根据关健字来搜索的文本搜索工具,只能在某个网站内部搜索文本内容,不能跨网站搜索
二) Lucene通常用在什么地方?
Lucece不能用在互联网搜索(即像百度那样),只能用在网站内部的文本搜索(即只能在CRM,RAX,ERP内部使用),但思想是相通的。如图:
Lucene用在服务端三层结构中的哪一层?
三) Lucene中存的什么内容?
Lucene中存的就是一系列的二进制压缩文件和一些控制文件,它们位于计算机的硬盘上,
这些内容统称为索引库,索引库有二部份组成:
(1)原始记录
存入到索引库中的原始文本,例如:中国是一个伟大的国家
(2)词汇表
按照一定的拆分策略(即分词器)将原始记录中的每个字符拆开后,存入一个供将来搜索的表
Lucene索引库结构与原理图:
四) 为什么网站内部有些地方要用Lucene来索搜,而不全用SQL来搜索?
(1)SQL只能针对数据库表搜索,不能直接针对硬盘上的文本搜索
(2)SQL没有相关度排名
(3)SQL搜索结果没有关健字高亮显示
(4)SQL需要数据库的支持,数据库本身需要内存开销较大,例如:Oracle
(5)SQL搜索有时较慢,尤其是数据库不在本地时,超慢,例如:Oracle
五) 使用Lucene的流程图1.Lucene程序宏观结构
3.Lucene索引库查询的过程
两个重要的类:
图解TopDocs和ScoreDoc这二个类
创建索引库:
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实例准备工作:
导入Lucene相关的jar包
lucene-core-3.0.2.jar【Lucene核心】
lucene-analyzers-3.0.2.jar【分词器】
lucene-highlighter-3.0.2.jar【Lucene会将搜索出来的字,高亮显示,提示用户】
lucene-memory-3.0.2.jar【索引库优化策略】
创建实体类:
public class Article {
private Integer id;//标题
private String title;//标题
private String content;//内容
public Article(){}
public Article(Integer id, String title, String content) {
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;
}
}
/**
* 创建索引库
* 将Article对象放入索引库的原始记录表中,从而形成词汇表
* @throws Exception
*/
@Test
public void createIndexDB() throws Exception{
///创建Article对象
Article article=new Article(1,"中","中国是一个伟大的国家");
//创建Document对象
Document document=new Document();
/**
*
* 参数一:document对象中的属性名叫id,article对象中的属性名叫id,项目中提倡相同
* 参数二:document对象中的属性id,与article对象中相同
* 参数三:是否将id属性值存入由原始记录表中转存入词汇表
* Store.YES表示该属性值会存入原始记录表
* Store.No表示该属性值不会存入原始记录表
* 项目中提倡非id值都存入词汇表
* 参数四:是否将id属性值进行分词算法
* Index.ANALYZED:表示该属性值会进行词汇拆分
* Index.NOT.ANALYZED表示该属性值不会进行词汇拆分
* 项目中提倡非id值都进行词汇拆分
*
*/
document.add(new Field("id",article.getId().toString(),Store.YES,Index.ANALYZED));
document.add(new Field("title",article.getTitle(),Store.YES, Index.ANALYZED));
document.add(new Field("content", article.getContent(), Store.YES, Index.ANALYZED));
//创建IndexWriter字符流
/**
* 参数一:lucene索引库最终应对于硬盘中的目录,例如:E:/indexDB
* 参数二:采用什么策略将文本拆分,一个策略就是一个具体的实现类
* 参数三:最多将文本拆分出多少词汇,LIMITED表示一万个,即只取前一万个词汇,
* 如果不足一万,以实际为主
*/
Directory directory=FSDirectory.open(new File("E:/IndexDB"));
Version version=Version.LUCENE_30;
Analyzer analyzer=new StandardAnalyzer(version);
MaxFieldLength maxFieldLength=MaxFieldLength.LIMITED;
IndexWriter indexWriter=new IndexWriter(directory, analyzer, maxFieldLength);
//将document对象写入lucene索引库
indexWriter.addDocument(document);
indexWriter.close();
}
/**
* 根据关键字从索引库中搜索符合条件的内容
* @throws Exception
*/
@Test
public void findIndexDB() throws Exception{
//准备工作
String keywords="中";
List<Article> articles=new ArrayList<Article>();
Directory directory = FSDirectory.open(new File("E:/IndexDB"));
Version version = Version.LUCENE_30;
Analyzer analyzer=new StandardAnalyzer(version);
MaxFieldLength maxFieldLength = MaxFieldLength.LIMITED;
//创建IndexSearcher字符流对象
IndexSearcher indexSearcher=new IndexSearcher(directory);
//创建查询解析器对象
/**
* 参数一:使用分词器的版本,提倡使用该jar包中的最高版本
* 参数二:针对document对象中的那个属性进行搜索
*/
QueryParser queryParser=new QueryParser(version,"content",analyzer);
Query query = queryParser.parse(keywords);
//根据关键字,去索引库中的词汇表搜索
/**
* 参数一:表示封装关键字查询对象,其他QueryParen表示查询解析器
* 参数二:Max_RECODER:表示如果根据关键字搜索出来的内容较多,只取前MAX_RECORD个内容
* 不足max_reord个数的话,以实际为准
*/
int MAX_RECORD=100;
TopDocs topDocs = indexSearcher.search(query, MAX_RECORD);
//迭代词汇表中符合条件的编号
for(int i=0;i<topDocs.scoreDocs.length;i++){
//取出封装编号和分数的ScoreDoc对象
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
//取出每一个编号,例如:0,1,2
int no = scoreDoc.doc;
//根据编号去索引库中的原始记录表中查询对应的docuemnt对象
Document document = indexSearcher.doc(no);
//获取docuemnt对象中的三个属性值
String id= document.get("id");
String title = document.get("title");
String content = document.get("content");
Article article=new Article(Integer.valueOf(id), title, content);
articles.add(article);
}
for(Article a:articles){
System.out.println(a.toString());
}
}