Lucene全文检索技术

Lucene流程分析

一、什么是全文检索
1、数据的分类
1)结构化数据:格式固定、长度固定、数据类型固定。例如数据库中的数据
2)非结构化数据:格式不固定、长度不固定、数据类型不固定。例如Word文档、pdf文档、邮件、html、txt

2、数据的查询
1)结构化数据的查询:SQL语句,查询结构化数据的方法。简单、速度快。
2)非结构化数据的查询:从文本文件中找出包含spring单词的文件。
1、目测
2.使用程序吧文档读取到内存中,然后匹配字符串。顺序扫描。
3、把非结构化数据变成结构化数据
先跟根据空格进行字符声拆分,得到一个单词列表,基于单词列表创建一个索引。然后查询索引,根据单词和文档的对应关系找到文档列表。这个过程叫做全文检索。
索引:一个为了提高查询速度,创建某种数据结构的集合.

3.全文检索:先创建索引然后查询索引的过程叫做全文检索.
索引一次创建可以多次使用。表现为每次查询速度很快。

二、全文检索的应用场景
1、搜索引擎:百度、360搜索、谷歌、搜狗
2、站内搜索:论坛搜索、微博、文章搜索
3、电商搜索:淘宝搜索、京东搜索
4、只要是有搜索的地方就可以使用全文检索技术

三、什么是Lucene
Lucene是一个基于Java开发全文检索工具包

四、Lucene实现全文检索的流程

在这里插入图片描述A、绿色表示索引过程,对要搜索的原始内容进行索引构建一个索引库,索引过程包括:
确定原始内容即要搜索的内容→采集文档→创建文档→分析文档→索引文档

B、红色表示搜索过程,从索引库中搜索内容,搜索过程包括:

用户通过搜索界面>创建查询≥执行搜索,从索引库搜索>渲染搜索结果

1、创建索引

1)获得文档
原始文档:要基于那些数据来进行搜索,那么这些数据就是原始文档。
搜索引擎:使用爬虫获得原始文档
站内搜索:数据库中的数据

2)构建文档对象
对应每个原始文档创建一个Document对 象,每个document对象中包含多个域(field)。域中保存就是原始文档数据。
域的名称
域的值
每个文档都有一一个唯一的编号, 就是文档id

3)分析文档
就是分词的过程
1.根据空格进行字符串拆分,得到一-个单词列表。
2.把单词统一转换成小写。
3、去除标点符号。
4、去除停用词。停用词:无意义的词

每个关键词都封装成一个Term对象中
Term中包含两部分内容:关键词所在的域、关键词本身。
不同的域中拆分出来的相同的关键词是不同的Term

4)创建索引
基于关键词列表创建一个索引,保存到索引库中。
索引库中:索引、document对象、关键词文档的对应关系。
通过词语找文档,这种索引的结构叫做倒排索引结构

2、查询索引
1)用户查询接口:用户输入查询条件的地方。例如:百度的搜索框
2)把关键词封装成一个查询对象:要查询的域、要搜索的关键词
3)执行查询:根据要查询的关键词到对应的城上进行搜索。找到关键词,根据关键词找到对应的文档。
4)渲染结果
根据文档的id找到文档对象,对关键词进行高亮显示;分页处理,最终展示给用户看。|

入门程序

1、导入jar坐标

<packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>7.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>4.10.0</version>
        </dependency>
        <dependency>
            <groupId></groupId>
            <artifactId></artifactId>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

2、编写代码
创建索引的步骤

1、创建一个Directory对象,指定索引库保存的位置
2、基于Directory对象创建一个IndexWriter对象
3、取磁盘上的文件,对每一个文件创建一个文档对象
4、向文档对象中添加域
5、把文档对象写入索引
6、关闭IndexWriter对象

实现步骤如下:

public void createIndex() throws Exception{
    
    
        //1、创建一个Directory对象,指定索引库保存的位置
        //Directory directory = new RAMDirectory();       //把索引库保存到内存中
        Directory directory = FSDirectory.open(new File("D:\\Downloads\\java_project\\lucene\\index").toPath());          //把索引库保存到磁盘中

        //2、基于Directory对象创建一个IndexWriter对象
        IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig());

        //3、取磁盘上的文件,对每一个文件创建一个文档对象
        File dir = new File("D:\\Downloads\\java_project\\index\\index\\src\\test\\day10");
        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
            //参数一:域的名称、参数二:域的内容、参数三:是否存储【将内容保存到磁盘】
            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();

    }

成功的显示效果如下:
会在指定的目录下生成以下五个二进制文件
在这里插入图片描述

查询索引的步骤

1、创建一个Directory对象,指定索引库的位置
2、创建一个IndexReader对象
3、创建一个IndexSearcher对象,构造方法中的参数就是IndexReader对象
4、创建一个Query对象,TermQuery
5、执行查询,得到一个TopDocs对象
6、获取查询结果的总记录数
7、获取文档列表
8、打印文档文档的内容
9、关闭IndexReader对象

实现代码如下

public void searchIndex() throws Exception {
    
    
        //1、创建一个Directory对象,指定索引库的位置
        Directory directory = FSDirectory.open(new File("D:\\Downloads\\java_project\\lucene\\index").toPath());          //把索引库保存到磁盘中

        //2、创建一个IndexReader对象
        IndexReader indexReader = DirectoryReader.open(directory);

        //3、创建一个IndexSearcher对象,构造方法中的参数就是IndexReader对象
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        //4、创建一个Query对象,TermQuery
        //表示在content域中查找包含public关键字的Team
        Query query = new TermQuery(new Term("content", "public"));

        //5、执行查询,得到一个TopDocs对象
        //参数一:查询对象、参数二:结果返回的最大记录条数
        TopDocs topDecs = indexSearcher.search(query, 10);

        //6、获取查询结果的总记录数
        System.out.println("查询总记录数" + topDecs.totalHits);

        //7、获取文档列表
        ScoreDoc[] scoreDocs = topDecs.scoreDocs;

        //8、打印文档文档的内容
        for (ScoreDoc scoreDoc : scoreDocs) {
    
    
            //取文档ID
            int docId = scoreDoc.doc;
            //根据ID取文档对象
            Document document = indexSearcher.doc(docId);
            System.out.println(document.get("name"));
            System.out.println(document.get("path"));
            System.out.println(document.get("content"));
            System.out.println(document.get("size"));
            System.out.println("================华丽的分割线===============");
        }

        //9、关闭IndexReader对象
        indexReader.close();
    }

成功显示效果如下:
会在控制台显示文件中的内容
在这里插入图片描述

分析器

默认使用的是标准分析器StandAnalyzer
1、如何查看分析器的分析效果
使用Analyzer对象的tokenStream方法,可以返回一个TokenStream对象(包含了最终的分词结果)。

实现步骤:
1、创建一个Analyzer对象,StandardAnalyzer对象
2、使用过分析器对象的tokenStream方法获取一个TokenStream对象
3、向TokenStream对象中设置一个引用,相当于一个指针
4、调用TokenStream对象的reset方法,将指针置顶,不过不调用会抛出异常
5、使用while循环遍历TokenStream对象
6、释放资源,关闭TokenStream对象

实现代码如下:

public void testTokenStream() throws Exception {
    
    
        //1、创建一个Analyzer对象,StandardAnalyzer对象
        StandardAnalyzer analyzer = new StandardAnalyzer();

        //2、使用过分析器对象的tokenStream方法获取一个TokenStream对象
        TokenStream tokenStream = analyzer.tokenStream("", "我在等风的同时,也在等你!!I am here waitting for you !!");

        //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的使用方法

1)添加IKAnalyze的坐标

<dependency>
            <groupId>com.jianggujin</groupId>
            <artifactId>IKAnalyzer-lucene</artifactId>
            <version>8.0.0</version>
        </dependency>

2)把配置文件和扩展词典添加到工程的classpath下
这些配置文件可以再jar包中找到
在这里插入图片描述

注意:扩展词典严禁使用windows记事本嫡辑保证扩展词典的嫡码格式是utf-8
扩展词典:添加一些新词
停用词词典:无意义的词或者是敏感词汇

猜你喜欢

转载自blog.csdn.net/qq_44796093/article/details/111870143