Administrator
发布于 2024-05-25 / 0 阅读
0
0

ES-202509120220

ES-202509120220

ES

一、概述

1、简述ES

ElasticSearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎,基于 Apache Lucene 实

现。它提供了一个分布式的多用户的全文搜索引擎。它能很方便的使大量数据具有搜索、分析和

探索的能力。充分利用 Elasticsearch 的水平伸缩性,能使数据在生产环境变得更有价值

Elasticsearch 提供了一个全文搜索的功能,但它不仅仅是一个搜索引擎。它还提供了分布式的实

时文档存储,每个字段可以被索引与搜索。Elasticsearch 也能进行实时的数据分析,并能在近实

时的情况下返回分析结果。

Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开源软件发布。它的 API 使用 JS

ON 作为数据交换的格式,支持各种语言的官方客户端,包括:Java、.NET(C#)、PHP、Pytho

n、Apache Groovy、Ruby 和许多其他语言。

ElasticSearch 主要特点包括:

分布式实时文件存储:每个字段都被索引并可被搜索;

分布式实时分析:搜索、稳定、可靠;

可扩展性:可以扩展到上百台服务器,处理 PB 级结构化或非结构化数据;

多租户:具有多种粒度的索引能力,例如可以对用户数据进行单独索引,也可以将所有用户

的数据存储在一个索引中,并使用用户 ID 进行过滤或者聚合;

全文搜索:内置对全文搜索的支持,内部使用 Lucene 进行全文搜索;

安全:内置用户认证、权限控制、SSL/TLS 加密等安全特性;

JSON/HTTP:使用 JSON 进行数据交互,提供了 RESTful API;

兼容性:支持多种语言客户端,如 Java、Python、PHP、JavaScript 等;

生态系统:Elasticsearch 是 Elastic Stack(也被称为 ELK Stack)的一部分,该栈还包括 Lo

gstash(日志收集、处理和转发工具)、Kibana(数据可视化工具)和 Beats(轻量级数据采

集器)

2、ElasticSearch 是搜索引擎?还是数据库?

(1)作为搜索引擎

作为搜索引擎,ElasticSearch 绝对稳坐该领域的头把交椅,其内核基于 Lucene 构建,支持全文

搜索是职责所在,提供了丰富友好的 API。

但是在现在项目中,Elasticsearch 用作传统意义上全文检索的比重越来越少,多数时候是用来做

精确查询加速,查询条件很多,可以任意组合,查询速度很快,替代其它很多数据库复杂条件查

询的场景需求。甚至有的数据库产品直接使用 Elasticsearch 做二级索引,如 HBase、Redis 等。

因此 Elasticsearch 由于自身的一些特性,更像一个多模数据库。

(2)作为数据库

Elasticsearch 与大名鼎鼎的 MongoDB 十分相似,Elasticsearch 使用 Json 格式来承载数据模型

(MongoDB 使用 Bson,类似于 Json),已经成为事实上的文档型数据库,虽然底层存储不是 J

son 格式。不过二者在产品定位上有差别:

Elasticsearch 更加擅长的基于查询搜索的分析型数据库,倾向 OLAP;

MongoDB 定位于事务型应用层面 OLTP,虽然也支持数据分析

3、应用场景

全文检索:Elasticsearch 最初是作为一个全文搜索引擎而设计的,它将 Lucene 的复杂设置

进行了封装,为开发人员提供了友好的接口,可以提供快速、实时的全文搜索服务,非常适

合用于网站搜索、文档搜索等场景。

应用查询:Elasticsearch 最擅长的就是查询,基于倒排索引核心算法,查询性能强于 B-Tre

e 类型所有数据产品,尤其是关系型数据库方面。当数据量超过千万或者上亿时,数据检索

的效率非常明显。

大数据:Elasticsearch 已经成为大数据平台对外提供查询的重要组成部分之一。大数据平台

将原始数据经过迭代计算,之后结果输出到 Elasticsearch 提供查询,特别是大批量的明细

数据。

日志检索:Elasticsearch 结合 Logstash 和 Kibana,形成了著名的 ELK 三件套,专门针对日

志采集、存储、查询设计的产品组合。

监控领域:Elasticsearch 进入此领域比较晚,但由于其倒排索引核心算法,也是支持时序数

据场景的,性能也是相当不错的,在功能性上完全压住时序数据库。

机器学习:Elasticsearch 本身是数据平台,集成了部分机器学习算法,同时又集成了 Kiban

a 可视化操作,使得从数据采集、到模型训练、到模型预测应用都可以一键式完成。

作为 NoSQL 数据库:Elasticsearch 支持分布式的 CRUD 操作,可以作为一个分布式的 NoS

QL 数据库使用。

地理空间数据分析和搜索:Elasticsearch 支持地理空间数据的索引和搜索,可以用于地理位

置搜索、地理空间数据分析等场景。

二、ElasticSearch逻辑结构

1、索引

在 Elasticsearch 中,索引(Index)是具有类似特性的文档集合。每个索引都有一个唯一的名称

来标识,这个名称必须全部是小写。当我们对文档进行索引、搜索、更新和删除操作时,都会引

用到这个索引名称。

例如,我们可以创建一个名为 “customer” 的索引来存储所有的客户数据,创建一个名为 “produc

t” 的索引来存储所有的产品数据。当我们需要搜索某个客户的信息时,就可以对 “customer” 索引

进行搜索;当我们需要更新某个产品的信息时,就可以对 “product” 索引进行更新。

这种方式使得我们可以在 Elasticsearch 中组织和管理大量的数据,同时也能保证高效的搜索和

查询性能

2、类型

在 Elasticsearch 早期版本中,类型(Type)是索引的逻辑分类,用于将具有共同字段的文档分

组在一起。每个类型都有自己的映射(Mapping),定义了类型中文档的字段名和字段类型。

然而,需要注意的是,从 Elasticsearch 7.0 开始,类型的概念已经被逐渐废弃,一个索引下只能

有一个类型,或者完全不使用类型。这是因为多类型存在一些问题,如字段名冲突、内存浪费

等,所以 Elasticsearch 决定逐步移除多类型的支持。在新的版本中,我们通常直接在索引级别

定义映射,不再使用类型。

3、映射

在 Elasticsearch 中,映射(Mapping)是定义索引中字段名和字段类型的过程,可以看作是 Ela

sticsearch 中的"模式定义"。映射定义了字段的名称、字段的类型(如文本、整数、日期等)、以

及可能的一些额外信息(如是否该字段可以被搜索、是否存储原始值等)

字符串:text(可分词),keyword(精确值)

数值:long,integer,short,byte,double,float

布尔:boolean

日期:date

对象:object

位置:geo_point

{    "settings": {

"number_of_shards": 3,//分片数

"number_of_replicas": 2//副本数

},

"mappings": {

"properties": {

"name": {

"type": "text"

},

"age": {

"type": "integer"

},

"joined": {

"type": "date"

}

}

}

}

Ps:Elasticsearch 允许在文档中添加映射中未定义的字段。这是因为 Elasticsearch 默认开启了

动态映射(Dynamic Mapping)功能。

当 Elasticsearch 遇到映射中未定义的字段时,它会根据字段的内容自动推断字段类型,并更新

映射。例如,如果一个新字段的值是一个日期字符串,Elasticsearch 会自动将这个字段映射为日

期类型。

但是,也可以关闭动态映射功能,或者设置为严格模式,这样在遇到未定义的字段时,Elasticse

arch 会抛出异常,而不是自动更新映射。

需要注意的是,虽然 Elasticsearch 允许动态添加字段,但是频繁修改映射会影响性能,而且一

旦字段被映射为某种类型,就不能再改变类型。因此,对于重要的字段,最好在创建索引时就定

义好映射。

4、文档

在 Elasticsearch 中,文档(Document)是可以被索引的基本信息单位。每个文档都由一系列字

段组成,每个字段都有自己的数据类型和值。文档以 JSON 格式表示,这使得 Elasticsearch 能

够处理复杂、层次化的数据结构。

在 Elasticsearch 中,文档(Document)具有以下特征:

自我包含:一篇文档同时包含字段(如 name)和它们的取值(如 John Doe)。这意味着文

档包含了所有描述数据的信息;

层次型结构:文档中的字段可以是简单的值,也可以是复杂的值,包含其他字段和取值。例

如,“location” 字段可以是一个包含 “city” 和 “country” 字段的对象;

灵活的结构:文档不依赖于预先定义的模式。这意味着你可以为每个文档定义不同的字段。

例如,并非所有的文档都需要 “description” 这个字段,所以可以彻底忽略该字段。同时,如

果需要,可以为文档添加新的字段,如 “location” 的 “latitude” 和 “longitud”;

JSON 格式:文档以 JSON 格式表示,这使得 Elasticsearch 能够处理复杂、层次化的数据结

构,并且与许多现代编程语言的数据处理方式兼容;

可索引和可搜索:文档被存储在索引中,你可以对文档进行索引、搜索、更新和删除操作。

每个文档都有一个唯一的 ID,你可以通过这个 ID 来引用文档。

这些特性使得 Elasticsearch 非常适合处理半结构化的数据,如 JSON,可以灵活地应对数据

结构的变化。

5、字段

在 Elasticsearch 中,字段(Field)是文档的一个属性或特性,每个字段都有一个字段名和字段

值。字段的数据类型可以是简单的(如文本、数字、日期等),也可以是复杂的(如对象或者数

组)。

例如,一个文档可能有一个名为 title 的字段用于存储标题,一个名为 date 的字段用于存储日

期,等等。

字段的定义(包括字段名和字段类型)通常在映射(Mapping)中进行。

Ps:需要注意的是,虽然 Elasticsearch 允许动态添加字段(即在文档中添加映射中未定义的字

段),但是一旦字段被映射为某种类型,就不能再改变类型。因此,对于重要的字段,最好在创

建索引时就定义好映射。

6、逻辑结构类比

在关系数据库中,我们可以将 Elasticsearch 的索引(Index)类比为表(Table),将映射(Mapp

ing)类比为表结构定义(Schema),将文档(Document)类比为表的行数据(Row)。

索引(Index):在 Elasticsearch 中,索引是文档的集合。这与关系数据库中的表(Table)

类似,表也是行数据的集合;

映射(Mapping):映射定义了索引中文档的字段名和字段类型,类似于关系数据库中的表结

构定义(Schema),定义了表中列的名称和数据类型。

文档(Document):文档是 Elasticsearch 中可以被索引的基本数据单位,包含了多个字段

和字段的值。这与关系数据库中的行数据(Row)类似,行数据也包含了多个列和列的值。

这种类比可以帮助我们更好地理解 Elasticsearch 的数据模型,但需要注意的是,Elasticsear

ch 是一个分布式的全文搜索和分析引擎,它的设计和实现与关系数据库有很大的不同,所以

这种类比并不完全准确。

然而,从 Elasticsearch 7.0 开始,类型的概念已经被逐渐废弃,一个索引下只能有一个类型,或

者完全不使用类型。在这种情况下,索引(Index)更类似于关系数据库中的表(Table),映射

(Mapping)类似于表结构定义,文档(Document)类似于表的行数据。

MySQL

ElasticSearch

说明

Table

Index

索引(index),就是文档的集

合,类似数据库的表

Row

Document

文档(Document),就是一

条条数据,类似数据库中的

行(Row),文档都是JSON

格式

Column

Field

字段(Field),就是JSON文

档中的字段,类似数据库的

列(Column)

Schema

Mapping

映射(Mapping)是索引中文

档的约束,类似数据库的表

结构(Schema)

SQL

DSL

DSL是ES提供的JSON风格的

请求语句,用来操作ES

三、倒排索引

1、概述

倒排索引作为一种数据结构,用于存储一种映射关系,即从词项到出现该词项的文档的映射。它

是全文搜索引擎的核心组成部分,如 Elasticsearch、Lucene 等。

在倒排索引中,每个唯一的词项都有一个相关的倒排列表,这个列表中包含了所有包含该词项的

文档的 ID。这样,当我们搜索一个词项时,搜索引擎只需要查找倒排索引,就可以快速找到所有

包含这个词项的文档。

2、创建倒排索引的过程

分词:这是第一步,将一段文本分解成一个个的词项(Tokens)。这个过程由分词器(Toke

nizer)完成,可以根据不同的语言和需求选择不同的分词器。

生成词项:对分词后的结果进行处理,生成最终的词项。这个过程可能包括转换为小写、去

除停用词、词干提取等操作。

创建倒排列表:对于每个词项,都创建一个倒排列表,记录包含这个词项的所有文档的 ID。

更新倒排索引:将新的倒排列表添加到倒排索引中。如果倒排索引中已经存在这个词项,就

将新的文档 ID 添加到对应的倒排列表中。

四、ES简单使用

1、建立连接

2、创建索引

CreateIndexRequest 用于创建索引。

request.source 方法传入索引的设置(如分片数和副本数)以及映射定义(字段类型)。

/**

  • 建立连接
  • *

  • @return
  • */

    public static RestHighLevelClient createClient() {

    return new RestHighLevelClient(RestClient.builder(new

    HttpHost("localhost", 9200, "http")));

    }

    public static void createIndex(RestHighLevelClient client) throws

    Exception {

    CreateIndexRequest request = new CreateIndexRequest("my_index");


    String jsonString =

    3、添加文档

    IndexRequest 用于构建要插入的文档。

    request.source 接收一个 Map,包含要索引的字段和值。

    client.index(request, RequestOptions.DEFAULT) 执行添加文档的操作。

    4、编辑文档

    UpdateRequest 用于指定要更新的文档 ID 和索引。

    updateRequest.doc() 方法用于指定更新的字段和新值

    "{\n" + " \"settings\": {\n" + "   \"number_of_shards\":

    3,\n" + "   \"number_of_replicas\": 2\n"            + " },\n" + "

    \"mappings\": {\n" + "   \"properties\": {\n"            + "

    \"name\": {\"type\": \"text\"},\n" + "     \"age\": {\"type\":

    \"integer\"},\n"            + "     \"joined\": {\"type\":

    \"date\"}\n" + "   }\n" + " }\n" + "}";•

    request.source(jsonString, XContentType.JSON);•

    client.indices().create(request, RequestOptions.DEFAULT);

    System.out.println("Index 'my_index' created successfully.");

    public static void addDocument(RestHighLevelClient client) throws

    Exception {

    Map jsonMap = new HashMap<>();

    jsonMap.put("name", "John Doe");

    jsonMap.put("age", 29);

    jsonMap.put("joined", "2024-11-06");•

    IndexRequest request = new IndexRequest("my_index")       // 文档

    ID(可选)

    .id("1").source(jsonMap);•

    client.index(request, RequestOptions.DEFAULT);

    System.out.println("Document added successfully.");

    }

    public static void updateDocument(RestHighLevelClient client) throws

    Exception {

    // 指定索引和文档ID

    UpdateRequest updateRequest = new UpdateRequest("my_index", "1");


    // 更新内容:将 age 改为 30

    String jsonString = "{ \"doc\": { \"age\": 30 } }";

    updateRequest.doc(jsonString, XContentType.JSON);

    client.update(updateRequest, RequestOptions.DEFAULT);

    System.out.println("Document updated successfully.");

    }

    5、删除文档

    DeleteRequest 用于删除指定 ID 的文档

    1、自定义分词

    public static void deleteDocument(RestHighLevelClient client) throws

    Exception {

    // 指定要删除的文档 ID 和索引

    DeleteRequest deleteRequest = new DeleteRequest("my_index", "1");


    client.delete(deleteRequest, RequestOptions.DEFAULT);

    System.out.println("Document deleted successfully.");

    }


    本文整理自实践经验,如有问题欢迎交流讨论。


    评论