Elastaticsearch 介绍

Elasticsearch是一种实时的分布式搜索和分析引擎,可横向扩展,能够解决各种用例。作为Elastic Stack的核心,它集中存储您的数据,以便您可以发现预期并发现意外情况。

Elasticsearch是Elastic Stack的核心,扮演着搜索和分析引擎的核心角色。Elasticsearch建立在 Apache Lucene之上。它作为数据存储的主要好处:

  • 无架构,面向文档
  • 搜索
  • Analytics(分析)
  • 丰富的客户端库支持和REST API
  • 易于操作,易于扩展
  • 近实时
  • 容错

1. 无架构和面向文档

Elasticsearch 没有严格的数据结构; 您可以存储任何JSON文档。JSON文档是Elasticsearch中的一等公民。文档大致相当于关系数据库表中的记录。传统的关系数据库需要预先定义模式,以指定一组固定的列及其数据类型和大小。而在 Elasticserch 上,数据的性质通常非常动态,需要支持新的或动态的列。JSON文档自然支持这种类型的数据。例如,请查看以下文档:

//第一个文档

1
2
3
4
5
{
"name": "Li Si",
"telephone": "12345678901",
"age": 24
}

//第二个文档

1
2
3
4
5
{
"name": "Zhang San",
"age": 18,
"email": "zhangsan@aishangwei.net"
}

请注意,第二个文档没有telephone字段,而是有一个email地址。实际上,其他客户文档可能具有完全不同的字段集。这在可存储的内容方面提供了极大的灵活性。

2. 搜索功能

Elasticsearch的核心优势在于其文本处理能力。Elasticsearch 作为搜索,是很厉害的,尤其是全文搜索。让我们了解全文搜索是什么:

全文搜索意味着搜索数据库中所有可用文档的所有条目。这需要所有文件的全部内容预先解析和存储。当您听到全文搜索时,请想象一下Google搜索百度搜索等等。 您可以输入任何搜索字词,Google会浏览互联网上的所有网页,以找到最匹配的网页。这与针对string 关系数据库中的类型列运行的简单SQL查询完全不同 。带有WHERE子句equals(=)LIKE 子句的普通SQL查询尝试与基础数据进行精确匹配或通配符匹配。SQL查询最多只能将搜索项与文本列中的子字符串匹配。

当您想在自己的数据上执行类似于Google搜索的搜索时,Elasticsearch是您最好的选择。您可以索引电子邮件,文本文档,PDF文件,网页或几乎任何非结构化文本文档,并使用搜索词搜索所有文档。

在较高的层面上,Elasticsearch将文本数据分解为术语并通过构建Lucene索引使每个术语都可搜索。您可以为自己的应用程序构建自己的快速,灵活的Google搜索。

除了支持文本数据,Elasticsearch还支持其他数据类型,如数字,日期,地理位置,IP地址等。

3. Analytics (分析)

除了搜索,第二个Elasticsearch 最重要的功能就是分析。是的,最初被称为全文搜索引擎的东西现在被用作各种用例中的分析引擎。许多组织正在运行由Elasticsearch提供支持的分析解决方案。

进行搜索就像大海捞针,也就是说,要精确定位大量数据中需要的东西。分析与搜索正好相反;它是关于缩小和放大。例如,您可能想知道站点上有多少访问者来自哪些城市,或者您可能想知道站点上有多少访问者使用macOS、Windows或Linux。

Elasticsearch支持用于分析的各种聚合。Elasticsearch聚合非常强大,可以应用于各种数据类型。

4. 丰富的客户端库和 REST API 支持

Elasticsearch拥有非常丰富的客户端库支持,以使它可以被许多编程语言访问。有可用于Java,C#,Python,JavaScript,PHP,Perl,Ruby等的客户端库。除了官方客户端库之外,还有20多种编程语言的社区驱动库。

此外,Elasticsearch还有一个非常丰富的REST(Representational State Transfer)API,它可以在HTTP协议上运行, 通过HTTP提供所有操作。

所有这些意味着Elasticsearch可以非常轻松地集成到任何应用程序中,以满足您的搜索和分析需求。

5. 易于操作和扩展

Elasticsearch可以在单个节点上运行,并且很容易扩展到数百个节点。很容易启动一个单节点实例的Elasticsearch;它可以开箱即用,无需任何配置更改,并且可以扩展到数百个节点。

[success]水平可伸缩性是通过启动相同类型的多个实例而不是一个单个超性能的服务器。 垂直扩展是指通过添加更多处理能力(通过增加CPU或CPU核心数),内存或存储容量来升级单个实例。由于成本和其他因素(例如高端硬件的可用性),系统可以垂直扩展的程度存在实际限制。

6. 近乎实时的能力

通常,数据可在一秒钟内用于查询(被索引保存后)。并非所有大数据存储系统都具备实时功能。Elasticsearch允许您每秒索引数千到数十万个文档,并使它们几乎可以立即搜索。

它使用Apache Lucene作为它的底层技术。默认情况下,Elasticsearch会索引文档的所有字段。这非常好,因为您可以通过记录中的任何字段进行查询或搜索。你永远不会处于你认为的情况。Elasticsearch贡献者已经充分利用了Apache Lucene的优势,并且还有其他一些优化可以让它快速发展。

7. 容错

即使当存在节点故障和网络故障等硬件故障时,Elasticsearch集群仍可以继续运行。在节点发生故障的情况下,它会将故障节点上的所有数据复制到集群中的另一个节点。在网络出现故障的情况下,Elasticsearch会无缝地选择主副本以保持群集运行。无论是节点还是网络故障,您都可以放心,您的数据是安全的。

Kibana UI

在我们要与 Elasticsearch 进行交互的查询之前,需要先熟悉一下:Kibana Console 。

Elasticsearch 有一个非常丰富的 REST API,允许对 Elasticsearch 进行各种操作。Kibana Console 有一个非常强大能够识别 Rest API 的编辑器。能自动完成和格式化查询。

[success]什么是REST API?REST代表Representational State Transfer。它是一种建筑风格,用于使系统相互操作和相互作用。REST随着HTTP协议的发展而发展,几乎所有基于REST的系统都使用HTTP作为协议。HTTP支持不同的方法,包括 GETPOSTPUTDELETEHEAD,和其它,其用于不同的语义。例如, GET用于获取或搜索某物, POST用于创建新资源, PUT可用于创建或更新现有资源,并且DELETE可用于永久地删除资源。

如你所见,通过控制台发送的命令的长度比 Curl 命令更简洁。不需要输入 Elasticsearch 节点的主机和端口。

// 一个例子

1
2
3
4
5
6
7
8
9
PUT /catalog/_doc/1
{
"seq": "001",
"title": "Elasticsearch Study",
"description": "Elasticsearch Study",
"author": "xxx",
"ISBN": "19000089",
"price": 66.66
}

//curl 版本

1
curl -XPUT http://192.168.20.175:9200/catalog/_doc/2 -d '{ "sku": "book001", "title": "Elasticsearch", "description": "Elasticsearch book", "author": "test", "ISBN": "001", "price": 26.99}' -H "Content-Type: application/json"

Elastaticsearch 核心概念

关系数据库具有 schemas、表、行、列等概念。Elasticsearch 和其它面向文档的存储基于不同的抽象。Elasticsearch 是一个面向文档的存储。JSON 文档是Elasticsearch中的一等公民。这些JSON文档在不同类型和索引中组织。主要有以下核心抽象:

  • Indexes
  • Types
  • Documents
  • Clusters
  • Nodes
  • Shards and replicas
  • Mappings and types
  • Inverted indexes

1. Indexes (索引)

索引是在Elasticsearch中存储和管理单一类型文档的容器。索引可以包含单一类型的文档,如下图所示:

索引是一种类型的逻辑容器。一些配置参数是在索引级别定义的,而其他配置参数是在类型级别定义的。

Elasticsearch中的 Index 概念与关系数据库中的数据库模式大致类似。按照这个类比,Elasticsearch中的type等价于表,Document等价于表中的记录。但需要注意的是,这个比较只是为了便于理解。关系数据库模式几乎总是包含多个表,与此不同,一个索引只能包含一种类型。

[info]在Es 6.0之前,一个索引可以包含多个类型。从6.0开始,只允许一种类型。如果您有一个在6.0之前创建了多种类型的现有索引,并且您正在升级到Elasticsearch 6.0,那么您仍然可以使用旧索引。您不能在Elasticsearch 6.0或更高版本中创建具有多个类型的新索引。

在Elasticsearch 7.3中,默认情况下一个索引只能严格包含一种类型。尝试创建第二个类型将导致以下错误:Rejecting mapping update to [index1],因为最终的映射将有多个类型:[type1, type2]。

2. Types (类型)

在我们的产品目录示例中,被索引的文档属于产品类型。存储在产品类型中的每个文档表示一个产品。由于相同的索引不能具有其他类型,例如客户、订单和订单行项等,类型有助于在索引中逻辑地分组或组织相同类型的文档。

通常,具有最常见字段集的文档被分组在一个类型下。Elasticsearch是无模式的,允许您将带有任意一组字段的任何JSON文档存储到类型中。在实践中,我们应该避免将完全不同的实体(如客户和产品)混合到一个类型中。将它们存储在不同索引中的不同类型中是有意义的。

// 客户索引代码如下:

1
2
3
4
5
6
7
8
9
PUT /customers/_doc/1
{
"firstName": "jack"
"lastName": "zang"
"contact": {
"mobile": "19939661234"
},
...
}

// 产品索引代码如下:

1
2
3
4
5
6
PUT /products/_doc/1
{
"title": "MeiZu Mobile (8 core,4G Ram,1200w xiangsu)
"price": 1680.99,
...
}

3. Documents(文档)

如前所述,JSON文档是Elasticsearch中的一等公民。文档由多个字段组成,是存储在Elasticsearch中的基本信息单元。例如,您可能有一个表示单个产品、单个客户或单个订单项的文档。

如上图所示,它显示了索引、类型和文档之间的关系,文档包含在类型和索引中。

文档包含多个字段。JSON文档中的每个字段都具有特定的类型。在我们前面看到的产品目录示例中,这些字段是title和price。在文档中,每个字段及其值都可以看作键-值对,键是字段名,值是字段值。字段名类似于关系数据库中的列名。字段值可以看作是给定行的列的值,即表中给定单元格的值。

除了用户在文档中发送的字段之外,Elasticsearch还维护内部metafields。这些领域如下:

1
2
3
_id:这是类型内文档的惟一标识符,就像数据库表中的主键一样。它可以由用户自动生成或指定。
_type:此字段包含文档的类型。
_index:这个字段包含文档的索引名。

4. Nodes

Elasticsearch节点是Elasticsearch的单个服务器,可以是更大节点集群的一部分。它参与索引,搜索和执行Elasticsearch支持的其他操作。每个Elasticsearch节点在启动时都会分配一个唯一的ID和名称。也可以通过配置手工指定,编辑config/elasticsearch.yml

[success]每个Elasticsearch节点或实例都有一个主配置文件,该文件位于/etc/elasticsearch子目录中。该文件采用YML格式。此配置文件可用于更改默认值,例如节点名称,端口和群集名称。

5. Cluster

群集承载一个或多个索引和负责提供搜索,索引和聚合等操作。集群由一个节点或多个节点组成。每个Elasticsearch节点始终是群集的一部分,即使它只有一个节点群集。默认情况下,每个Elasticsearch节点都尝试使用名称Elasticsearch加入群集。如果在同一网络上启动多个节点而未修改 cluster.name,则 它们会自动形成一个群集

[warning]建议修改cluster.name 属性,以避免加入同一网络中的其他群集。由于节点的默认行为是加入网络中的现有群集,因此本地节点可能会尝试加入另一个节点并形成群集。

集群由多个节点组成,每个节点负责存储和管理其数据共享。一个集群可以托管一个或多个索引。索引是相关类型文档的逻辑分组。

6. Shards and replicas

索引包含一种或多种类型(在以后的版本中,类型可能会取消)的文档。碎片有助于在集群上分布索引。切分有助于将单个索引的文档划分到多个节点上。可以存储在单个节点上的数据量是有限制的,该限制由该节点的存储、内存和处理能力决定。切分有助于在集群上分割单个索引的数据,从而允许使用集群的存储、内存和处理能力。

将数据切片的过程称为分片。分片是Elasticsearch固有的,是一种缩放和并行化的方法,如下:

  • 它有助于跨集群的不同节点使用存储
  • 它有助于利用集群中不同节点的处理能力

默认情况下,每个索引在Elasticsearch中都配置为一个分片。在创建索引时,您可以指定为索引划分数据的分片的数量。一旦创建了索引,就不能修改碎片的数量。

默认分片解释https://www.elastic.co/guide/en/elasticsearch/reference/7.3/release-highlights-7.0.0.html#_default_to_one_shard

下图说明了一个索引的五个分片可以如何分布在一个三个节点的集群中:

每个碎片大约包含索引中的总数据的 5/1 ,当对该索引进行查询时,ES 会把所有碎片并行合并。

现在,假如其中一个节点 Down ,该节点的数据的就会丢失,但 ES 还是会正常运行。这个问题由复制碎片或副本来解决。索引中的每个碎片都可以配置为零或多个复制碎片。复制碎片是原始碎片或主碎片的额外副本,提供高可用性的数据。

从上图可以看出,P 是主碎片,R 为复制碎片。复制就绪后,如果一个节点 Down , 数据依然完整,当相应的主碎片失败后,复制碎片提升为主碎片。

除了提供高可用性和故障转移,副本碎片还允许执行查询工作负载。如搜索、查询和聚合。Elasticsearch透明地将查询的执行分布在集群的各个节点上,其中包含所需的碎片或副本。

总而言之,节点聚集在一起形成集群。集群提供服务的物理层,可以在该物理层上创建多个索引。索引可以包含一个类型,类型包含数百万或数十亿个文档。索引被分成碎片,这些碎片是索引中基础数据的分区。碎片分布在集群的各个节点上。

7. 映射和数据类型

Elasticsearch是无模式的,这意味着您可以使用任意数量的字段和字段类型存储文档。但在实际场景中,数据从来都不是完全无模式或非结构化的。在一个类型的所有文档中,总是有一些字段集是通用的。

关系数据库采用严格的结构。在关系数据库中,需要在创建表时为每一列定义列名和数据类型,以定义表的结构。不能在运行时插入具有新列或不同数据类型列的记录。

ES 支持多种数据类型,适用于不同的场景,在这些场景中,您希望存储文本数据、数字、布尔值、二进制对象、数组、对象、嵌套类型、地理点、地理形状,以及许多其他特殊的数据类型,如IPv4和IPv6地址。

在文档中,每个字段都有一个与之关联的数据类型。主要分为以下几类:

(1)核心数据类型

  • 字符串类型

    • text:对于全文搜索比较有用,比如描述或者长文本。在为支持全文搜索建立索引之前,将对这些字段进行分析。
    • keyword:支持对字符串字段进行分析、排序、过滤和聚合。
  • 数字类型

    • byte,short,integer,long :精度分别为 8,16,32,64 位的带符号整数。
    • float,double:具有单精度32位和双精度64位表示的IEEE 754浮点数
    • half_float:半精度16位的 IEEE 754 浮点数
    • scaled_float:一个浮点数,它由一个长的、由一个固定的双比例因子缩放而成。
  • 日期类型

    • date:Date包含一个可选的时间戳组件,该组件能够存储精确到毫秒级的时间戳
  • 布尔类型

    • boolean:true 或 false
  • 二进制类型

    • binary:接受二进制值作为Base64编码的字符串。
  • 范围类型

    • integer_range, float_range, long_range, double_range, and date_range: 定义整数、浮点数、长数等的范围

[success]scaled_float是一种非常有用的数据类型,用于存储诸如price之类的东西,它的精度总是有限的小数位数。Price可以以100的比例因子存储,比如 5.99 元,可以在内部作为 599 分整数进行存储,在内部,scaled_float的存储效率更高,因为整数可以被更好地压缩。

(2)Complex(复合)数据类型

  • Array datatype:相同类型实例的数组。例如,字符串数组、整数数组等等。不允许在数组中混合数据类型。

  • Object datatype:允许JSON文档中的内部对象。

  • Nested datatype:用于支持内部对象数组,其中每个内部对象都需要是独立可查询的。

(3)其它数据类型

  • Geo-point datatype:允许将地理点存储为经度和纬度。地理点数据类型支持查询,例如在距离点1千米以内的进行搜索。

  • Geo-shape datatype:允许存储多边形、地图等几何形状。Geo-shape支持查询,例如搜索形状中的所有项。

  • IP datatype:允许您存储IPv4和IPv6地址。

数据类型参考链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html

(4)Mappings(映射)

为了便于理解,创建一个示例

1
2
3
4
5
6
7
8
PUT /catalog/_doc/3
{
"seq": "002",
"title": "Xiaomi mobile",
"description": "5 inch display,6G RAM ",
"price": 888.00,
"os": "Android 7.2"
}

主要做了以下两个方面:

  • 创建索引:如果索引不存在,则新创建
  • 映射:当上传的文档中的字段类型在该索引映射中不存在时,ES 会尝试推断字段的数据类型,此功能称为类型的动态映射,默认情况下,ES 启用类型的动态映射。

// 查看映射

1
GET /catalog/_mapping
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"catalog" : {
"mappings" : {
"properties" : {
"ISBN" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
...

您可能已经注意到,作为字符串发送的每个字段都分配了文本数据类型。文本数据类型支持对字段进行全文搜索。此外,同样的字段也存储为一个多字段,它也存储为一个关键字类型。这有效地支持在同一字段上进行全文搜索和分析(例如排序、聚合和过滤)。

索引操作:https://www.elastic.co/guide/en/elasticsearch/reference/current/indices.html
获取映射:https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-mapping.html

8. Inverted indexes(反向索引)

反向索引是Elasticsearch和其他支持全文搜索的系统的核心数据结构。反向索引类似于您在任何书籍末尾看到的索引。它将文档中出现的术语映射到文档。

例如,你可以建立一个反向索引从以下字符串:

Document ID Document
1 Today is Sunday.
2 Sunday is the last day of a week.

ES 根据上面的文档构建数据结构,这也称为反向索引。

术语 频率 文档(位置)
a 1 1
day 1 2
is 2 1,2
last 1 2
of 1 2
sunday 2 1,2
the 1 2

注意以下事项:

  • 在删除标点符号并将其小写后,文档被分解为多个 terms (术语)。
  • 术语按字母顺序排列。
  • 频率列捕获术语在整个文档集中出现的次数。
  • 第三列捕获发现该术语的文档。此外,它还可能包含找到术语的确切位置(文档中的偏移量)。

在文档中搜索术语时,查找出现给定术语的文档非常快。如果用户搜索“sunday”,那么从“term”列查找“sunday”将非常快,因为这些术语在索引中进行了排序。即使有数百万项,在对它们进行排序时,也可以快速地查找它们。

接下来,考虑一个场景,其中用户搜索两个单词,last sunday。反向索引可以单独搜索lastsunday和文档2包含两个术语,因此它比文档1更匹配,文档1只包含一个术语。

反向索引是执行快速搜索的构建块。类似地,很容易查找索引中出现了多少项。这是一个简单的计数聚合。当然,Elasticsearch反向索引的基础上使用了很多创新。它同时迎合了搜索和分析。

REST API

Elasticsearch支持多种操作类型。有些操作处理文档,即创建、读取、更新、删除等等。有些操作提供搜索和聚合,而其他操作则提供与集群相关的操作,例如监视健康状况。大体上,处理Elasticsearch的api分为以下几种类型:

  • Document APIs
  • Search APIs
  • Aggregation APIs
  • Indexes APIs
  • Cluster APIs
  • Cat APIs

Elasticsearch 参考文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.3/rest-apis.html

所有的Elasticsearch REST api都有一些共同的特性。它们几乎可以跨所有api使用。

  • 格式化JSON响应
  • 处理多个索引

1. 格式化 JSON

默认情况下,所有请求的响应都不格式化。它在一行中返回一个未格式化的JSON字符串:

1
2
3
4
5
6
7
8
curl -XGET http://192.168.20.176:9200/catalog/_search

{"took":19,"timed_out":false,"_shards":{"total":3,"successful":3,"skipped":0,"failed":0},"hits":{"total":{"value":4,"relation":"eq"},"max_score":1.0,"hits":[{"_index":"catalog","_type":"_doc","_id":"Vq42dmwBUUVP2MHMA067","_score":1.0,"_source":{
"name": "phones"
}
},{"_index":"catalog","_type":"_doc","_id":"O641dmwBUUVP2MHM0U4e","_score":1.0,"_source":{
"name": "books"
...

//传递 pretty=true 格式化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 curl -XGET http://192.168.20.176:9200/catalog/_search?pretty=true

{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4,
"relation" : "eq"
},
...

[success]使用Kibana控制台UI时,所有响应都默认格式化。

2. 处理多个索引

搜索和聚合等操作可以针对同一查询中的多个索引运行。可以在GET请求中使用不同的url指定应该搜索哪些索引。

(1)在所有索引中搜索所有文档

下面的查询匹配所有文档。在本例中,查询实际返回的文档默认将被限制为10个。

1
GET /_search
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{
"took" : 6,
"timed_out" : false,
"_shards" : {
"total" : 8,
"successful" : 8,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : ".kibana_1",
"_type" : "_doc",
"_id" : "space:default",
"_score" : 1.0,
"_source" : {
"space" : {
"name" : "Default",
"description" : "This is your default space!",
"color" : "#00bfb3",
"disabledFeatures" : [ ],
"_reserved" : true
},
"type" : "space",
"migrationVersion" : {
"space" : "6.6.0"
},
"updated_at" : "2019-08-09T02:38:50.205Z"
}
...
  • took:集群返回结果所花费的毫秒数。
  • timed_out:false 这意味着操作在没有超时的情况下成功完成。
  • _shards:显示整个集群中搜索成功或失败的碎片的总数。
  • hit:包含匹配的实际文档。它包含total,表示所有索引中匹配搜索条件的文档总数。max_score显示搜索命中的最佳匹配文档的得分。此元素的hits子元素包含实际的文档列表。

[success]数组中包含的hits列表不包含所有匹配的文档。Elasticsearc可以选择使用GET /_search?size=100将其指定为请求参数。大小的默认值是10,因此search hits数组在默认情况下最多包含10条记录。

(2)在一个索引中搜索所有文档

1
2
3
GET /catalog/_search                //第一种方式

GET /catalog/_doc/_search //第二种方式

具有_doc类型名称的版本会产生一个弃用警告,因为每个索引应该只包含一种类型。

1
2
3
4
#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
"took" : 11,
...

(3)在多个索引中搜索所有文档

1
GET /catalog,catalog1/_search

CRUD 操作

Elasticsearch有一个精心设计的REST API, CRUD操作的目标是文档。

我们将用下面的这些操作理解 CRUD 操作:

  • Create API
  • Get API
  • Update API
  • Delete API

1. Create API

ES术语中,向ES索引中的类型添加(或创建)文档称为索引操作。本质上,它涉及通过解析文档中的所有字段并构建反向索引将文档添加到索引中。这就是为什么这个操作被称为索引操作。

有两种方法可以索引文档:

  • 通过提供索引ID操作
  • 自动生成索引ID操作

(1)通过提供索引ID操作

格式:PUT /<index>/<type>/<id>

1
2
3
4
5
6
7
8
9
PUT /catalog/_doc/1
{
"seq": "001",
"title": "Elasticsearch Study",
"description": "Elasticsearch Study",
"author": "xxx",
"ISBN": "19000089",
"price": 66.66
}

(2)自动生成索引ID操作

如果不希望控制文档的ID生成,可以使用POST方法。

格式:POST /<index>/<type>

1
2
3
4
5
6
7
8
POST /catalog/_doc
{
"seq": "003",
"title": "Elastic Stack",
"description": "Elastic Stack",
"author": "xxx",
"price": 99.99
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"_index" : "catalog",
"_type" : "_doc",
"_id" : "7a1TdWwBUUVP2MHMHOCs",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}

在本例中,ID将由Elasticsearch生成,它是一个散列字符串。

[success]根据纯REST约定,POST用于创建新资源,PUT用于更新现有资源。在这里,PUT的用法相当于说我知道要分配的ID,所以在索引这个文档时使用这个ID

2. Get API

格式:GET /<index>/<type>/<id>

1
GET /catalog/_doc/7a1TdWwBUUVP2MHMHOCs

3. Update API

格式:POST <index>/<type>/<id>/_update

1
2
3
4
5
6
POST /catalog/_update/1
{
"doc": {
"price": "88.99"
}
}

doc元素下指定的属性将合并到现有文档中。这个更新操作只更新 price,而不改变文档的其他字段。这种类型的更新意味着指定doc并将其用作与现有文档合并的部分文档;

在内部,ES 维护每个文档的版本,每当文档更新,版本号都会增加。

如果文档不存在,则会报错。当然也可以指定 doc_as_upsert 参数,如文档不存在,则插入新文档。

1
2
3
4
5
6
7
8
9
10
11
12
POST /catalog/_update/2
{
"doc": {
"seq": "002",
"title": "Xiaomi mobile",
"description": "5 inch display,6G RAM ",
"price": 866.00,
"os": "Android 7.2",
"new": "2019"
},
"doc_as_upsert": true
}

4. Delete API

delete API允许您通过ID删除文档:

1
DELETE /catalog/_doc/2

创建索引并控制映射

前面我们学习了 ES 执行 CRUD 操作。在这个过程中,我们了解了如何将第一个文档索引到一个还不存在的索引,从而创建新的索引和类型的映射。

通常,有的时候,我们不想自动发生,而想以手工的方式控制索引以及映射。

  • 创建索引
  • 创建映射
  • 更新映射

1. 创建索引

删除之前实验的 catalog 索引

您可以创建一个索引,并指定要创建的碎片和副本的数量:

1
2
3
4
5
6
7
8
9
PUT /catalog
{
"settings": {
"index": {
"number_of_shards": 3,
"number_of_replicas": 2
}
}
}

可以在创建索引时为类型指定映射。下面的命令将创建一个名为catalog的索引,其中包含三个碎片和两个副本。此外,它还定义了两个字段,一个是文本类型,另一个是关键字类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PUT /catalog1
{
"settings": {
"index": {
"number_of_shards": 3,
"number_of_replicas": 2
}
},
"mappings": {
"properties": {
"field1": {
"type": "text"
},
"field2": {
"type": "keyword"
}
}
}
}
1
2
3
4
5
POST /catalog1/_doc
{
"field1": "books",
"field2": "2019"
}

2. 在现有索引中创建类型映射

对于Elasticsearch 7.3,索引严格包含一种类型,因此通常建议在创建索引时在该索引中创建索引和默认类型。默认类型名称为_doc。

在Elasticsearch(6.0及之前版本)的早期版本中,可以定义一个索引,然后根据需要向该索引添加多个类型。这仍然是可能的,但它是一个不推荐的特性。使用以下代码创建索引之后,可以在索引中添加类型。类型的映射可以指定如下:

1
2
3
4
5
6
7
8
PUT /catalog/_mapping
{
"properties": {
"name": {
"type": "text"
}
}
}

上面的命令会自动创建一个 _doc的类型。

1
2
3
4
5
6
7
8
9
POST /catalog/_doc
{
"name": "books"
}

POST /catalog/_doc
{
"name": "phones"
}

下面的例子说明:Elasticsearch将根据为新字段插入的值自动分配类型。它只考虑它看到的第一个值来猜测字段的类型:

1
2
3
4
5
POST /catalog/_doc
{
"name": "zabbix",
"description": "Monitor system"
}

当使用字段索引新文档时,将根据初始文档中的值为该字段分配数据类型。让我们看一下索引此文档后的映射

1
GET /catalog/_mapping
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"catalog" : {
"mappings" : {
"properties" : {
"description" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"name" : {
"type" : "text"
}
}
}
}
}

description 字段分别有两个数据类型,分别是 textkeyword ,从逻辑上讲,有两个字段,分别是 descriptiondescription.keyword , description 字段在索引时进行分析,而 description.keyword 按照不进行任何分析的方式存储。默认情况下,第一次使用双引号索引的字段同时存储为文本和关键字类型。

如果要控制类型,则应在包含该字段的第一个文档编制索引之前定义该字段的映射。在该字段中索引一个或多个文档后,无法更改字段的类型。让我们看看如何更新映射以添加具有所需类型的字段。

3. 更新映射

在创建类型之后,可以添加新字段的映射。可以使用PUT映射API更新类型的映射。让我们添加一个code字段,它是关键字类型,但没有分析:

1
2
3
4
5
6
7
8
PUT /catalog/_mapping
{
"properties": {
"code": {
"type": "keyword"
}
}
}

这个映射被合并到_doc类型的现有映射中。合并后的映射如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"catalog" : {
"mappings" : {
"properties" : {
"code" : {
"type" : "keyword"
},
"description" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"name" : {
"type" : "text"
}
}
}
}
}

使用code字段索引的任何后续文档都被分配了正确的数据类型:

1
2
3
4
5
6
POST /catalog/_doc
{
"name": "python",
"code": "hello world",
"description": "This is test"
}