1、什么是Lucene
Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写。它是一个全文检索引擎的架构,提供了完整的创建索引和查询索引,以及部分文本分析的引擎。
Lucene在全文检索领域是一个经典的祖先,现在很多检索引擎都是在其基础上创建的,思想是相通的。
Lucene是根据关健字来搜索的文本搜索工具,但只能在某个网站内部搜索文本内容,不能跨网站搜索。
Lucene is a Java full-text search engine. Lucene is not a complete application, but rather a code library and API that can easily be used to add search capabilities to applications. |
2、Lucene通常用在什么地方
Lucece不能用在互联网搜索(即像百度那样),只能用在网站内部的文本搜索(即只能在CRM,RAX,ERP内部使用),但思想是相通的。
3、Lucene中存的什么内容
Lucene中存的就是一系列的二进制压缩文件和一些控制文件,它们位于计算机的硬盘上,
这些内容统称为索引库,索引库有二部份组成:
(1)原始记录
存入到索引库中的原始文本
(2)词汇表
按照一定的拆分策略(即分词器)将原始记录中的每个字符拆开后,存入一个供将来搜索的表
4、为什么网站内部有些地方要用Lucene来索搜,而不全用SQL来搜索
(1)SQL只能针对数据库表搜索,不能直接针对硬盘上的文本搜索
(2)SQL没有相关度排名
(3)SQL搜索结果没有关健字高亮显示
(4)SQL需要数据库的支持,数据库本身需要内存开销较大,例如:Oracle
(5)SQL搜索有时较慢,尤其是数据库不在本地时,超慢,例如:Oracle
5、Lucene版本和JDK版本
不同的Lucene版本对JDK的版本的要求也不同,对于这一问题,我还不太懂。
6、下载Lucene 3.0.2版本
下载地址: https://archive.apache.org/dist/lucene/java/
下载两个文件:lucene-3.0.2-src.zip(源码包)和lucene-3.0.2.zip(jar包)
7、入门
解压lucene-3.0.2.zip文件,找到如下4个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【索引库优化策略】
将这4个jar包引入到项目当中,编写代码进行测试:
package com.rk.lucene.firstapp;
import java.io.File;
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.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
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.util.Version;
import org.junit.Test;
import com.rk.lucene.entity.Article;
public class FirstLucene {
/**
* 创建索引库
* 将Aritcle对象放入索引库中的原始记录表中,从而形成词汇表
*/
@Test
public void createIndexDB() throws Exception{
//创建Article对象
Article article = new Article(1,"你好","欢迎来到我的世界");
//创建Document对象
Document document = new Document();
//将Article对象中的三个属性值分别绑定到Document对象中
/*
*参数一:document对象中的属性名叫xid,article对象中的属性名叫id,项目中提倡相同
*参数二:document对象中的属性xid的值,与article对象中相同
*参数三:是否将xid属性值存入由原始记录表中转存入词汇表
* Store.YES表示该属性值会存入词汇表
* Store.NO表示该属性值不会存入词汇表
* 项目中提倡非id值都存入词汇表
*参数四:是否将xid属性值进行分词算法
* Index.ANALYZED表示该属性值会进行词汇拆分
* Index.NOT_ANALYZED表示该属性值不会进行词汇拆分
* 项目中提倡非id值都进行词汇拆分
* 目前将分词理解为分汇拆分,目前认为一个汉字一个分词拆分
*/
document.add(new Field("xid", article.getId().toString(), Store.YES, Index.ANALYZED));
document.add(new Field("xtitle", article.getTitle(), Store.YES, Index.ANALYZED));
document.add(new Field("xcontent", article.getContent(), Store.YES, Index.ANALYZED));
//创建IndexWriter字符流对象
/*
* 参数一:lucene索引库最终应对于硬盘中的目录,例如:D:/rk/indexDB
* 参数二:采用什么策略将文本拆分,一个策略就是一个具体的实现类
* 参数三:最多将文本拆分出多少词汇,LIMITED表示1W个,即只取前1W个词汇,如果不足1W个词汇个,以实际为准
*/
Directory directory = FSDirectory.open(new File("D:/rk/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字符流对象
indexWriter.close();
}
/**
* 根据关键字从索引库中搜索符合条件的内容
*/
@Test
public void findIndexDB() throws Exception{
//一、处理关键字
String keywords = "世界";
List<Article> articleList = new ArrayList<Article>();
Version version = Version.LUCENE_30;
Analyzer analyzer = new StandardAnalyzer(version);
//创建查询解析器对象
/*
* 参数一:使用分词器的版本,提倡使用该jar包中的最高版本
* 参数二:争对document对象中的哪个属性进行搜索
*/
QueryParser queryParser = new QueryParser(version, "xcontent", analyzer);
//创建对象封装查询关键字
Query query = queryParser.parse(keywords);
//二、搜索关键字
//创建IndexSearcher字符流对象
Directory directory = FSDirectory.open(new File("D:/rk/indexDB"));
IndexSearcher indexSearcher = new IndexSearcher(directory);
int MAX_RECORD = 100;
//根据关键字,去索引库中的词汇表搜索
/*
* 参数一:表示封装关键字查询对象,其它QueryParser表示查询解析器
* 参数二:MAX_RECORD表示如果根据关键字搜索出来的内容较多,只取前MAX_RECORD个内容
* 不足MAX_RECORD个数的话,以实际为准
*/
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;
//根据编号去索引库中的原始记录表中查询对应的document对象
Document document = indexSearcher.doc(no);
//获取document对象中的三个属性值
String xid = document.get("xid");
String xtitle = document.get("xtitle");
String xcontent = document.get("xcontent");
//封装到article对象中
Article article = new Article(Integer.parseInt(xid), xtitle, xcontent);
//将article对象加入到list集合中
articleList.add(article);
}
//迭代结果集
for(Article a : articleList){
System.out.println(a);
}
//关闭IndexSearcher对象
indexSearcher.close();
}
}
Article.java
package com.rk.lucene.entity;
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 "Article [编号=" + id + ", 标题=" + title + ", 内容=" + content + "]";
}
}
生成的文件:
输出的结果:
Article [编号=1, 标题=你好, 内容=欢迎来到我的世界]
8、代码使用Lucene的流程图
创建索引库:
1)创建JavaBean对象
2)创建Document对象
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对象中去,并加入到集合中保存,以备将之用
package com.rk.lucene.firstapp;
import java.io.File;
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.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
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.util.Version;
import org.junit.Test;
import com.rk.lucene.entity.Article;
public class DemoA {
@Test
public void createIndexDB() throws Exception{
//1、得到JavaBean对象
Article article = new Article(1, "你好", "欢迎来到我的世界");
//2、将JavaBean对象转换为Document对象
Document doc = new Document();
doc.add(new Field("xid", article.getId().toString(), Store.YES, Index.ANALYZED));
doc.add(new Field("xtitle", article.getTitle(), Store.YES, Index.ANALYZED));
doc.add(new Field("xcontent", article.getContent(), Store.YES, Index.ANALYZED));
//3、利用IndexWriter将Document对象写入到索引库内
// 3.1、创建索引库位置
Directory directory = FSDirectory.open(new File("D:/rk/indexDB"));
// 3.2、创建分词器
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
// 3.3、创建IndexWriter对象
IndexWriter indexWriter = new IndexWriter(directory, analyzer, MaxFieldLength.LIMITED);
// 3.4、将Document写入到索引库
indexWriter.addDocument(doc);
// 3.5、关闭IndexWriter对象
indexWriter.close();
}
@Test
public void findIndexDB() throws Exception{
//1、对搜索的“关键字”进行分词处理,“分词处理的结果”是Query对象
String keywords = "世界";
Version version = Version.LUCENE_30;
Analyzer analyzer = new StandardAnalyzer(version);
QueryParser queryParser = new QueryParser(version, "xcontent", analyzer);
Query query = queryParser.parse(keywords);
//2、在“索引库”中,对“分词处理的结果”进行查询,得到TopDocs对象
Directory directory = FSDirectory.open(new File("D:/rk/indexDB"));
IndexSearcher indexSearcher = new IndexSearcher(directory);
TopDocs topDocs = indexSearcher.search(query, 10);
//3、从TopDocs中取出Document对象,然后转换为JavaBean对象
List<Article> articleList = new ArrayList<Article>();
for(int i=0;i<topDocs.scoreDocs.length;i++){
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
Document document = indexSearcher.doc(no);
String xid = document.get("xid");
String xtitle = document.get("xtitle");
String xcontent = document.get("xcontent");
Article article = new Article(Integer.parseInt(xid), xtitle, xcontent);
articleList.add(article);
}
//4、将查询结果输出
for(Article article : articleList){
System.out.println(article);
}
}
}
转载于:https://blog.51cto.com/lsieun/1852168