ElasticSearch:全文检索及倒排索引原理

在这里插入图片描述

1.从全文检索说起

首先介绍一下结构化与非结构化数据:

  • 结构化数据将数据具有的特征事先以结构化的形式定义好,数据有固定的格式或有限的长度。典型的结构化数据就是传统关系型数据库的表结构,数据特征直接体现在表结构的字段上,所以根据某一特征做数据检索很直接,速度也比较快
  • 非结构化数据没有预先定义好的结构化特征,也没有固定格式和固定长度。典型的非结构化数据包括文章、图片、视频、网页、邮件等,其中像HTML网页这种具有一定格式的文档也称为半结构化数据

对于非结构化的数据检索,被称为全文检索。

假设现在MySQL中有一张User表,含有三个阶段:姓名name、年龄age和爱好favor:

对于User表来说,整体上是结构化的,比如name、age都可以直接建立索引来快速地检索。
而其中的favor字段是一个text类型,存储的是非结构化的文本数据:
篮球、足球、爱运动的我;本人热爱学习,游戏偶尔也玩!!!!

与结构化查询相比,全文检索面临的最大问题就是性能问题。全文检索最一般的应用场景是根据一些关键字查找包含这些关键字的文档,比如互联网搜索引擎要实现的功能就是根据一些关键字查找网页。显然,如果没有对文档做特别处理,查找的办法似乎只能是逐条比对。

假设现在需要找到favor中含有“足球”这个关键字的User,那么只能使用like模糊查询:
select * from user where favor like '%足球%'

like语句是无法建立索引的,查询时会进行全表扫描,并且在每个favor字段中进行遍历匹配,以找到含有“足球”这个关键字的记录,整体复杂度特别高,所以全文检索也是MySQL这类结构关系式数据库无法很好实现的需求。

全文检索一般是查询包含某一或某些关键字记录,所以通过文档整体值建立的索引对提高查询速度是没有任何帮助的。为了解决这个问题,人们创建了一种新索引方法,这种索引方法就是倒排索引。

2.倒排索引的原理

倒排索引是为了解决上述非结构化数据的检索问题而产生的。

首先明确一下,在ES中存储记录的单位是JSON“文档”,而JSON“文档”中的“字段”也就是组成JSON的一个个KV对。

普通索引也被称为正排索引,也就是通过对主键和结构化字段建立索引,通过这些结构化索引找到文档。

倒排索引则是先将文档中包含的关键字全部提取出来,然后再将关键字与文档的对应关系保存起来,最后再对关键字本身做索引排序。用户在检索某一关键字时,可以先对关键字的索引进行查找,再通过关键字与文档的对应关系找到所在文档。

假设上述的User表通过ES存储,其中两个User文档为:

{
    "_id: 1,
    "name":"pbr1",
    "age":22,
    "favor":"篮球、足球、爱运动的我;本人热爱学习,游戏偶尔也玩!!!!"
}

{
    "_id: 2,
    "name":"pbr2",
    "age":22,
    "favor":"篮球、足球、爱运动的我"
}

其中favor定义为text类型,假设分词器进行以下分词:

  • 文档1的favor分词:“篮球”、“足球”、“爱运动的我”、“本人热爱学习”、“游戏偶尔也玩”这5个token
  • 文档2的favor分词:“篮球”、“足球”、“爱运动的我”这3个token

那么对分词token建立索引,并建立对原始文档的映射,就得到一个以favor进行分词的倒排索引:
在这里插入图片描述

可以看到,倒排索引实际上就是对全文数据结构化的过程。对于存储在关系型数据库中的数据来说,它们依赖于人的预先分析将数据拆解为不同字段,所以在数据插入时就已经是结构化的;而在全文数据库中,文档在插入时还不是结构化的,需要应用程序根据规则自动提取关键字,并形成关键字与文档之间的结构化对应关系。

比如现在需要查询爱好为“篮球”和“足球”的用户,那么可以直接通过倒排索引拿到对应的文档1和文档2,也就查询到了这两个用户。

3.ES索引构建过程

全文检索中提取关键字是非常重要的一步。这些预先提取出来的关键字,在Elasticsearch及全文检索的相关文献中一般称为词项(Term),文档的词项提取在Elasticsearch中称为文档分析(Analysis),是整个全文检索中较为核心的过程。这个过程必须要区分哪些是词项,哪些不是。对于英文来说,它还必须要知道apple和apples指的同一个东西,而run和running指的是同一动作。对于中文来说就更麻烦了,因为中文词语不以空格分隔,所以面临的第一难题是如何将词语分辨出来。

ES底层使用了Lucene来构建索引,一个基本的过程是先对text类型的字段进行分词,分词使用的分词器以配置mapping时指定的为准,默认使用standard分词器,对于中文分词来说,一般建议使用ik_smart或ik_max_word分词器:

暂时无法在文档外展示此内容

关于Lucene如何存储这些分词解析结果可以学习这篇文章:https://www.shenyanchao.cn/blog/2018/12/04/lucene-index-files/

由于文档存储前的分析和索引过程比较耗资源,所以为了提升性能,文档在添加到ES中时并不会立即被编入索引。

默认情况下,ES会每隔1s统一处理一次新加入的文档,可以通过index.refresh_interval参数修改。

为了提升性能,在ES 7中还添加了index.search.idle.after参数,它的默认值是30s:如果索引在一段时间内没有收到检索数据的请求,那么它至少要等30s后才会刷新索引数据。

所以可以看出ES的写入操作实际上是准实时的,新添加到索引中的文档可能在一段时间内不能被检索到,如果的确需要立即检索到文档可以使用强制刷新到索引的方式,包括使用_refresh接口和在操作文档时使用refresh参数等进行强制刷新缓冲区中的索引到磁盘中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/67418.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

内网隧道—HTTP\DNS\ICMP

本文仅限于安全研究和学习,用户承担因使用此工具而导致的所有法律和相关责任! 作者不承担任何法律和相关责任! HTTP隧道 Neo-reGeorg Neo-reGeorg 是一个旨在积极重构 reGeorg 的项目,目的是: 提高可用性&#xff0…

springBoot整合RabbitMq实现手动确认消息

如何保证消息的可靠性投递? 1.保证生产者向broke可靠性投递,开启ack投递成功确认,如果失败的话进行消息补偿 /*** author yueF_L* date 2023-08-10 01:32* ConfirmCallback:消息只要被 RabbitMQ broker 接收到就会触发confirm方…

tomcat7.exe 启动闪退解决

标题tomcat7.exe 启动闪退解决 双击tomcat7.exe启动,但是出现闪退问题,无法启动tomcat 解决: 1.解决 tomcat7.exe 启动闪退解决 第一步:双击打开tomcat7w.exe 文件 如果出现 “指定的服务未安装。 Unable to open the service ‘…

FFmpeg常见命令行(三):FFmpeg转码

前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》。本文是Android音视频任务列表的其中一个, 对应的要学习的内容是:如何使…

vue项目中Uncaught runtime errors:怎样关闭

原文链接: yvue项目中Uncaught runtime errors:怎样关闭_笑毅的博客-CSDN博客https://blog.csdn.net/qq_36877078/article/details/131175355是webpack-dev-server弄出来的 解决办法 在vue.config.js中添加如下配置 module.exports defineConfig({...devServer:…

php代码审计,php漏洞详解

文章目录 1、输入验证和输出显示2、命令注入(Command Injection)3、eval 注入(Eval Injection)4、跨网站脚本攻击(Cross Site Scripting, XSS)5、SQL 注入攻击(SQL injection)6、跨网站请求伪造攻击(Cross Site Request Forgeries, CSRF)7、Session 会话劫持(Session Hijacking…

虾皮运营每天需要做什么?如何处理后台数据?

#shopee#​有很多朋友想做电商,但是对电商运营比较朦胧,不知道电商运营每天到底该做些什么。今天咱们就来解析下,Shopee电商运营每天该做哪些事情一个合格的电商运营,每天都会做好以下几点: 一、查看数据: …

【100天精通python】Day31:使用python操作数据库_数据库编程接口,连接对象和游标对象,数据库连接配置

目录 专栏导读 一、数据库编程接口 1. Python标准库接口 2. MySQL Connector/Python接口 3. Psycopg2接口(用于连接PostgreSQL数据库) 4. SQLAlchemy接口 二、连接对象和游标对象 1. 连接对象(Connection Object) 2. 游标…

❤ vue3 使用 ElementPlus

❤ vue3 使用ElementPlus 承接自上一篇文章 VUE3 项目具体配置(二) ① 使用 ElementPlus Icon 图标 官网地址: https://element-plus.org/zh-CN/component/icon.html 1、安装 yarn add element-plus/icons-vue安装成功以后: …

【分布式技术专题】「数据一致性体系」带你一同建立采用消息队列实现的数据一致性框架技术体系方案

带你一同建立采用消息队列实现的数据一致性框架技术体系方案 分布式服务数据一致性问题采用分布式事务3PC模式3PC模式阶段分析 采用分布式锁采用数据同步机制采用数据分片机制针对常规方案所具有的问题预发送消息阶段切换为可发送状态定时补偿更新为可发送状态定时补偿发送数据…

Java基础篇--基本数据类型

目录 前言: 内置数据类型 类型默认值 示例: 内置数据类型转换 自动类型转换(隐式类型转换): 强制类型转换(显式类型转换): 隐含强制类型转换: 引用类型 前言: …

浅谈JVM中的即时编译器(Just-In-Time compiler, JIT)

Java虚拟机(JVM)中的即时编译器(Just-In-Time compiler, JIT)是一个非常重要的组件,它负责将字节码转换为本地机器代码。在不使用JIT的情况下,JVM通过解释字节码来执行程序,这意味着它会为每个字…

Vue2嵌入HTML页面空白、互相传参、延迟加载等问题解决方案

一、需求分析 最近做的一个用H5加原生开发的html项目,现需要集成到Vue2.0项目里面来。遇到的相关问题做个记录和总结,以便能帮到大家避免踩坑。 二、问题记录 1、页面空白问题 将html页面通过iframe的方式嵌入进来之后,发现页面是空白的&am…

2023牛客暑期多校训练营7(C/I/M)

目录 C.Beautiful Sequence I.We Love Strings M.Writing Books C.Beautiful Sequence 思路:显然若得到了a[1],则整个序列a我们都知道了。所以我们要求出第k大的a[1],这个可以利用序列a为不递减序列的性质来得出。 首先,由题…

商品推荐系统浅析 | 京东云技术团队

一、综述 本文主要做推荐系统浅析,主要介绍推荐系统的定义,推荐系统的基础框架,简单介绍设计推荐的相关方法以及架构。适用于部分对推荐系统感兴趣的同学以及有相关基础的同学,本人水平有限,欢迎大家指正。 二、商品…

独立站如何进行Facebook广告投放?关于广告投放策略的真相

谷歌广告是独立站卖家推广引流的首选渠道,那么谷歌广告该如何投放?在这个过程中有哪些需要特别注意的吗? 创建Facebook广告账户: 访问Facebook广告管理平台(Ads Manager)并创建一个广告账户。您需要提供一…

Towards Open World Object Detection【论文解析】

Towards Open World Object Detection 摘要1 介绍2 相关研究3 开放世界目标检测4 ORE:开放世界目标检测器4.1 对比聚类4.2 RPN自动标注未知类别4.3 基于能量的未知标识4.4 减少遗忘 5 实验5.1开放世界评估协议5.2 实现细节5.3 开放世界目标检测结果5.4 增量目标检测结果 6 讨论…

【ArcGIS Pro二次开发】(56):界址点导出Excel

界址点成果表是地籍测绘中的一种表格,用于记录地块的界址点坐标和相关属性信息。 这个工具的目的就是为了将地块要素导出为界址点成果表。 一、要实现的功能 如上图所示,在【数据处理】组—【Excel相关】面板下,点击【界址点导出Excel】工具。…

linux文件I/O之 open() 函数用法

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> typedef unsigned int mode_t ; int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); 函数功能 打开或创建一个文件 返回值 成功…

21、springboot的宽松绑定及属性处理类的构造注入

springboot的宽松绑定及属性处理类的构造注入 ★ 如何使用属性处理类所读取的属性 属性处理类最终变成了Spring容器中的一个Bean组件&#xff0c;因此接下来Spring即可将该Bean组件注入任意其他组件。 这种做法的好处是&#xff1a;可以将大量的配置信息封装一个对象——所以…