学而实习之 不亦乐乎

Elasticsearch 基础:全文搜索概述

2024-02-25 20:40:51

一、全文搜索概述

全文搜索也称为全文检索,它的工作原理是计算机索引程序通过扫拙文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。

由于在执行搜索之前,搜索的关键字已经被建立了索引,因此搜索时的速度往往很快。

1、数据结构

在理解全文搜索的概念之前,先对数据结构进行理解。数据结构主要分为结构化数据与非结构化数据。

(1)结构化数据:指具有固定格式或有限长度的数据,如数据库、元数据等。

(2)非结构化数据:指不定长或无固定格式的数据 如邮件、 Word 文档等。

2、数据搜索的方式

针对不同的数据结构(结构化数据或是非结构化数据),有不同的数据搜索方式。

【1】 结构化数据的搜索方式

对于结构化的数据而言,数据 般就存储在关系型数据库中,通过 SQL 语句来对数据库进行搜索。

如果是针对元数据的搜索,则可以利用操作系统本身的机制,如利用 Windows 搜索对文件名、类型、修改时间进行搜索等。

【2】菲结构化数据的搜索方式

对于非结构化的数据而言,有下面两种搜索方式

  1. 顺序扫描法( Serial Scanning ):所谓顺序扫描,例如,要找内容包含某一个字符串的文件,就是一个文档一个文档地查看,对于每一个文档,从头看到尾,如果此文档包含此字符串,则此文档为要找的文件,接着看下一个文件,直到扫描完所有的文件 利用 Windows 的搜索也可以搜索到文件的内容 Linux 下的 grep 命令也是这种方式 这些方式都是操作系统提供的简单方法,但对于小数据量的文件而言,这种方法还是最直接、最方便的 但是对于大量的文件,这种方法就很慢了。
  2. 全文检索( Full-text Search ):将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索从而达到搜索相对较快的目的。这部分从非结构化数据中提取出的然后重新组织的信息,我们称为索引。以字典为例,字典的拼音表和部首检字表就相当于字典的索引,对每一个字的解释是非结构化的,如果字典没有音节表和部首检字表,要找一个字只能顺序扫描 然而字的某些信息可以提取出来进行结构化处理,如读音,就比较结构化,分声母和韵母,分别只有几种情况可以一一列举,于是将读音提取出来按一定的顺序排列,每一项读音都指向此字的详细解释的页数。搜索时按结构化的拼音搜到读音,然后按其指向的页数,便可找到非结构化数据,即对字的解释。这种先建立索引,再对索引进行搜索的过程就称为全文搜索

有人可能会说,全文检索的确加快了搜索的速度,但是多了创建索引的过程,两者加起来不一定比顺序扫描快多少。的确,加上索引的过程,全文检索不一定比顺序扫描快,尤其是在数据量小的时候更是如此。而对大量的数据创建索引也是一个很慢的过程。

然而两者还是有区别的,顺序扫描是每次都要扫描,而创建索引的过程仅仅需要一次,以后便一劳永逸了,每次搜索,创建索引的过程不是必需的,仅仅搜索创建好的索引就可以了。

3、全文搜索的原理

实现全文搜索一般分为以下步骤:

【1】建文本库

在开发功能之前,一个信息检索系统需要做一些准备工作,首先,必须建立一个文本数据库,用于保存所有用户可能检索的信息。根据这些信息,确定索引中的文本类型。文本类型是系统识别的信息格式。这种格式应该具有可识别和低冗余的特性,一旦确定了文本类型,就不应当对其进行大的改动。

【2】建立索引

有了文本类型之后,就应该根据数据库中的文本来建立索引。索引可以大大提高信息检索的速。目前,建立索引的方法有很多种。使用哪种方法取决于信息检索系统的大小。大型信息检索系统,如百度、 Goog 等,都是采用倒排的方式来构建索引。

【3】执行搜索

在文档建立索引之后,就可以开始对其进行搜索。这时,通常由用户提交搜索请求,将请求进行分析,然后用文本操作来处理。对于一个真实的信息检索系统而言,在真正处理请求前,还可以对请求进行一些预处理,然后再将请求送到后台,并返回用户需要的信息。

【4】过滤结果

通常情况下,在信息检索系统中检索到用户需要的信息后,还要做进一步操作,即将信息按一定顺序进行排序或过滤,然后返回给用户。这一步实际上关乎到最终用户的体验。

4、全文搜索相关的技术

基于 Java 的全文搜索相关的技术,开源实现如下

Lucene: http://lucene.apache.org/core
Elasticsearch: https://www.elastic.co/cn/products/elasticsearch
Solr: http://lucene.apache.org/solr/

Lucene 是搜索引擎,而 Elasticsearch、Solr 都是基于 Lucene 之上而实现的全文检索系统。其对比, 总结如下

  • Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能。
  • Solr 支持更多格式的数据,如 JSON、XML、CSV,而 Elasticsearch 仅支持 JSON 文件格式。
  • Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多由第三方插件提供。
  • Solr 在传统的搜索应用中表现好于 Elasticsearch ,但在处理实时搜索应用时效率明显低于Elasticsearch。
  • Solr 传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。

二、Elasticsearch 核心概念

Elasticsearch 是一个高度可扩展的开源全文搜索和分析引擎,它允许用户快速地、近实时地对

大数据进行存储、搜索和分析,它通常用来支撑有复杂的数据搜索需求的企业级应用。Elasticsearch 基于 Apache Lucene 构建,作为一个非常流行的开源软件的同时,也有相应的公司提供商业支持,使之非常适合企业用户使用。

Elasticsearch 是一个为云构建的分布式 RESTful 搜索引擎,它有如下特点:

• 分布式、高度可用的搜索引擎。

  • 每个索引都使用可配置数量的分片
  • 每个分片可以有一个或多个副本
  • 在任何副本分片上执行的读取、搜索操作。

• 多租户与多类型

  • 支持多个索引
  • 每个索引支持多个类型
  • 索引级别配置(分片数、索引存储 ... ...)

• 多种 API

  • HTTP RESTful API
  • 原生 JavaAPI
  • 所有 API 执行自动节点操作重新路由

• 面向文档

  • 不需要事先定义模式(Schema)
  • 可以为每个类型定义模式以自定制索引过程

• 对数据持久化提供可靠、异步的写入

• (近)实时搜索

• 建立在 ucene 之上

  • 每个分片是一个功能齐全的 Lucene 索引
  • 容易通过简单的配置/插件来发挥 Lucene 所有的功能

• 保证操作的一致性

  • 每个文档级的操作都是原子的,具备一致性、隔离性和持久性

• 遵循 Apache 协议2(ALv2)

1、基于 Lucene

Elasticsearch 底层是基于 Lucene 来构建的,无论在开源杜区还是专有领域,Lucene 可以被认为是迄今为止最先进、性能最好的、功能最全的 Java 搜索引擎库

但是,Lucene 个相当底层的库,想要使用它,开发人员必须使用 Java 来作为开发语言并将其直接集成到自己的应用中,更糟糕的是, Lucene 在使用上非常复杂,必须要深入了解检索的相关知识来理解它是如何工作的,而这一切都阻碍了开发人员来掌握它。正是因为考虑到上述难点 Elasticsearch 出现了 Elasticsearch 对底层 Lucene 进行了封装,通过简单易用的 RESTful API 暴露接口 从而有效减轻了开发人员的学习成本,让全文搜索的实现不再困难。

如下:只需要使用 curl 软件就能轻松实现搜索

# curl -XGET 'http://localhost:9200/waylau/_search?pretty=true' -H 'Content-Type:application/json' -d '
{
    "query": {
        "match":{"user":"kimchy"}
    }
}'

2、如何查看 Elasticsearch 对应的 Lucene 版本

访问 http://localhost:9200/ 应能看到返回的数据中就有相关信息。

3、近实时

Elasticsearch 个接近实时(Near Realtime, NRT)而非实时的搜索平台,这意味着从索引文档到可搜索的时间有一个轻微的延迟(通常为1秒)。之所以会有这个延时,主要考虑查询的性能优化。 Elasticsearch 其实是可以做到实时的,因为 Lucene 是可以做到实时的,但是这样做,要么是牺牲索引的效率(每次索引之后刷新),要么就是牺牲查询的效率(每次查询之前都进行刷新 ),所以 Elasticsearch 采取一种折中的方案,每隔 n 秒自动刷新,这样用户创建索引之后,最多在 n 之内肯定能查到,这就是所谓的近实时查询。

实际上 Elasticsearch 索引新文档后,不会直接写入磁盘,而是首先存入文件系统缓存,之后根据刷新设置,定期同步到磁盘,默认情况下 ,每个分片每秒自动刷新一次 这就是为什么文档的改动不会立即被搜索,但是会在 1 秒内可见,这个时间可以通过 index.refresh_interval 参数来修改间隔。

4、集群

集群是一个或多个节点的集合,用来保存应用的全部数据并提供基于全部节点的集成式索引和搜索功能。集群有利于系统性能的水平扩展及保障系统的可用性。

每个 Elasticsearch 集群都需要有一个唯一的名称,默认是 elasticsearch 此名称很重要 ,因为有可能节点会设置为通过其名称来加入集群。

当一个集群只有一个节点时,通常不会出现什么问题,然而需要考虑部署到多个独立的集群时,

就需要为每个集群配置自己唯一的集群名称了。建议在不同的环境中使用不同的集群名称,这样可

以避免由于名称搞棍而导致节点加入错误的集群中。

5、节点

节点是一个集群中的单台服务器,用来保存数据并参与整个集群的索引和搜索操作,就像一个集群一样,一个节点有一个名称标识。默认情况下它是一个随机的通用唯一标识符(UUID),在启动时分配给该节点。如果不想使用默认值,可以定义任何所需的节点名称。此名称对于管理集群节点非常重要,开发人员需要确定网络中哪些服务器对应于 Elasticsearch 集群中的哪些节点。

可以将节点配置为通过集群名称加入特定集群。默认情况下,每个节点都设置为加入名为 "elasticsearch" 的集群,这意味着如果开发人员在网络上启动多个节点,并且假设它们可以发现彼此,则它们将自动形成并加入名为 "elasticsearch" 的单个集群。

在单个集群中,开发人员可以拥有任意数量的节点。此外,如果网络上当前没有其他 Elasticsearch 节点运行,则启动单个节点将默认形成名为

"elasticsearch" 的新单节点集群

6、索引

索引是相似文档的集合。索引中的内容与应用本身的业务相关,如电子商务应用可以使用索引来保存产品数据、订单数据和客户数据等。每个索引都有一个名称,通过该名称可以对索引中包含的文档进行添加、更新、删除和搜索等操作。在单个集群中可以根据需要定义任意数量的索引。

7、类型

类型是对一个索引中包含的文档的进一步细分。一般根据文档的公共属性来进行划分。例如,在电子商务应用的产品数据索引中,可以根据产品的特征划分成不同的类型,如一般产品、虚拟产品、数字产品等。

8、文档

文档是进行索引的基本单位,与索引中的一个类型相对应。例如,产品数据索引中一般产品类型中的每个具体的产品可以有一个文档与之对应,文档使用 JSON 格式来表示。

在索引/类型中,可以存储任意数量的文档 需要注意的是,虽然文档物理上驻留在索引中,但实际上文档必须是索引中的类型。

9、分片和副本

企业应用需要存储的数据量一般比较巨大,超出单个节点所能处理的范围 Elasticsearch 允许把索引划分成多个分片(Shard)来存储索引的部分数据 Elasticsearch 会负责处理分片的分配和聚合。从可靠性的角度出发,对于一个分片中的数据,应该有至少一个副本(Replica)。Elasticsearch 中每个索引可以划分成多个分片,而且有多个副本 Elasticsearch 会自动管理集群中节点的分片和副本,对开发人员透明。

【1】设置分片的原因

  1. 它允许用户水平分割、缩放内容卷
  2. 它允许用户跨分片(可能在多个节点上)分布和并行操作,从而提高性能/吞吐量。

碎片如何分布、文档如何聚合搜索请求等,这些机制都由 Elasticsearch 完全管理,并且对用户是透明的。

由于在云环境中故障不可避免,因此一定要有故障转移机制,以防某个分片/节点故障。为此,Elasticsearch 允许用户将索引的碎片的一个或多个副本转换为所谓的副本碎分片,或简称为副本。

【2】设置副本的原因

设置副本的主要原因如下

  1. 在碎片/节点故障的情况下提供高可用性 因此,副本分片不能部署在从其复制的原始/主分片相同的节点上.
  2. 它允许用户扩展搜索量/吞吐量,因为搜索可以并行地在所有副本上执行。

总而言之,每个索引可以拆分成多个分片。索引也可以复制为零(意味着没有副本)或更多次。一旦复制,每个索引将具有主分片和副本分片,可以在创建索引时为每个索引定义分片和副本的数量。创建索引后,用户可以随时动态更改副本数,但不能随后更改分片数。

默认情况下, Elasticsearch 每个索引分配 5 个主分片和 1 个副本,这意味着集群至少有两个节点,索引将有 5 个主要碎片和另外 5 个副本碎片( 1 个完整的副本)。每个索引共 10 个分片。

注意: 每个 Elasticsearch 分片是一个 Lucene 索引,在一个 Lucene 索引中有文档数的最多限制。从 LUCENE-5843 版本开始,限制为 2147483519 个文档,可以使用 _cat/shards api 监视分片大小。