最详细的Lucene实现全文检索

您所在的位置:网站首页 中文检索工具 最详细的Lucene实现全文检索

最详细的Lucene实现全文检索

2024-04-09 05:14| 来源: 网络整理| 查看: 265

文章目录 1. 全文检索1.1 为什么需要全文检索1.2 什么是全文检索1.3 应用的场景 2. Lucene介绍2.1 [定义](https://baike.baidu.com/item/Lucene)2.2 Lucene 实现全文检索的流程2.3 创建索引2.3.1 获得文档2.3.2 构建索引文档2.3.1 分析文档(分词)2.3.1 创建索引 2.4 查询索引2.4.1 用户查询接口2.4.2 创建查询2.4.3 执行查询2.4.4 渲染结果 3. Lucene使用3.1 下载Lucene3.2 导包3.2.1 jar包3.2.2 pom.xml 3.3 创建索引3.3.1 步骤:3.3.2 代码实现3.3.2 结果显示 3.3 查询索引3.3.1 步骤3.3.2 代码实现3.3.3 结果显示 3.4 分析器3.5 中文分析器3.5.1 pom.xml3.5.2 代码实现3.5.3 查看结果 3.6 Luck3.7 Field域的属性 4. Lucene维护索引库4.1 添加文档4.1.1 代码实现4.1.2 查看结果 4.2 删除文档4.2.1 删除所有文档4.2.1.1 代码实现4.2.1.2 查看结果 4.2.2 针对性删除4.2.2.1 信息介绍4.2.2.2 代码实现4.2.2.3 查看结果 4.3 修改文档4.3.1 信息介绍4.3.2 代码实现4.3.3 查询结果 4.4 查询文档4.4.1 提取公用代码4.4.2 TermQuery4.4.2.1 适用范围4.4.2.2 代码实现4.2.2.3 查看结果 4.4.3 RangeQuery4.4.3.1 适用范围4.4.3.2 代码实现4.4.3.3 查看结果 4.4.3 queryparser4.4.3.1 适用范围4.4.3.2 代码实现4.4.3.3 查看结果

1. 全文检索 1.1 为什么需要全文检索

数据可分为结构化数据和非结构化数据,对数据查询时,结构化数据可以通过 SQL 语句等方式查询,而非结构化数据(如PPT,word等)无法用此方式查询,我们利用 将非结构化数据转化为结构化数据 (即 先将文件中单词按空格拆分,把单词创建创建一个索引表,然后查询索引,根据单词和文档的关系找到文档列表,即全文检索),进行快速查询。

1.2 什么是全文检索

先创建索引,然后查询索引的过程是全文检索。 具有一次创建,多次使用的特点(创建的速度有点慢)。

1.3 应用的场景

1.搜索引擎 百度 360 google bing 2.站内搜索 论坛 CSDN文章搜索 3.电商搜索 淘宝 京东 软件内的搜索

2. Lucene介绍 2.1 定义

Lucene是一个开放源代码的全文检索引擎工具包。

2.2 Lucene 实现全文检索的流程

在这里插入图片描述

主要是 创建索引 和 查询索引两个步骤。

2.3 创建索引 2.3.1 获得文档

你可以利用你的技术从数据库、互联网、爬虫、word等方式获取原始文档,即 采集信息。

2.3.2 构建索引文档

对应每个原始文档创建一个 Document 对象(拥有唯一的ID) 每个 Document 中包含多个 Field 不同的Document可以有不同的Field 同一个Document可以有相同的Field 域中以键值对保存 域的 名称和值

2.3.1 分析文档(分词)

对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元,可以将语汇单元理解为一个一个的单词。 每个单词都是一个Term

The Spring Framework provides a comprehensive programming and configuration model.。

Spring 、Framework 、programming 、model 是一个个Term。 不同的域中拆分出来的相同的单词是不同的term。 term中包含两部分一部分是文档的域名,另一部分是单词的内容。

2.3.1 创建索引

基于关键词创建一个索引,保存到索引库中 在这里插入图片描述 通过词语找文档,这种索引的结构叫倒排索引结构。

2.4 查询索引 2.4.1 用户查询接口

在这里插入图片描述

2.4.2 创建查询

创建 查询对象Query,将需要查询的内容Term输入 进去,进行查询。

2.4.3 执行查询

根据对应搜索词的索引,从而找到索引所链接的文档链表。

2.4.4 渲染结果

搜索词如上图进行高亮显示。

3. Lucene使用 3.1 下载Lucene

点击下载Lucene

我的版本是7.4 jdk为1.8

3.2 导包

下面分别是使用 jar 和 maven

3.2.1 jar包

在这里插入图片描述

3.2.2 pom.xml junit junit 4.12 commons-io commons-io 2.6 org.apache.lucene lucene-core 7.4.0 org.apache.lucene lucene-queryparser 7.4.0 org.apache.lucene lucene-analyzers-common 7.4.0 org.apache.lucene lucene-highlighter 7.4.0 3.3 创建索引 3.3.1 步骤:

1.创建一个indexwriter对象 2. 创建document对象

指定索引库的存放位置Directory对象 指定一个IndexWriterConfig对象

3.创建field对象,将field添加到document对象中 4.使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。 5.关闭IndexWriter对象

3.3.2 代码实现 @Test public void createIndex() throws Exception { //1.创建一个Directory对象,指定索引库保存的位置 //1.1把索引库保存在内存中 //Directory directory = new RAMDirectory(); //1.2把做因结构保存在磁盘 Directory directory = FSDirectory.open(new File("D:\\Lucene\\index").toPath()); //2.基于Directory 对象创建一个IndexWriter对象 IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig()); //3.读取磁盘上的文件,对应每个文件创建一个文档对象 File dir = new File("D:\\Lucene\\searchsource"); File[] files = dir.listFiles(); for (File f : files) { //取文件名 String fileName = f.getName(); //文件的路径 String filePath = f.getPath(); //文件的内容 String fileContent = FileUtils.readFileToString(f, "utf-8"); //文件的大小 long fileSize = FileUtils.sizeOf(f); //创建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(); } 3.3.2 结果显示

在这里插入图片描述

这就是人看不懂的索引库,但计算机看的很明白【无奈】

3.3 查询索引 3.3.1 步骤 3.3.2 代码实现 @Test public void searchIndex() throws Exception { //1.创建一个Directory对象,指向索引库位置 Directory directory = FSDirectory.open(new File("D:\\Lucene\\index").toPath()); //2.创建一个IndexReader对象 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对象 //参数1:查询对象;参数2:查询结果返回最大的记录数 TopDocs topDocs = indexSearcher.search(query, 10); //6.取查询结果的总记录数 System.out.println("查询总记录数:" + topDocs.totalHits); //7.取文档列表 ScoreDoc[] scoreDocs = topDocs.scoreDocs; //8.打印文档中的内容 for (ScoreDoc scoredoc : scoreDocs) { //取文档id int docId = scoredoc.doc; //根据Id取文档对象 //与创建的document是一个对象 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.关闭indexReader对象 indexReader.close(); } 3.3.3 结果显示

在这里插入图片描述

3.4 分析器

在这里插入图片描述 在这里插入图片描述

它默认使用的是 标准分析器 但是使用 标准分析器 分析英文得到的是 单词 分析中文的话 得到的是 单个字(无意义) 因此 不可以使用 标准分析器 分析中文

3.5 中文分析器 3.5.1 pom.xml 7.4.0 junit junit 4.12 compile commons-io commons-io 2.4 org.apache.lucene lucene-core ${lucene.version} org.apache.lucene lucene-analyzers-common ${lucene.version} org.apache.lucene lucene-queryparser ${lucene.version} org.apache.lucene lucene-highlighter ${lucene.version} com.chenlb.mmseg4j mmseg4j-core 1.10.0 org.htmlparser htmlparser 2.1 com.sun tools com.chenlb.mmseg4j mmseg4j-solr 2.3.0 org.apache.solr solr-core 3.5.2 代码实现

在这里插入图片描述

@Test public void createIndex() throws Exception { //1.创建一个Directory对象,指定索引库保存的位置 //1.1把索引库保存在内存中 //Directory directory = new RAMDirectory(); //1.2把做因结构保存在磁盘 Directory directory = FSDirectory.open(new File("D:\\Lucene\\index").toPath()); //2.基于Directory 对象创建一个IndexWriter对象 IndexWriterConfig config = new IndexWriterConfig(new ComplexAnalyzer()); IndexWriter indexWriter = new IndexWriter(directory, config); //3.读取磁盘上的文件,对应每个文件创建一个文档对象 File dir = new File("D:\\Lucene\\searchsource"); File[] files = dir.listFiles(); for (File f : files) { //取文件名 String fileName = f.getName(); //文件的路径 String filePath = f.getPath(); //文件的内容 String fileContent = FileUtils.readFileToString(f, "utf-8"); //文件的大小 long fileSize = FileUtils.sizeOf(f); //创建Field //参数1:域的名称;参数2:域的值;参数3:是否进行存储 Field fieldName = new TextField("name", fileName, Field.Store.YES); //就采不分词,不保存,只存储的方式 Field fieldPath = new StoredField("path", filePath); Field fieldContent = new TextField("content", fileContent, Field.Store.YES); //采用分析索引,不存储,但是可以进行数值运算 Field fieldSizeValue = new LongPoint("size", fileSize); //就采不分词,不保存,只存储的方式 Field fieldSize = new StoredField("size", fileSize); //创建文档对象 Document document = new Document(); //4.向文档对象中添加域 document.add(fieldName); document.add(fieldPath); document.add(fieldContent); document.add(fieldSizeValue); document.add(fieldSize); //5.把文档对象写进索引库 indexWriter.addDocument(document); } //6.关闭indexWriter对象 indexWriter.close(); } 3.5.3 查看结果

在这里插入图片描述

3.6 Luck

点击获取Luck 提取码:jrb3 复制这段内容后打开百度网盘手机App,操作更方便哦

打开 指定位置为索引库的位置 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

3.7 Field域的属性

是否分析:是否对域的内容进行分词处理。前提是我们要对域的内容进行查询。 是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可搜索到。 比如:商品名称、商品简介分析后进行索引,订单号、身份证号不用分析但也要索引,这些将来都要作为查询条件。 是否存储:将Field值存储在文档中,存储在文档中的Field才可以从Document中获取 比如:商品名称、订单号,凡是将来要从Document中获取的Field都要存储。

是否存储的标准:是否要将内容展示给用户

在这里插入图片描述

在这里插入图片描述 上文中的代码 ,都是用TextField 存储的,不太合适,我们可以进行以下修改 在这里插入图片描述 Luck查看 在这里插入图片描述

4. Lucene维护索引库 4.1 添加文档 4.1.1 代码实现 @Test public void addDocument() throws Exception { //1.创建一个IndexWriter对象,需要使用ComplexAnalyzer作为分析器 IndexWriter indexWriter = new IndexWriter(FSDirectory.open( new File("D:\\Lucene\\index").toPath()), new IndexWriterConfig(new ComplexAnalyzer())); //2.创建一个Document 对象 Document document = new Document(); //3.向document 中添加域 document.add(new TextField("name","新添加的文件", Field.Store.YES)); document.add(new TextField("content","新添加的文件", Field.Store.NO)); document.add(new StoredField("name","f:/temp/hello")); //4.把文档写进索引库 indexWriter.addDocument(document); //5.关闭索引库 indexWriter.close(); } 4.1.2 查看结果

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

4.2 删除文档 4.2.1 删除所有文档 4.2.1.1 代码实现 IndexWriter indexWriter =null; @Before public void init() throws IOException { indexWriter = new IndexWriter(FSDirectory.open( new File("D:\\Lucene\\index").toPath()), new IndexWriterConfig(new ComplexAnalyzer())); } @Test public void deleteDocument() throws Exception { indexWriter.deleteAll(); indexWriter.close(); } 4.2.1.2 查看结果

在这里插入图片描述

4.2.2 针对性删除 4.2.2.1 信息介绍

索引库共有15个document, 在这里插入图片描述

4.2.2.2 代码实现

在这里插入图片描述

IndexWriter indexWriter =null; @Before public void init() throws IOException { indexWriter = new IndexWriter(FSDirectory.open( new File("D:\\Lucene\\index").toPath()), new IndexWriterConfig(new ComplexAnalyzer())); } @Test public void deleteDoumentByCondition() throws IOException { indexWriter.deleteDocuments(new Term("name","apache")); indexWriter.close(); } 4.2.2.3 查看结果

在这里插入图片描述 在这里插入图片描述

4.3 修改文档 4.3.1 信息介绍

在这里插入图片描述

4.3.2 代码实现 @Test public void updateDocument() throws IOException { Document document = new Document(); document.add(new TextField("name","update 之后的文档",Field.Store.YES)); document.add(new TextField("name1","update 之后的文档1",Field.Store.YES)); document.add(new TextField("name2","update 之后的文档2",Field.Store.YES)); indexWriter.updateDocument(new Term("name","spring"),document); indexWriter.close(); } 4.3.3 查询结果

在这里插入图片描述

4.4 查询文档 4.4.1 提取公用代码 package com.chao.lucene; import org.apache.lucene.document.Document; import org.apache.lucene.document.LongPoint; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; 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.FSDirectory; import org.junit.Before; import org.junit.Test; import java.io.File; import java.io.IOException; /** * ClassName:SearchIndex * Package:com.chao.lucene * Description: * * @Date:2020/3/19 21:34 * @Author: wxc */ public class SearchIndex { private IndexReader indexReader; private IndexSearcher indexSearcher; @Before public void init() throws IOException { indexReader = DirectoryReader.open( FSDirectory.open(new File("D:\\Lucene\\index").toPath())); indexSearcher = new IndexSearcher(indexReader); } public void printResult(Query query) throws IOException { TopDocs topDocs = indexSearcher.search(query, 10); System.out.println("总记录数:"+topDocs.totalHits); ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoredoc : scoreDocs) { //取文档id int docId = scoredoc.doc; //根据Id取文档对象 //与创建的document是一个对象 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.关闭indexReader对象 indexReader.close(); } } 4.4.2 TermQuery 4.4.2.1 适用范围

TermQuery,通过项查询,TermQuery不使用分析器所以建议匹配不分词的Field域查询,比如订单号、分类ID号等。 指定要查询的域和要查询的关键词。

4.4.2.2 代码实现 @Test public void testTermQuery() throws IOException { Query query = new TermQuery(new Term("content", "lucene")); printResult(query); } 4.2.2.3 查看结果

在这里插入图片描述

4.4.3 RangeQuery 4.4.3.1 适用范围

数值范围内的查询

4.4.3.2 代码实现 @Test public void testRangeQuery() throws IOException { //创建一个query对象 Query query = LongPoint.newRangeQuery("size", 0L, 100L); printResult(query); } 4.4.3.3 查看结果

在这里插入图片描述

4.4.3 queryparser 4.4.3.1 适用范围

我查询的是一句话,它是带分析的查询,首先通过分词后,再根据分词后的结果在进行查询。 在这里插入图片描述 需要的依赖

org.apache.lucene lucene-queryparser ${lucene.version} 4.4.3.2 代码实现 @Test public void testQueryParser() throws IOException, ParseException { //创建QueryParser //参数1:默认域 //参数2:分析器对象 QueryParser queryParser = new QueryParser("name",new ComplexAnalyzer()); //使用 QueryParser ,创建 QueryParser对象 , Query query = queryParser.parse("lucene是一个Java开发的全文检索工具包"); printResult(query); } 4.4.3.3 查看结果

在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3