Lucene简介
- Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供。Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在Java开发环境里Lucene是一个成熟的免费开源工具。就其本身而言,Lucene是当前以及最近几年最受欢迎的免费Java信息检索程序库。人们经常提到信息检索程序库,虽然与搜索引擎有关,但不应该将信息检索程序库与搜索引擎相混淆。
- lucene是一个基于java开发全文检索工具包。
全文检索
- 先创建索引然后查询索引的过程叫做全文检索
1.创建索引
1.1 获得原始文档
- 是指要索引和搜索的内容。原始内容包括互联网上的网页、数据库中的数据、磁盘上的文件等。
1.2 构建文档对象
- 对应每一个原始对象创建一个Document对象
- 每个document对象中包含多个域(field)
- 域中保存的是原始文档数据。一个文档可以有多个域
1.域的名称
2.域的值
1.3 分析文档
- 分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元,可以将语汇单元理解为一个一个的单词。
- 每个关键词封装在一个Term对象中
Term:
1.关键词
2.关键词在的域
1.4 创建索引
- 对所有文档分析得出的语汇单元进行索引,索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到Document(文档)。
倒排索引 - 创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。
- 传统方法:根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。
2.查询索引
- 查询接口
- 封装查询对象
- 执行查询
- 渲染结果(展示给用户看)
3.入门案例
- 环境搭建
lucene-analyzers-common-7.4.0.jar
lucene-core-7.4.0.jar
commons-io.jar
步骤:
- 创建一个director对象,指定索引库保存的位置。
- 基于directory对象创建一个IndexWriter对象。
- 读取磁盘上的文件,对应每一个文件创建一个文档对象。
- 向文档对象中添加域
- 把文档对象写入索引库
- 关闭indexwriter对象
代码如下
/**
* 创建索引
* @throws IOException
*/
@Test
public void saveIndex() throws IOException {
// 1. 创建一个directory对象,指定索引库保存的位置。
Directory directory = FSDirectory.open(new File("D:\\y study\\index").toPath());
// 2. 基于directory对象创建一个IndexWriter对象。
IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig());
// 3. 读取磁盘上的文件,对应每一个文件创建一个文档对象。
File dir = new File("D:\\1全套黑马\\黑马57最新的笔记\\61.会员版(2.0)-就业课(2.0)-Lucene\\61.会员版(2.0)-就业课(2.0)-Lucene\\lucene\\02.参考资料\\searchsource");
File[] files = dir.listFiles();
for (File file : files) {
//取文件名
String fileName = file.getName();
//文件的路径
String filePath = file.getPath();
//文件的内容
String fileContent = FileUtils.readFileToString(file, "utf-8");
//文件的大小
long fileSize = FileUtils.sizeOf(file);
//创建Field
//参数1:域的名称 参数2:域的内容 参数3:是否存储
Field fieldName = new TextField("name", fileName, Field.Store.YES);
Field fieldPath = new TextField("path", filePath, Field.Store.YES);
Field fieldContent = new TextField("content", fileContent, Field.Store.YES);
Field fieldSize = new TextField("size", fileSize + "", Field.Store.YES);
//创建文档对象
Document document = new Document();
//4.向文档对象中添加域
document.add(fieldName);
document.add(fieldPath);
document.add(fieldContent);
document.add(fieldSize);
//5. 把文档对象写入索引库
indexWriter.addDocument(document);
}
// 6. 关闭indexwriter对象
indexWriter.close();
}
- .使用luke查看索引库中的内容
- 查询索引库
步骤:
- 创建一个director对象,指定索引库的位置。
- 创建一个IndexReader对象。
- 创建一个IndexSearcher对象,构造方法中的参数indexReader对象。
- 创建一个Query对象,TermQuery。
- 执行查询,得到一个TopDocs对象。
- 取查询结果的总记录数。
- 取文档列表
- 打印文档中的内容。
- 关闭indexwriter对象
代码如下:
/**
* 查询索引
* @throws IOException
*/
@Test
public void serachIndex() throws IOException {
// 1. 创建一个director对象,指定索引库的位置。
Directory directory = FSDirectory.open(new File("D:\\y study\\index").toPath());
// 2. 创建一个IndexReder对象。
IndexReader indexReader = DirectoryReader.open(directory);
// 3. 创建一个IndexSearcher对象,构造方法中的参数indexReader对象。
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// 4. 创建一个Query对象,TermQuery。
Query query = new TermQuery(new Term("content","spring"));
// 5. 执行查询,得到一个TopDocs对象。
//参数一:查询对象 参数二:查询结果返回的最大记录数
TopDocs topDocs = indexSearcher.search(query, 10);
// 6. 取查询结果的总记录数。
System.out.println("查询总记录数:"+ topDocs.totalHits);
// 7. 取文档列表
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
// 8. 打印文档中的内容。
for (ScoreDoc doc : scoreDocs) {
int docId = doc.doc;
Document document = indexSearcher.doc(docId);
System.out.println(document.get("name"));
System.out.println(document.get("path"));
System.out.println(document.get("size"));
// System.out.println(document.get("content"));
System.out.println("-------------------------------------------------------------分割线");
}
// 9. 关闭indexwriter对象
indexReader.close();
}
运行结果:
4.分析器
- 默认使用的分析器是StandardAnalyzer
查看分析器的分析效果
实现步骤:
1 创建一个Analyzer对象,StandardAnalyzer对象
2 使用分析器对象的tokenStream方法获得一个TokenStream对象
3 向TokenStream对象中设置一个引用,相当一个指针
4 调用TokenStream对象的reset方法
5 使用while循环遍历TOkenStream对象
6 关闭TokenStream对象
代码如下:
@Test
public void testTokenStream() throws Exception {
//1 创建一个Analyzer对象,StandardAnalyzer对象
Analyzer analyzer = new StandardAnalyzer();
//2 使用分析器对象的tokenStream方法获得一个TokenStream对象
TokenStream tokenStream = analyzer.tokenStream("", "The Spring Framework provides a");
//3 向TokenStream对象中设置一个引用,相当一个指针
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
//4 调用TokenStream对象的reset方法
tokenStream.reset();
//5 使用while循环遍历TOkenStream对象
while (tokenStream.incrementToken()) {
System.out.println(charTermAttribute.toString());
}
//6 关闭TokenStream对象
tokenStream.close();
}
结果显示:
但是如果是对中文进行分析是什么效果呢?
如果对 " 全文检索是将整本书java、整篇文章中的任意内容信息查找出来的检索" 进行分析
结果如下:
我们会发现只分析了一个字,显然处理中文不合理。
IKAnalyze的使用
- 添加jar包到工程中
- 把配置文件和扩展词典添加到工程的classpath下
代码如下:
@Test
public void testTokenStream() throws Exception {
//1 创建一个Analyzer对象,StandardAnalyzer对象
//Analyzer analyzer = new StandardAnalyzer();
Analyzer analyzer = new IKAnalyzer();
//2 使用分析器对象的tokenStream方法获得一个TokenStream对象
TokenStream tokenStream = analyzer.tokenStream("", "全文检索是将整本书java、整篇文章中的任意内容信息查找出来的检索");
//3 向TokenStream对象中设置一个引用,相当一个指针
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
//4 调用TokenStream对象的reset方法
tokenStream.reset();
//5 使用while循环遍历TOkenStream对象
while (tokenStream.incrementToken()) {
System.out.println(charTermAttribute.toString());
}
//6 关闭TokenStream对象
tokenStream.close();
}
运行结果:
根据结果可以知道,使用IKAnalyze后分析的中文是一个个的词语,达到了我们想要的结果。
- 如果我们想要是某两个字被分析为词语,可以加入扩展词典。
- 如果希望停用该词,则加入停用词典。
如何用IK分析器?
action: 在创建索引时添加分析器IK
代码如下:
@Test
public void saveIndex() throws IOException {
// 1. 创建一个directory对象,指定索引库保存的位置。
Directory directory = FSDirectory.open(new File("D:\\y study\\index").toPath());
// 2. 基于directory对象创建一个IndexWriter对象。
// IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig());
IndexWriterConfig config = new IndexWriterConfig(new IKAnalyzer());
IndexWriter indexWriter = new IndexWriter(directory,config);
// 3. 读取磁盘上的文件,对应每一个文件创建一个文档对象。
File dir = new File("D:\\1全套黑马\\黑马57最新的笔记\\61.会员版(2.0)-就业课(2.0)-Lucene\\61.会员版(2.0)-就业课(2.0)-Lucene\\lucene\\02.参考资料\\searchsource");
File[] files = dir.listFiles();
for (File file : files) {
//取文件名
String fileName = file.getName();
//文件的路径
String filePath = file.getPath();
//文件的内容
String fileContent = FileUtils.readFileToString(file, "utf-8");
//文件的大小
long fileSize = FileUtils.sizeOf(file);
//创建Field
//参数1:域的名称 参数2:域的内容 参数3:是否存储
Field fieldName = new TextField("name", fileName, Field.Store.YES);
Field fieldPath = new TextField("path", filePath, Field.Store.YES);
Field fieldContent = new TextField("content", fileContent, Field.Store.YES);
Field fieldSize = new TextField("size", fileSize + "", Field.Store.YES);
//创建文档对象
Document document = new Document();
//4.向文档对象中添加域
document.add(fieldName);
document.add(fieldPath);
document.add(fieldContent);
document.add(fieldSize);
//5. 把文档对象写入索引库
indexWriter.addDocument(document);
}
// 6. 关闭indexwriter对象
indexWriter.close();
}