首页 > 其他分享 >搜索引擎1-认识全文检索

搜索引擎1-认识全文检索

时间:2023-06-15 20:32:01浏览次数:36  
标签:文件 索引 认识 搜索引擎 lucene 全文检索 文档 org Document

1.关于全文检索需要懂的

什么叫做全文检索呢?这要从我们生活中的数据说起。我们生活中的数据总体分为两种:

  1. 结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等。
  2. 非结构化数据(也叫全文数据) :指不定长或无固定格式的数据,如邮件,word文档等。
  3. 半结构化数据:如XML,HTML等,当根据需要可按结构化数据来处理,也可抽取出纯文本按非结构化数据来处理。

按照数据的分类,搜索也分为两种:

  1. 对结构化数据的搜索 :如对数据库的搜索,用SQL语句。再如对元数据的搜索,如利用windows搜索对文件名,类型,修改时间进行搜索等。
  2. 对非结构化数据的搜索 :如利用windows的搜索也可以搜索文件内容,Linux下的grep命令,再如用Google和百度可以搜索大量内容数据。

对非结构化数据也即对全文数据的搜索主要有两种方法:

  1. 顺序扫描法 (Serial Scanning)

所谓顺序扫描,比如要找内容包含某一个字符串的文件,就是一个文档一个文档的看,对于每一个文档,从头看到尾,如果此文档包含此字符串,则此文档为我们要找的文件,接着看下一个文件,直到扫描完所有的文件。如利用windows的搜索也可以搜索文件内容,只是相当的慢。如果你有一个80G硬盘,如果想在上面找到一个内容包含某字符串的文件,不花他几个小时,怕是做不到。Linux下的grep命令也是这一种方式。

这种方法比较原始,但对于小数据量的文件,这种方法还是最直接,最方便的。但是对于大量的文件,这种方法就很慢了。

    2.全文检索

将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。

正排索引

根据文档找词!

搜索引擎1-认识全文检索_全文检索

为什么顺序扫描的速度慢:其实是由于我们想要搜索的信息和非结构化数据中所存储的信息不一致造成的。

倒排索引

非结构化数据中所存储的信息是每个文件包含哪些字符串,也即已知文件,欲求字符串相对容易,也即是从文件到字符串的映射。而我们想搜索的信息是哪些文件包含此字符串,也即已知字符串,欲求文件,也即从字符串到文件的映射。两者恰恰相反。于是如果索引总能够保存从字符串到文件的映射,则会大大提高搜索速度。

搜索引擎1-认识全文检索_搜索_02

倒排索引一般表示为一个关键词,然后是它的频度(出现的次数),位置(出现在哪一篇文章或网页中,及有关的日期,作者等信息),它相当于为互联网上几千亿页网页做了一个索引,好比一本书的目录、标签一般。想看哪一个主题相关的章节,直接根据目录即可找到相关的页面。不必再从书的第一页到最后一页,一页一页的查找。

例如:

文章1

超级塞亚人

我是超级塞亚人我喜欢吃苹果,我不是天朝的人,也不是地球人

文章2

天朝大国

我大天朝威武,我大天朝13亿人,我大天朝

文章3

我喜欢游泳

游泳有很多好方法

文章4

动画片

喜欢看动画片,尤其是七龙珠,因为里面有塞亚人,而且塞亚人喜欢吃苹果,他们不是地球人

文章5

运动

喜欢运动,喜欢跑步,喜欢游泳,喜欢健身,喜欢打球

文章6

游戏

我喜欢打游戏,我最幸福的时光就是在天朝吃着苹果玩游戏

关键字:塞亚人 苹果 天朝 地球 七龙珠 游泳 喜欢

塞亚人 

文章1[1],文章4[2], n n n

苹果

文章1[1],文章4[1],文章6[1], n n n

天朝

文章1[1],文章2[2],文章6[1], n n n n

地球

文章1[1],文章4[1], n n

游泳

文章3[1],文章5[1], n n

七龙珠

文章4[1], n

喜欢

文章1[1],文章4[2],文章5[4],文章6[1], n n n n n n n n

倒排索引2个重要构成:

  1. 倒排文件(inverted file):存储倒排索引的物理文件
  2. 倒排索引组成:单词词典和倒排文件。

2.何为倒排索引

核心术语

搜索引擎1-认识全文检索_lucene_03

Index

Lucene的索引(Index)是由多个文件组成,这些文件被存放在同一目录下。

Token

词元(Token)在Lucene与在自然语言处理(NLP)中的概念相同,表示“词元”。词元即自然语言中的基本单位:在中文表现为一个独立的字或词,在英文中表现为一个单词。

Term

经过分词和语言处理后得到的字符串,它是索引的最小单位。

Field

不同的域可以指定不同的索引方式,比如指定不同的分词方式,是否构建索引,是否存储等。

数值型

int、bigint、double

IntPoint、LongPoint、DoublePoint

字符型

varchar

StringField

不做分词处理

文本型

text

TextField

会做分词处理

日期型

date、timestamp、datetime

-

Lucene没有日期型,可将其转为数值型或字符型

Document

文档是索引的基本单位,代表一些域(Field)的集合。在Lucene中,Document是一种逻辑文件。可以近似地认为它表示的是计算机中的一个文件。这个Document是一种抽象的表示,它从各种维度来描述一个数据源中的每一条数据。

可以使用关系型数据库中的记录来理解Document,数据库的每一条记录可以表示为一个Document,而每一列可以用Field来表示。但不同的是,Document并非结构化的,并没有schema的约束。不同的文档保存在不同的段中的,一个段中可以包含多篇文档。新添加的文档被单独保存在一个新生成的段中,随着段的合并,不同的文档会合并到至相同的段中。

Segment

一个Lucene的索引(Index)由多个段组成,段与段之间是独立的。当添加索引时会生成新的Document,但并不是把新的Document 立即添加到同一个索引文件,而是把它们先被写入到不同的小文件(Segment),当小文件的个数达到阈值(段的个数,段中包含的文件数等)时,然后再合并成一个大索引文件(不同的段可以合并)。

Directory

Lucene索引的存放位置。

文档模型

文件名称

扩展名

说明

Segments File

segments_N

保存提交点的信息

Lock File

write.lock

写文件锁,用于防止多个IndexWriters同时写一个文件

Segment Info

.si

保存段的元数据信息

Compound File

.cfs, .cfe

采用混合格式下该文件包括其他所有格式的文件

Fields

.fnm

保存域信息

Field Index

.fdx

保存指向域数据的指针

Field Data

.fdt

保存域数据

Term Dictionary

.tim

保存词项信息

Term Index

.tip

Term Dictionary的索引信息

Frequencies

.doc

记录文档信息,以及文档中词项对应的词频

Positions

.pos

记录词项的位置信息

Payloads

.pay

全文索引的字段,使用了一些像payloads的高级特性会有该文件,保存了term在doc中的一些高级特性

Norms

.nvd, .nvm

文件保存索引字段加权数据

Per-Document Values

.dvd, .dvm

lucene的docvalues文件,即数据的列式存储,用作聚合和排序


Term Vector Index


.tvx


记录文档数据记录中的偏移量

Term Vector Documents

.tvd

记录有词项向量的文档的信息

Term Vector Fields

.tvf

词项向量的域级别信息

Live Documents

.liv

存活文件的信息

Point values

.dii, .dim

记录被索引的点

Segment_N

Segments_N为段的元数据信息文件。保存了此索引包含多少个段,每个段包含多少篇文档等信息。

搜索引擎1-认识全文检索_搜索_04

Lucene当前活跃的Segment都会存在一个Segment Info文件里,也就是segments_N。如果有多个segments_N, 那么序号最大的就是最新的。

  • Format:索引文件格式的版本号。由于Lucene是在不断开发过程中的,不同版本的Lucene可能有不同索引文件格式,所以规定了文件格式的版本号。
  • Version:索引的版本号
  • NameCount:下一个新段的段名
  • SegCount:段的个数

域文件格式

域元数据文件(fnm)

一个段(Segment)包含多个域,每个域都有一些元数据信息,保存在.fnm文件中,.fnm文件的格式如下:

搜索引擎1-认识全文检索_lucene_05

域的数据信息存储在 .fdt 和 .fdx 文件中。其中,.fdx 文件中存放FieldValuesPositon,指向.fdt文件,也就是说域的具体数据是存放在fdt文件中的。

域数据文件(fdt)

真正保存域(stored field)信息的是fdt文件。

假如在一个Segment中包含N篇文档,那么fdt文档中一会有N个项,每一个项都保存对应文档的域信息。

  • FieldCount,表示此文档包含的域数目
  • 紧接着是FieldCount域信息项,每个项保存一个域的信息。对于每一个域的信息:
  • FieldNum是域编号
  • 接着是一个8bit的byte。根据填充值(0或1),代表不同的意义。最低一位表示此域是否分词;倒数第二位表示此域保存的是字符串数据还是二进制数据;倒数第三位表示此域是否被压缩。最后存储的是这个存储域的值。

域索引文件(fdx)

由域数据文件格式可知,每篇文档包含的域的个数、每个存储域的值都是不一样的。

因为segment中会包含N篇文档(Document),每篇文档占用的大小也是不一样的,那么如何快速在fdt文件中辨别每一篇文档的起始地址和终止地址?如何能够更快的找到第N篇文档的存储域的信息呢?

这就需要借助域索引文件。域索引文件也总共有N个项(如果segment中包含N篇Document),每篇文档都对应一个项,每一项中都存储一个Long型数值(大小固定),该数值代表文档在fdt中的起始地址偏移量。

搜索引擎1-认识全文检索_搜索_06

词向量文件

词向量信息是从索引(Index)到文档(Document)到域(Field)到词(Term)的正向信息,有了词向量信息,就可以得到一篇文档包含哪些词的信息 。

搜索引擎1-认识全文检索_全文检索_07

词向量数据文件(tvd)

首先,是此文档包含域的个数:NumFields

  • 之后,是一个NumFields大小的数组,数组每一项都是域号
    • 最后,是(NumField - 1)大小的数组。每一篇文档的第一个域的偏移量信息存储在 tvx 文件中。而其他(NumFields - 1)域的偏移量就是第一个域的偏移量加上第(NumField - 1)个数组的值。

    词向量索引文件(tvx)

    一个段(segment)包含N篇文档,此文件就有N项,每一项代表一篇文档。每一项包含两部分信息

    • 第一部分是词向量文档文件(tvd)中此文档的偏移量
    • 第二部分是词向量文件(tvf)中此文档的第一个域的偏移量

    词向量域文件(tvf)

    该文件包含了此段(Segment)中的所有域,并且不对文档做区分,到底第几个域到第几个域是属于那篇文件,是由tvx文件中的第一个域的偏移量以及tvd文件中的(NumField - 1)个域的偏移量来决定哪些域数据属于哪个文档。

    对于每一个域,包含如下项:

    • 首先,是说明此域中包含的多少(NumTerms)个词(Term)
    • 之后,是8bit的byte(最后一位指定是否保存位置信息,倒数第二位表示是否保存偏移量信息)
    • 最后,NumTerms个项的数组,每一项代表一个词(Term)。每一个词,由如下几部分构成
    • 词的文本TermText
    • 词频TermFreq(词在该文档中出现的次数)
    • 词的位置
    • 词的偏移量

    3.创建倒排索引流程

    搜索引擎1-认识全文检索_lucene_08

    全文检索的索引创建过程一般有以下几步:

    第一步(原始素材)

    为了方便说明索引创建过程,这里特意用两个文件为例:

    • 文件一:Students should be allowed to go out with their friends, but not allowed to drink beer.
    • 文件二:My friend Jerry went to school to see his students but found them drunk which is not allowed.

    第二步(分词)

    将原文档传给分词器(Tokenizer),分词器会做以下几件事情( 此过程称为Tokenize) :

    1. 将文档分成一个一个单独的单词。
    2. 去除标点符号。
    3. 去除停词(Stop word) 。

    所谓停词(Stop word)就是一种语言中最普通的一些单词,由于没有特别的意义,因而大多数情况下不能成为搜索的关键词,因而创建索引时,这种词会被去掉而减少索引的大小。

    每一种语言的分词组件(Tokenizer),都有一个停词(stop word)集合。

    经过分词(Tokenizer) 后得到的结果称为词元(Token) ,如下:

    “Students”,“allowed”,“go”,“their”,“friends”,“allowed”,“drink”,“beer”,“My”,“friend”,“Jerry”,“went”,“school”,“see”,“his”,“students”,“found”,“them”,“drunk”,“allowed”。

    第三步(语言处理)

    将得到的词元(Token)传给语言处理组件(Linguistic Processor),语言处理组件(linguistic processor)主要是对得到的词元(Token)做一些同语言相关的处理。

    对于英语,语言处理组件(Linguistic Processor) 一般做以下几点:

    1. 变为小写(Lowercase) 。
    2. 将单词缩减为词根形式,如“cars ”到“car ”等。这种操作称为:stemming 。
    3. 将单词转变为词根形式,如“drove ”到“drive ”等。这种操作称为:lemmatization 。

    经过语言处理,得到的词(Term)如下:

    “student”,“allow”,“go”,“their”,“friend”,“allow”,“drink”,“beer”,“my”,“friend”,“jerry”,“go”,“school”,“see”,“his”,“student”,“find”,“them”,“drink”,“allow”

    第四步(构建索引)

    将得到的词(Term)传给索引组件(Indexer),索引组件(Indexer)主要做以下几件事情:

    1. 利用得到的词(Term)创建一个字典。

    Term

    文档编号

    student

    1

    allow

    1

    go

    1

    their

    1

    friend

    1

    allow

    1

    drink

    1

    beer

    1

    my

    2

    friend

    2

    jerry

    2

    go

    2

    school

    2

    see

    2

    his

    2

    student

    2

    find

    2

    them

    2

    drink

    2

    allow

    2

    1. 对字典按字母顺序进行排序。
    2. 合并相同的词(Term) 成为文档倒排(Posting List) 链表。

    4.Lucene构建索引代码示例

    版本需求

    JDK 1.8

    Lucene 7.7.0

    具体代码

    pom.xml

    <properties>
      <java.version>1.8</java.version>
      <lucene.version>7.7.0</lucene.version>
    </properties>
    
    <dependencies>
      <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-queries</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-analyzers-smartcn</artifactId>
        <version>${lucene.version}</version>
      </dependency>
    
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
      </dependency>
    </dependencies>

    创建索引代码示例:

    import org.apache.commons.io.FileUtils;
    import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
    import org.apache.lucene.document.*;
    import org.apache.lucene.index.*;
    import org.apache.lucene.queryparser.classic.ParseException;
    import org.apache.lucene.queryparser.classic.QueryParser;
    import org.apache.lucene.search.*;
    import org.apache.lucene.store.Directory;
    import org.apache.lucene.store.FSDirectory;
    
    import java.io.File;
    import java.io.IOException;
    import java.nio.file.Paths;
    
    public class LuceneIndexDemo {
        // 创建索引
        public void createIndex() throws IOException {
            // 原始文档的路径
            File path = new File("D:/Lucene/data");
    
            // 索引存放路径
            Directory directory = FSDirectory.open(Paths.get("D:/Lucene/index"));
    
            // 创建标准分析器
            SmartChineseAnalyzer analyzer = new SmartChineseAnalyzer();
    
            // 创建IndexWriterConfig
            IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
            // 是否使用复合索引格式
            iwc.setUseCompoundFile(true);
    
            //创建IndexWriter
            IndexWriter indexWriter = new IndexWriter(directory, iwc);
    
            for (File file : path.listFiles()) {
                // 创建Document对象
                Document document = new Document();
                // 文件名称
                document.add(new TextField("filename", file.getName(), Field.Store.YES));
                // 文件内容
                document.add(new TextField("content", FileUtils.readFileToString(file, "GBK"),
                        Field.Store.YES));
                // 文件路径
                document.add(new StoredField("path", file.getPath()));
                // 文件大小
                document.add(new NumericDocValuesField("size", FileUtils.sizeOf(file)));
    
                // 写入索引
                indexWriter.addDocument(document);
            }
    
            // 写入完毕,清理工作
            if (indexWriter != null) {
                indexWriter.close();
                indexWriter = null;
            }
        }
    }

    标签:文件,索引,认识,搜索引擎,lucene,全文检索,文档,org,Document
    From: https://blog.51cto.com/u_13222507/6476609

    相关文章

    • Java 多线程同步问题的探究(三、Lock来了,大家都让开【1. 认识重入锁】)
      在上一节中,我们已经了解了Java多线程编程中常用的关键字synchronized,以及与之相关的对象锁机制。这一节中,让我们一起来认识JDK5中新引入的并发框架中的锁机制。我想很多购买了《Java程序员面试宝典》之类图书的朋友一定对下面这个面试题感到非常熟悉:问:请对比synchronized......
    • 从 SpringApplication 认识 Spring 应用启动过程
      一、SpringApplication是什么?Spring应用的启动类。二、SpringApplication执行了什么?创建ApplicationContext实例ApplicationContext就是我们所说的容器实例。注册CommandLinePropertySourceCommandLinePropertySource的作用是将命令行参数输出为Spring属性。......
    • c关键字认识
      下表列出了C中的保留字。这些保留字不能作为常量名、变量名或其他标识符名称。关键字说明auto声明自动变量break跳出当前循环case开关语句分支char声明字符型变量或函数返回值类型const定义常量,如果一个变量被const修饰,那么它的值就不能再被改变cont......
    • 通用搜索引擎背后的技术点
      垂直搜索引擎垂直搜索又称为垂搜,是特定领域的搜索,比如用QQ音乐搜周杰伦的歌等。 2.2搜索和推荐搜索和推荐经常被相提并论,但是二者存在一些区别和联系。共同点宏观上来说,搜索和推荐都是为了解决用户和信息之间的隔离问题,给用户有用的/需要的/喜欢的信息。区别点搜索一般是用户主动......
    • 基于Drone+Gogs流水线-全面认识轻量级云原生CI引擎Drone
      1.介绍DronebyHarness™是一个基于Docker容器技术的可扩展的持续集成引擎,用于自动化测试、构建、发布。每个构建都在一个临时的Docker容器中执行,使开发人员能够完全控制其构建环境并保证隔离。开发者只需在项目中包含.drone.yml文件,将代码推送到git仓库,Drone就能够自动化的......
    • Lucene--开放源代码的全文检索引擎工具包
      Lucene是apache软件基金会4jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的......
    • RCU的简单认识
      RCURUC是什么?RCU(Read-Copy-Update)是一种用于并发编程的技术,旨在提供高效且无锁(lock-free)的读操作,同时保证数据一致性和并发性。也就是说他并不需要锁的机制来保障数据一致性和并发现.1.RCU的实现原理RCU的实现本质上是为了解决读写锁的问题,因为读者可以多数的问题,而......
    • 认识 ArgoCD
      ArgoCD官网:https://argo-cd.readthedocs.io/en/stable/应用程序的定义、配置和环境应该是声明式的,并受版本控制。应用程序部署和生命周期管理应该是自动化的、可审计的,并且易于理解。ArgoCD遵循GitOps模式,使用Git存储库作为定义所需应用程序状态的真实源。Kubernetes清单可......
    • Python借助百度搜索引擎爬取Python小屋密切相关文章
      封面图片:《Python程序设计实验指导书》(ISBN:9787302525790),董付国,清华大学出版社=============第一步,查看本机Chrome浏览器版本。第二步,下载正确版本的Chrome浏览器驱动然后放到Python安装目录中,同时确保Python安装目录在系统环境变量Path中,下载地址为http://chromedriver.storage.go......
    • java——微服务——spring cloud——Nacos——Nacos认识与安装
                     Nacos开发必知Nacos开发必知官网:https://nacos.io/zh-cn/index.htmlNocas文档:https://nacos.io/zh-cn/docs/what-is-nacos.htmlNocas下载:https://github.com/alibaba/nacos/releases  说明:1.4.0以下使用的mysql驱......