Lucene基础知识
1 什么是全文检索
1.1 数据的分类
-
结构化数据
格式固定、长度固定、数据类型固定。例如数据库中的数据。
-
非结构化数据
word文档、pdf文档、邮件、html、txt格式不固定、长度不固定、数据类型不固定。
1.2 数据的查询
-
结构化数据的查询
SQL语句,查询结构化数据的方法。简单、速度快。
-
非结构化数据的查询
比如:从文本文件中找出包含spring单词的文件。
-
目测
-
使用程序把文档读到内存中,然后匹配字符串,顺序扫描。
-
把非结构化数据变成结构化数据
先根据空格进行字符串拆分,得到一个单词列表,基于单词列表创建一个索引,然后查询索引,根据单词和文档的对应关系找到文档列表。这个过程叫全文索引。
**索引:**一个为了提高查询速度,创建某种数据结构的集合。
-
1.3 全文检索
先创建索引然后查询索引的过程叫全文索引。索引一次创建可以多次使用,表现为每次查询速度就很快了。
2 全文检索的应用场景
2.1 搜索引擎
百度、360搜索、谷歌、搜狗
2.2 站内搜索
论坛搜索、微博、文章搜索
2.3 电商搜索
淘宝搜索、京东搜索
只要有嗖嗖的地方就可以使用全文检索技术。
3 Lucene
Lucene是一个基于Java开发全文检索工具包。
3.1 Lucene实现全文检索的流程
- 创建索引
-
获取文档
原始文档:要基于哪些数据来进行搜索,那么这些数据就是原始文档。
搜索引擎:使用爬虫获取原始文档。
站内搜索:数据库中的数据
案例:直接使用io流读取磁盘上的文件
-
构建文档对象
对应每个原始文档创建一个Document对象
每个document对象中包含多个域(field)
域中保存就是原始文档数据。
域的名称
域的值
每个文档中都有唯一的编号,就是文档的id
-
分析文档
就是分词的过程
- 根据空格进行字符串拆分,得到一个单词列表
- 把单词统一转换成小写
- 去除标点符号
- 去除停用词(即无意义的词)
每个关键词都封装成一个Term对象中。term对象中包含两部分内容:关键词所在的域、关键词本身,不同的域中拆分出来的相同的关键词是不同的term。
-
创建索引
基于关键词列表来创建一个索引,保存到索引库中。索引库中有索引和document对象和关键词与文档的对应关系,通过词语找文档,这种索引的结构叫倒排索引结构。
- 查询索引
-
用户查询接口
用户输入查询条件的地方,例如:百度的搜索框。
-
把关键词封装成查询对象
要查询的域,要搜索的关键词
-
执行查询
根据要查询的关键词到对应的域上进行搜索,找到关键词,根据关键词来找到对应文档。
-
渲染结果
根据文档id找到文档对象,进行高亮分页等处理。
4 入门案例
4.1 步骤分析
首先熟悉一下Lucene的步骤:
-
创建索引
将用户要搜索的文档进行索引,索引存储在索引库(index)中。
-
获得原始文档:原始文档包括互联网上的网页、数据库中的数据、磁盘上的文件等。本案例中的原始内容就是磁盘上的文件:
-
创建文档对象:获取原始内容的目的是为了索引,在索引前需要将原始内容创建成文档(Document),文档中包括一个一个的域(Field),域中存储内容(file_name文件名称、file_path文件路径、file_size文件大小、file_content文件内容)。
注意:每个Document可以有多个Field,不同的Document可以有不同的Field,同一个Document可以有相同的Field(域名和域值都相同),每个文档都有一个唯一的编号,即文档id。
-
分析文档:分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元,可以将语汇单元理解为一个一个的单词。每一个单词叫做一个Term,不同的域中拆分出来的相同的单词是不同的term。term的结构为——文档的域名+单词的内容。
-
创建索引:对所有文档分析得出的词汇单元进行索引,索引的目的就是为了搜索,最终实现只搜索被索引的词汇单元从而找到Document。
注意:创建索引是对词汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。
-
-
查询索引
查询索引也是搜索的过程。搜索就是用户输入关键字,从索引(index)中进行查找的过程。根据关键字搜索索引,根据索引找到对应的文档,从而找到要搜索的内容。
- 创建查询:用户输入查询关键字执行搜索之前需要先构建一个查询对象,查询对象中可以指定查询要搜索的Field文档域、查询关键字等,查询对象会生成具体的查询语法。例如:语法“fileName:lucene” 表示要搜索Field域的内容为“Lucene”的文档。
- 执行查询:搜索索引过程——根据查询语法在倒排索引词典表中分别找出对应搜索词的索引,从而找到索引所链接的文档链表。比如搜索语法为“fileName:lucene”表示搜索出fileName域中包含Lucene的文档。搜索过程就是在索引上查找域为fileName,并且关键字为Lucene的term,并根据term找到文档id列表。
4.2 代码编写
首先需要从官方网站中下载lucene-7.4.0并解压。然后将以下jar包导入到工程中去:
需求:实现一个文件的搜索功能,通过关键字搜索文件,凡是文件名或文件内容包括关键字的文件都需要找出来。还可以根据中文词语进行查询,并且需要支持多个条件查询。
-
创建索引
@Test public void createIndex() throw Exception { // 1. 创建indexWriter对象:需要两个参数directory索引库存放路径和indexWriterConfig对象 Directory directory = FSDirectory.open(new File("D:\\ideaProjects\\index").toPath()); IndexWriterConfig config = new IndexWriterConfig(); IndexWriter indexWriter = new IndexWriter(directory, config); // 2. 获取原始文件 // 路径 File dir = new File("C:\Users\17163\Desktop\Java学习\searchsource"); // 获取文件信息 for (File f : dir.listFiles()) { // 文件名 String fileName = f.getName(); // 文件内容 String fileContent = FileUtils.readFileToString(f); // 文件路径 String filePath = f.getPath(); // 文件大小 long fileSize = FileUtils.sizeof(f); // 创建域 // TextField参数:第一个:域的名称;第二个:域的内容;第三个:是否存储 Field fileNameField = new TextField("fileName", 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 document = new Document(); document.add(fileNameField); document.add(fieldPath); document.add(fieldContent); document.add(fieldSize); // 创建索引,并写入索引库 indexWriter.addDocument(document); } // 关闭indexWriter indexWriter.close(); }
执行上述代码后,index目录下会出现下面这些文件:可以用Luke工具进行查看索引文件
Luke工具:
-
查询索引
@Test public void searchIndex() throws Exception { // 1. 创建indexReader对象 // 指定索引库存放的路径 Directory directory = FSDirectory.open(new File("D:\\ideaProjects\\index").toPath()); // 创建indexReader IndexReader inde }
5 分析器
默认使用的是标准分析器StandardAnalyzer
5.1 分析器的效果
使用Analyzer对象的tokenStream方法返回一个TokenStream对象。词对象包含了最终分词结果。
实现步骤:
- 创建一个Analyzer对象,StandardAnalyzer对象
- 使用分词器对象的tokenStream方法获得一个TokenStream对象。
- 向TokenStream对象中设置一个引用,相当于数一个指针
- 调用TokenStream对象的rest方法,如果不调用会抛出异常
- 使用while循环遍历TokenStream方法
- 关闭TokenStream对象
5.2 IKAnalyzer的使用方法
-
把IKAnalyzer的jar包添加到工程中
-
把配置文件和扩展词典添加到工程的classpath下
注意:扩展词典严禁使用windows记事本编辑保存保证扩展词典的编码格式是utf-8。(记事本默认是utf-8+bom)
扩展词典:添加一些新词
停用词词典:无意义的词或者敏感词汇
6 索引库维护
6.1 添加文档
6.2 删除文档
- 删除全部
- 根据查询、关键词删除文档
6.3 修改文档
7 索引库查询
7.1 使用Query的子类
- TermQuery: 根据关键词进行查询,需要指定查询的域和查询的关键词
- RangeQuery:范围查询
7.2 使用QueryParser进行查询
可以对要查询的内容先分词,然后基于分词的结果进行查询。
添加一个jar包:lucene-queryparser-7.4.0.jar
全部
- 根据查询、关键词删除文档
6.3 修改文档
7 索引库查询
7.1 使用Query的子类
- TermQuery: 根据关键词进行查询,需要指定查询的域和查询的关键词
- RangeQuery:范围查询
7.2 使用QueryParser进行查询
可以对要查询的内容先分词,然后基于分词的结果进行查询。
添加一个jar包:lucene-queryparser-7.4.0.jar