最详细的Lucene实现全文检索

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

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <!-- 读取文件的IO -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <!-- lucene核心库 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>7.4.0</version>
        </dependency>
        <!-- Lucene的查询解析器 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>7.4.0</version>
        </dependency>
        <!-- lucene的默认分词器库 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>7.4.0</version>
        </dependency>
        <!-- lucene的高亮显示 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-highlighter</artifactId>
            <version>7.4.0</version>
        </dependency>
    </dependencies>

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

    <properties>
        <lucene.version>7.4.0</lucene.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId> org.apache.lucene</groupId>
            <artifactId> lucene-core</artifactId>
            <version> ${lucene.version}</version>
        </dependency>
        <dependency>
            <groupId> org.apache.lucene</groupId>
            <artifactId> lucene-analyzers-common</artifactId>
            <version> ${lucene.version}</version>
        </dependency>
        <dependency>
            <groupId> org.apache.lucene</groupId>
            <artifactId> lucene-queryparser</artifactId>
            <version> ${lucene.version}</version>
        </dependency>
        <dependency>
            <groupId> org.apache.lucene</groupId>
            <artifactId> lucene-highlighter</artifactId>
            <version> ${lucene.version}</version>
        </dependency>

        <!--  中文分析器  -->

        <dependency>
            <groupId>com.chenlb.mmseg4j</groupId>
            <artifactId>mmseg4j-core</artifactId>
            <version>1.10.0</version>
        </dependency>
        <dependency>
            <groupId>org.htmlparser</groupId>
            <artifactId>htmlparser</artifactId>
            <version>2.1</version>
            <exclusions>
                <exclusion>
                    <groupId>com.sun</groupId>
                    <artifactId>tools</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 如下可以编译最新的mmseg4j-analysis替换,不然加载报错 -->
        <dependency>
            <groupId>com.chenlb.mmseg4j</groupId>
            <artifactId>mmseg4j-solr</artifactId>
            <version>2.3.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.solr</groupId>
                    <artifactId>solr-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

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 适用范围

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

		<dependency>
            <groupId> org.apache.lucene</groupId>
            <artifactId> lucene-queryparser</artifactId>
            <version> ${lucene.version}</version>
        </dependency>
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 查看结果

在这里插入图片描述

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
使用Lucene实现对MySQL数据表的全文检索是一种可行的方案。Lucene是一套开源的全文检索和搜寻的程式库,它提供了一个简单但强大的应用程式接口,能够实现全文索引和搜寻的功能。在Java开发环境中,Lucene是一个成熟的免费开源工具,被广泛应用于信息检索领域。 全文检索是一种针对非结构化数据的检索方法,对于像磁盘上的文件、网站资源等非结构化数据,无法使用SQL语句进行查询,因此需要使用全文检索法。全文检索法将非结构化数据中的一部分信息提取出来进行组织,形成索引,然后根据索引快速定位到要查找的信息。Lucene可以实现全文检索的功能,它是Apache软件基金会支持和提供的工具包。 使用Lucene实现全文检索的流程如下: 1. 创建索引:首先获取要进行检索的文档,可以是磁盘文件或网站资源等,然后构建文档对象,包括多个域,如文件名称、文件路径、文件大小、文件内容等。接下来对文档进行分词,将分词结果创建为索引并添加到索引库中。 2. 索引搜索:创建查询对象,执行查询并渲染结果。在倒排索引词典表中查找对应搜索词的索引,然后找到索引所链接的文档。例如,搜索语法为"fileName:lucene"表示搜索文件名中包含Lucene的文档。 要使用Lucene实现全文检索,首先需要下载和配置Lucene。你可以从官方网站或其他可信的资源下载Lucene的安装包,并按照相应的指南进行配置。然后,你可以使用Lucene提供的API来实现全文检索功能,根据具体需求进行代码编写和调用。 总之,Lucene是一种强大的全文检索工具,可以帮助你在MySQL数据表中实现全文检索功能。你可以通过学习和使用Lucene的API来了解更多关于Lucene的功能和用法,并根据具体需求进行相应的实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【springboot微服务】Lucence实现Mysql全文检索](https://blog.csdn.net/zhangcongyi420/article/details/129940816)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [【Lucene&Solr】Lucene实现全文检索](https://blog.csdn.net/qq_43705275/article/details/107229299)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值