前两篇,讲到了lucene的一些用法,这一篇,我们继续lucene的其他的特性
一) 索引库优化
1.1什么是索引库
索引库是Lucene的重要的存储结构,它包括二部份:原始记录表,词汇表
原始记录表:存放的是原始记录信息,Lucene为存入的内容分配一个唯一的编号
词汇表:存放的是经过分词器拆分出来的词汇和该词汇在原始记录表中的编号
1.2为什么要将索引库进行优化
在默认情况下,向索引库中增加一个Document对象时,索引库自动会添加一个扩展名叫*.cfs的二进制压缩文件,如果向索引库中存Document对象过多,那么*.cfs也会不断增 加,同时索引库的容量也会不断增加,影响索引库的大小。
1.3索引库优化方案
1.3.1合并cfs文件,合并后的cfs文件是二进制压缩字符,能解决是的文件大小和数量的问题如代码:
@Test
public void add2() throws Exception{
Article article=new Article(1,"学习","一起学习lucene索引库的优化",10);
Document document = LuceneUtil.javabenaToDocuemnt(article);
IndexWriter indexWriter=new IndexWriter(LuceneUtil.getDirectory(),LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
indexWriter.addDocument(document);
//合并cfs文本,每两个合拼
<span style="color:#FF6666;">indexWriter.optimize();</span>
indexWriter.close();
}
1.3.2设定合并因子,自动合并cfs文件,默认10个cfs文件合并成一个cfs文件
@Test
public void add3() throws Exception{
Article article=new Article(1,"学习","一起学习lucene索引库的优化",10);
Document document = LuceneUtil.javabenaToDocuemnt(article);
IndexWriter indexWriter=new IndexWriter(LuceneUtil.getDirectory(),LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
indexWriter.addDocument(document);
//每五个cfs文件合并在一起,默认是十个合并
<span style="color:#FF6666;">indexWriter.setMergeFactor(5); </span>
indexWriter.close();
}
1.3.3使用RAMDirectory,类似于内存索引库,能解决是的读取索引库文件的速度问题,
它能以空换时,提高速度快,但不能持久保存,因此启动时加载硬盘中的索引库到内存中的索引库,退出时将内存中的索引库保存到硬盘中的索引库,且内容不能重复。
@Test
public void add4() throws Exception{
Article article=new Article(1,"学习","一起学习lucene索引库的优化",10);
Document document = LuceneUtil.javabenaToDocuemnt(article);
//磁盘索引库
Directory fsDirectory=FSDirectory.open(new File("e:/IndexDB"));
//内存索引库,因为硬盘索引库的内容要同步到内存索引库中
Directory ramdDirectory=new RAMDirectory(fsDirectory);
指向硬盘索引库的字符流,true表示如果内存索引库中和硬盘索引库中的相同的document对象时,先删除硬盘索引库中的document对象,
//再将内存索引库的document对象写入硬盘索引库中
//反之是false,默认为false,这个boolean值写在硬盘字符流的构造器
IndexWriter fsIndexWriter=new IndexWriter(fsDirectory,LuceneUtil.getAnalyzer(),true,LuceneUtil.getMaxFieldLength());
//指向内存索引库的字符流
IndexWriter ramIndexWriter=new IndexWriter(ramdDirectory, LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
//将docuement对象写入内存索引库
ramIndexWriter.addDocument(document);
ramIndexWriter.close();
//将内存索引库的所有docuemnt对象同步到硬盘索引库中
fsIndexWriter.addIndexesNoOptimize(ramdDirectory);
fsIndexWriter.close();
}
如图所示:
二) 分词器
2.1什么是分词器
采用一种算法,将中英文本中的字符拆分开来,形成词汇,以待用户输入关健字后搜索
2.2为什么要分词器
因为用户输入的搜索的内容是一段文本中的一个关健字,和原始表中的内容有差别,
但作为搜索引擎来讲,又得将相关的内容搜索出来,此时就得采用分词器来最大限度
匹配原始表中的内容
2.3分词器工作流程
步一:按分词器拆分出词汇
步二:去除停用词和禁用词
步三:如果有英文,把英文字母转为小写,即搜索不分大小写
代码示例: private static void testAnalyzer(Analyzer analyzer, String text) throws Exception {
System.out.println("当前使用的分词器:" + analyzer.getClass());
TokenStream tokenStream = analyzer.tokenStream("content",new StringReader(text));
tokenStream.addAttribute(TermAttribute.class);
while (tokenStream.incrementToken()) {
TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
System.out.println(termAttribute.term());
}
}
public static void main(String[] args) throws Exception {
//使用第三方IKAnalyzer分词器
testAnalyzer(new IKAnalyzer(),"一起学习lucene分词器");
}
三) 搜索结果高亮
3.1什么是搜索结果高亮
在搜索结果中,将与关健字相同的字符用红色显示
示例代码:@Test
public void searchByKey()throws Exception{
String keywords="lucene";
List<Article> articles=new ArrayList<Article>();
QueryParser queryParser=new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
Query query = queryParser.parse(keywords);
IndexSearcher indexSearcher=new IndexSearcher(LuceneUtil.getDirectory());
TopDocs topDocs=indexSearcher.search(query, 100);
//设置高亮
Formatter formatter=new SimpleHTMLFormatter("<font color='red'>", "</font>");
//关键字对象
Scorer scorer=new QueryScorer(query);
//高亮对象
Highlighter highlighter=new Highlighter(formatter, scorer);
//Fragmenter fragmenter=new SimpleFragmenter(4);
for(int i=0;i<topDocs.scoreDocs.length;i++){
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
Document document = indexSearcher.doc(no);
String highlighterContent=highlighter.getBestFragment(LuceneUtil.getAnalyzer(),"content",document.get("content"));
document.getField("content").setValue(highlighterContent);
Article article =(Article) LuceneUtil.docuemntToJavaBean(document, Article.class);
articles.add(article);
}
for(Article article:articles){
System.out.println(article);
}
}
4.1什么是搜索结果搞要
如果搜索结果内容太多,我们只想显示前几个字符, 必须与高亮一起使用
@Test
public void searchByKey()throws Exception{
String keywords="lucene";
List<Article> articles=new ArrayList<Article>();
QueryParser queryParser=new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
Query query = queryParser.parse(keywords);
IndexSearcher indexSearcher=new IndexSearcher(LuceneUtil.getDirectory());
TopDocs topDocs=indexSearcher.search(query, 100);
//设置高亮
Formatter formatter=new SimpleHTMLFormatter("<font color='red'>", "</font>");
//关键字对象
Scorer scorer=new QueryScorer(query);
//高亮对象
Highlighter highlighter=new Highlighter(formatter, scorer);
//搜索结果搞要
Fragmenter fragmenter = new SimpleFragmenter(4);
highlighter.setTextFragmenter(fragmenter);
for(int i=0;i<topDocs.scoreDocs.length;i++){
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
Document document = indexSearcher.doc(no);
String highlighterContent=highlighter.getBestFragment(LuceneUtil.getAnalyzer(),"content",document.get("content"));
document.getField("content").setValue(highlighterContent);
Article article =(Article) LuceneUtil.docuemntToJavaBean(document, Article.class);
articles.add(article);
}
for(Article article:articles){
System.out.println(article);
}
}
四) 搜索结果排序
5.1什么是搜索结果排序
搜索结果是按某个或某些字段高低排序来显示的结果
5.2影响网站排名的先后的有多种
head/meta/
网页的标签整洁
网页执行速度
采用div+css
5.3Lucene中的显示结果次序与相关度得分有关
ScoreDoc.score;
默认情况下,Lucene是按相关度得分排序的,得分高排在前,得分低排在后
如果相关度得分相同,按插入索引库的先后次序排序
示例代码:
@Test
public void add()throws Exception{
Article article=new Article(1, "Lucene", "学习lucene的索引库", 10);
// Article article=new Article(2, "Lucene", "学习lucene的索引库", 20);
// Article article=new Article(3, "Lucene", "学习lucene的索引库", 20);
// Article article=new Article(4, "Lucene", "学习lucene的索引库", 40);
Document document = LuceneUtil.javabenaToDocuemnt(article);
IndexWriter indexWriter=new IndexWriter(LuceneUtil.getDirectory(),LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
//设置相关度得分,提高搜索
document.setBoost(50F);
indexWriter.addDocument(document);
indexWriter.close();
}
@Test
public void search()throws Exception{
String keywords="Lucene";
List<Article> articles=new ArrayList<Article>();
QueryParser queryParser=new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
Query query=queryParser.parse(keywords);
IndexSearcher indexSearcher=new IndexSearcher(LuceneUtil.getDirectory());
TopDocs topDocs = indexSearcher.search(query, 100);
for(int i=0;i<topDocs.scoreDocs.length;i++){
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
float score = scoreDoc.score;
System.out.println("========Score:"+score);
Document doc = indexSearcher.doc(no);
Article article=(Article)LuceneUtil.docuemntToJavaBean(doc, Article.class);
articles.add(article);
}
for(Article article:articles){
System.out.println(article);
}
}
5.4根据单个或多个字段排序
@Test
public void add() throws Exception{
<p><strong>
</strong></p> Article article=new Article(1, "Lucene", "学习lucene的索引库", 10);
// Article article=new Article(2, "Lucene", "学习lucene的索引库", 20);
// Article article=new Article(3, "Lucene", "学习lucene的索引库", 20);
// Article article=new Article(4, "Lucene", "学习lucene的索引库", 40);
Document document = LuceneUtil.javabenaToDocuemnt(article);
IndexWriter indexWriter=new IndexWriter(LuceneUtil.getDirectory(),LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
indexWriter.addDocument(document);
indexWriter.close();
}
@Test
public void search()throws Exception{
String keywords="lucene";
List<Article> list=new ArrayList<Article>();
QueryParser queryParser=new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
Query query = queryParser.parse(keywords);
IndexSearcher indexSearcher=new IndexSearcher(LuceneUtil.getDirectory());
//创建排序对象123 379.75
//参数一:id表示依据document对象中的哪个字段排序,例如:id
//参数二:SortField.INT表示document对象中该字段的类型,以常量方式书写
//参数三:true表示降序,类似于order by id desc
//参数三:false表示升序,类似于order by id asc
//单个字段排序
// Sort sort=new Sort(new SortField("id",SortField.INT, true));
//多个字段排序, 在多字段排序中,只有第一个字段排序结果相同时,第二个字段排序才有作用,提倡用数值型排序
//按count字段的降序排列,如果count字段相同的话,再按id的升序排序
Sort sort=new Sort(new SortField("count",SortField.INT,true),new SortField("id",SortField.INT,false));
TopDocs topDocs = indexSearcher.search(query, null, 100, sort);
for(int i=0;i<topDocs.scoreDocs.length;i++){
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
Document document = indexSearcher.doc(no);
Article article =(Article)LuceneUtil.docuemntToJavaBean(document, Article.class);
list.add(article);
}
for(Article article:list){
System.out.println(article);
}
}
五) 条件搜索
6.1什么是条件搜索
用关健字与指定的单列或多例进行匹配的搜索
@Test
public void search() throws Exception{
String keywords="lucene";
List<Article> list=new ArrayList<Article>();
//单字段条件搜索
//QueryParser queryParser=new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
//多字段条件搜索
QueryParser queryParser=new MultiFieldQueryParser(LuceneUtil.getVersion(),new String[]{"title","content"},LuceneUtil.getAnalyzer());
Query query = queryParser.parse(keywords);
IndexSearcher indexSearcher=new IndexSearcher(LuceneUtil.getDirectory());
TopDocs topDocs = indexSearcher.search(query, 100);
for(int i=0;i<topDocs.scoreDocs.length;i++){
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
Document document = indexSearcher.doc(no);
Article article=(Article)LuceneUtil.docuemntToJavaBean(document, Article.class);
list.add(article);
}
for(Article article:list){
System.out.println(article);
}
}