这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战
视频课程:极客时间 -- 《Elasticsearch核心技术与实战》-- 配套代码 GitHub
系列文章:
《Elasticsearch核心技术与实战》笔记 -- 第一章:概述
《Elasticsearch核心技术与实战》笔记 -- 第二章:安装上手
基本概念:索引、文档和 REST API
文档
- ElasticSearch 是面向文档的,文档是所有可搜索数据的最小单位
- 日志文件中的日志项
- 一部电影的具体信息 / 一张唱片的详细信息
- MP3 播放器里的一首歌 / 一篇PDF 文档中的具体内容
- 文档会被序列化成 JSON 格式,保存在 Elasticsearch 中
- JSON 对象由字段组成
- 每个字段都有对应的字段类型 (字符串 / 数值 / 布尔 / 日期 / 二进制 / 范围类型)
- 每个文档都有一个 Unique ID
- 你可以自己指定 ID
- 或者通过 Elasticsearch 自动生成
JSON 文档
- 一篇文档包含了一系列的字段。类似数据库表中的一条记录
- JSON 文档,格式灵活,不需要预先定义格式
- 字段的类型可以指定或者通过 ElasticSearch 自动推算
- 支持数组 / 支持嵌套
文档的元数据
- 元数据,用于标注文档的相关信息
- _index - 文档所属的索引名
- _type - 文档所属的类型名
- _id - 文档唯一 Id
- _source - 文档的原始 Json 数据
_all- 整合所有字段内容到该字段,已被废除(7.0版本后被废除)- _version - 文档的版本信息
- _score - 相关性打分
索引
- Index - 索引是文档的容器,是一类文档的结合
- Index 体现了逻辑空间的概念,每个索引都有自己的 Mapping 定义,用于定义包含的文档的字段名和字段类型
- Shard 体现了物理空间的概念;索引中的数据分散在 Shard 上
- 索引的 Mapping 与 Setting
- Mapping 定义文档字段的类型
- Setting 定义不同的数据分布
索引的不同语意
- 名词:一个 ElasticSearch 集群中,可以创建很多个不同的索引
- 动词:保存一个文档到 ElasticSearch 的过程也叫索引(indexing)
- ES 中,创建一个倒排索引的过程
- 名词:一个B 树索引,一个倒排索引
Type
- 在 7.0 之前,一个 Index 可以设置多个 Types
- 在 6.0 开始, Type 已经被 Deprecated,7.0 开始,一个索引只能创建一个 Type -
_doc
默认类型(default type) - 字段类型详解:www.cnblogs.com/candlia/p/1…
抽象与类比
- 传统关系型数据库和 ElasticSearch 的区别
- ElasticSearch - Schemalass / 相关性 / 高性能全文检索
- RDMS - 事务性 / Join
RDBMS | ElasticSearch |
---|---|
Table | Index(Type) |
Row | Document |
Column | Filed |
Schema | Mapping |
SQL | DSL |
REST Api -- 很容易被各种语言调用
一些基本的 API
- Indices
- 创建 Index
- PUT Movies
- 创建 Index
- 查看所有 Index
- _cat/indices
kibana 索引管理及操作
http://localhost:5601/app/management/data/index_management/indices
查看索引相关信息
- GET kibana_sample_data_ecommerce
{
"kibana_sample_data_ecommerce" : {
"aliases" : { },
"mappings" : {
"properties" : {
"category" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword"
}
}
},
"currency" : {
"type" : "keyword"
},
"customer_birth_date" : {
"type" : "date"
},
"customer_first_name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"customer_full_name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
....此处省略部分信息....
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"include" : {
"_tier_preference" : "data_content"
}
}
},
"number_of_shards" : "1",
"auto_expand_replicas" : "0-1",
"provided_name" : "kibana_sample_data_ecommerce",
"creation_date" : "1636645300804",
"number_of_replicas" : "0",
"uuid" : "3krdWclZQe66NVj1TmobYQ",
"version" : {
"created" : "7150099"
}
}
}
}
}
查看索引文档数
- GET kibana_sample_data_ecommerce/_count
{
"count" : 4675,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
}
}
- 查看前十条文档,了解文档格式
- POST kibana_sample_data_ecommerce/_search
{
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4675,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "kibana_sample_data_ecommerce",
"_type" : "_doc",
"_id" : "mhapD30B2_nndi5vbKef",
"_score" : 1.0,
"_source" : {
"category" : [
"Men's Clothing"
],
"currency" : "EUR",
"customer_first_name" : "Eddie",
"customer_full_name" : "Eddie Underwood",
"customer_gender" : "MALE",
"customer_id" : 38,
"customer_last_name" : "Underwood",
"customer_phone" : "",
"day_of_week" : "Monday",
"day_of_week_i" : 0,
"email" : "eddie@underwood-family.zzz",
"manufacturer" : [
"Elitelligence",
"Oceanavigations"
],
"order_date" : "2021-11-22T09:28:48+00:00",
"order_id" : 584677,
"products" : [
{
"base_price" : 11.99,
"discount_percentage" : 0,
"quantity" : 1,
"manufacturer" : "Elitelligence",
"tax_amount" : 0,
"product_id" : 6283,
"category" : "Men's Clothing",
"sku" : "ZO0549605496",
"taxless_price" : 11.99,
"unit_discount_amount" : 0,
"min_price" : 6.35,
"_id" : "sold_product_584677_6283",
"discount_amount" : 0,
"created_on" : "2016-12-26T09:28:48+00:00",
"product_name" : "Basic T-shirt - dark blue/white",
"price" : 11.99,
"taxful_price" : 11.99,
"base_unit_price" : 11.99
},
{
"base_price" : 24.99,
"discount_percentage" : 0,
"quantity" : 1,
"manufacturer" : "Oceanavigations",
"tax_amount" : 0,
"product_id" : 19400,
"category" : "Men's Clothing",
"sku" : "ZO0299602996",
"taxless_price" : 24.99,
"unit_discount_amount" : 0,
"min_price" : 11.75,
"_id" : "sold_product_584677_19400",
"discount_amount" : 0,
"created_on" : "2016-12-26T09:28:48+00:00",
"product_name" : "Sweatshirt - grey multicolor",
"price" : 24.99,
"taxful_price" : 24.99,
"base_unit_price" : 24.99
}
],
"sku" : [
"ZO0549605496",
"ZO0299602996"
],
"taxful_total_price" : 36.98,
"taxless_total_price" : 36.98,
"total_quantity" : 2,
"total_unique_products" : 2,
"type" : "order",
"user" : "eddie",
"geoip" : {
"country_iso_code" : "EG",
"location" : {
"lon" : 31.3,
"lat" : 30.1
},
"region_name" : "Cairo Governorate",
"continent_name" : "Africa",
"city_name" : "Cairo"
},
"event" : {
"dataset" : "sample_ecommerce"
}
}
},
...剩余还有九条记录...
]
}
}
查看indices
- GET /_cat/indices/kibana*?v&s=index
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open kibana_sample_data_ecommerce 3krdWclZQe66NVj1TmobYQ 1 0 4675 0 3.9mb 3.9mb
green open kibana_sample_data_flights pDqG7IFiTU-OmBGWNxFoUg 1 0 13059 0 5.4mb 5.4mb
green open kibana_sample_data_logs wnDLe-UKThm_bxeEHttUMA 1 0 14074 0 8.8mb 8.8mb
查看状态为绿色的索引
- GET /_cat/indices?v&health=green
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .geoip_databases eQG671gRQ_iZVqTsQjCoXg 1 0 42 39 40.6mb 40.6mb
green open .kibana_7.15.0_001 oUpr8MWaSSSz03le9LY7Pw 1 0 303 49 3.4mb 3.4mb
green open .apm-custom-link FPjNyXGNTVqCoIRznmUH8Q 1 0 0 0 208b 208b
green open kibana_sample_data_ecommerce 3krdWclZQe66NVj1TmobYQ 1 0 4675 0 3.9mb 3.9mb
green open .kibana-event-log-7.15.0-000001 Y-1aDsuUTZy39aCZbLmPVQ 1 0 2 0 11.9kb 11.9kb
green open .apm-agent-configuration ExWGfjcESt6TR5zLtg0LJw 1 0 0 0 208b 208b
green open kibana_sample_data_logs wnDLe-UKThm_bxeEHttUMA 1 0 14074 0 8.8mb 8.8mb
green open .async-search IXKJJTPCSRmg3LcrI3cpiQ 1 0 0 0 279.3kb 279.3kb
green open .kibana_task_manager_7.15.0_001 jtovZQEQSey9HJD4xnaUqA 1 0 15 10135 1.7mb 1.7mb
green open kibana_sample_data_flights pDqG7IFiTU-OmBGWNxFoUg 1 0 13059 0 5.4mb 5.4mb
green open .tasks VK0TmD2HTdSCjQsxmy_vUA 1 0 2 0 13.7kb 13.7kb
按照文档个数排序
- GET /_cat/indices?v&s=docs.count:desc
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open movies p54hyh_sR-6L1OF05s7Ihg 1 1 62424 0 7.3mb 7.3mb
green open kibana_sample_data_logs wnDLe-UKThm_bxeEHttUMA 1 0 14074 0 8.8mb 8.8mb
green open kibana_sample_data_flights pDqG7IFiTU-OmBGWNxFoUg 1 0 13059 0 5.4mb 5.4mb
green open kibana_sample_data_ecommerce 3krdWclZQe66NVj1TmobYQ 1 0 4675 0 3.9mb 3.9mb
green open .kibana_7.15.0_001 oUpr8MWaSSSz03le9LY7Pw 1 0 303 52 3.4mb 3.4mb
green open .geoip_databases eQG671gRQ_iZVqTsQjCoXg 1 0 42 39 40.6mb 40.6mb
green open .kibana_task_manager_7.15.0_001 jtovZQEQSey9HJD4xnaUqA 1 0 15 10188 1.6mb 1.6mb
green open .kibana-event-log-7.15.0-000001 Y-1aDsuUTZy39aCZbLmPVQ 1 0 2 0 11.9kb 11.9kb
green open .tasks VK0TmD2HTdSCjQsxmy_vUA 1 0 2 0 13.7kb 13.7kb
green open .apm-custom-link FPjNyXGNTVqCoIRznmUH8Q 1 0 0 0 208b 208b
green open .apm-agent-configuration ExWGfjcESt6TR5zLtg0LJw 1 0 0 0 208b 208b
green open .async-search IXKJJTPCSRmg3LcrI3cpiQ 1 0 0 0 279.3kb 279.3kb
查看索引所占的内存
- GET /_cat/indices?v&h=i,tm&s=tm:desc
i tm
kibana_sample_data_ecommerce 72kb
kibana_sample_data_logs 50kb
movies 39kb
kibana_sample_data_flights 35.4kb
.kibana_task_manager_7.15.0_001 29kb
.kibana_7.15.0_001 28.3kb
.geoip_databases 8.5kb
.kibana-event-log-7.15.0-000001 4.7kb
.tasks 4.4kb
.apm-custom-link 0b
.apm-agent-configuration 0b
.async-search 0b
# 查看索引相关信息
GET kibana_sample_data_ecommerce
# 查看索引的文档数
GET kibana_sample_data_ecommerce/_count
# 查看前十条文档,了解文档格式
POST kibana_sample_data_ecommerce/_search
# _cat indices api
# 查看indices
GET /_cat/indices/kibana*?v&s=index
# 查看状态为绿色的索引
GET /_cat/indices?v&health=green
# 按照文档个数排序
GET /_cat/indices?v&s=docs.count:desc
# 查看具体的字段
GET /_cat/indices/kibana*?pri&v&h=health,index,pri,rep,docs.count,mt
# 查看索引所占的内存
GET /_cat/indices?v&h=i,tm&s=tm:desc
基本概念:节点、集群、分片及副本
分布式特征
- ElasticSearch 分布式架构的好处
- 存储的水平扩容
- 提高系统的可用性,部分节点停止服务,整个集群的服务不受影响
- ElasticSearch 的分布式架构
- 不同的集群通过不同的名字来区分,默认名字 “elasticsearch”
- 通过配置文件修改,或者命令行中 -E cluster.name=tyron 进行设定
- 一个集群可以有一个或者多个节点
节点
- 节点是一个 ElasticSearch 的实例
- 本质上就是一个 Java 进程
- 一台机器上可以运行多个 ElasticSearch 进程,但是生产环境一般建议一台机器上只运行一个 ElasticSearch 实例
- 每一个节点都有名字,通过配置文件进行配置,或者启动时候 -E node.name=node1 指定
- 每一个节点在启动之后,会分配一个 UID,保存在 data 目录下
Master-eligible nodes 和Master Node
- 每个节点启动后,默认就是一个 Master eligible 节点
- 可以设置 node.master:false 禁止
- Master-eligible 节点可以参加选举主流程,成为 Master 几点
- 当每一个节点启动时候,它会将自己选举成 Master 节点
- 每个节点上都保存了集群的状态,只有 Master 节点才能修改集群的状态信息
- 集群状态(Cluster State),维护了一个集群中必要的信息
- 所有的节点信息
- 所有的索引和其相关的 Mapping 与 Setting 信息
- 分片的路由信息
- 任意节点都能修改信息会导致数据的不一致性
- 集群状态(Cluster State),维护了一个集群中必要的信息
Data Node & Coordinating Node
- Data Node
- 可以保存数据的节点,叫做 Data Node。负责保存分片数据,在数据扩展上起到了至关重要的作用。
- Coordinating Node
- 负责接收 Client 的请求,将请求分发到合适的节点,最终把结果汇聚到一起
- 每个节点默认都起到了 Coordinating Node的职责
其他的节点类型
- Hot & Warm Node
- 不同硬件配置的 Data Node,用来实现 Hot & Warm 架构,降低集群部署成本
- Machine Learning Node
- 负责跑机器学习的 Job,用来做异常检测
- Tribe Node
- (5.3 开始使用 Cross Cluster Search)Tribe Node 连接到不同的 ElasticSearch 集群,并且支持将这些集群当做一个单独的集群处理
配置节点类型
- 开发环境中,一个节点可以承担多种juese
- 生产环境中,应该设置单一角色的节点 (dedicated node)
节点类型 | 配置参数 | 默认值 |
---|---|---|
master eligible | node.master | true |
data | node.data | true |
ingest | node.ingest | true |
coordinating only | 无 | 每个节点默认都是 coordinating 节点,设置其他类型全部为false |
machine learning | node.ml | true(需enable x-pack) |
分片(Primary Shard & Replica Shard)
-
主分片,用以解决数据水平拓展的问题。通过主分片,可以将数据分布到集群内的所有节点之上
- 一个分片是一个运行的 Lucene 的实例
- 主分片数在索引创建时指定,后续不允许修改,除非 Reindex
-
副本,用以解决数据高可用的问题,分片主分片的拷贝
- 副本分分片数,可以动态调整
- 增加副本数,还可以在一定程度上提高服务的可用性(读取得吞吐)
-
一个三节点的集群中,blogs 索引的分片分布情况
- 思考:增加一个节点或改大主分片数对系统的影响?
分片的设定
- 对于生产环境中分片的设定,需要提前组好容量规划
- 分片数设置过小
- 导致后续无法增加节点实现水平扩容
- 单个分片的数据量太大,导致数据重新分配耗时
- 分片数量设置过大,7.0 开始,默认主分片设置为 1,解决了 over-sharding 的问题
- 影响搜索结果的相关性打分,影响统计结果的准确性
- 单个节点上过多的分片,对导致资源的浪费,同时也会影响性能
- 分片数设置过小
查看集群的健康状况
集群操作在docker环境安装后进行演示补充。
文档的基本 CRUD 与批量操作
CRUD | 操作 |
---|---|
Index | PUT my_index/_doc/1 {"user":"mike","comment":"You know,for search"} |
Create | PUT my_index/_create/1 {"user":"mike","comment":"You know,for search"} POST my_index/——doc (不指定ID,自动生成) {"user":"mike","comment":"You know,for search"} |
Read | GET my_index/_doc/1 |
Update | POST my_index/_update/1 {"doc":{"user":"mike","comment":"You know,for search"}} |
Delete | DELETE my_index/_doc/1 |
- Type 名,约定都用 _doc
- Create,如果 ID 已经存在,会失败
- Index,如果 ID 不存在,创建新的文档,否则,会先删除现有文档,再创建新的文档,版本会增加
- Update,文档必须已经存在,更新只会对相应字段做增量修改
Create 文档
- 支持自动生成文档 Id 和指定文档 Id 两种方式
- 通过调用 “POST /users/_doc“ ,系统会自动生成 document Id
- 使用 HTTP PUT user/_create/1 创建时,URI 中显示指定 _create,此时如果该 id 的文档已经存在,操作失败
GET 文档
- 找到文档,返回 HTTP 200
- 文档元信息
- 版本信息,同一个 id 的文档,即使被删除,Version号也会不断增加
- _source 中默认包含了文档的所有原始信息
- 文档元信息
- 找不到文档,返回 HTTP 404
Index 文档
- Index 和 Create 不一样的地方:如果文档不存在,就会索引新的文档,否则现有文档会被删除,新的文档被索引,版本信息 +1
Update 文档
- Update 方法不会删除原来的文档,而是实现真正数据的更新
- Post 方法 / Payload 需要包含在 “doc” 中
ES 操作
# create document 自动生成 _id
POST users/_doc
{
"user":"Tyron",
"poset_date": "2021-10-10T 13:10:10",
"message":"trying out kibana"
}
{
"_index" : "users",
"_type" : "_doc",
"_id" : "zTFsH30BWlRHpTG9YJXm",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
# create document,指定id,如果id已经存在,报错
PUT users/_doc/1?op_type=create
{
"user":"Milk",
"poset_date": "2021-10-10T 13:10:10",
"message":"trying out kibana"
}
#第一次执行
{
"_index" : "users",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
#第二次执行
{
"error" : {
"root_cause" : [
{
"type" : "version_conflict_engine_exception",
"reason" : "[1]: version conflict, document already exists (current version [1])",
"index_uuid" : "vTw-Xm05TeycobYXlwN1eA",
"shard" : "0",
"index" : "users"
}
],
"type" : "version_conflict_engine_exception",
"reason" : "[1]: version conflict, document already exists (current version [1])",
"index_uuid" : "vTw-Xm05TeycobYXlwN1eA",
"shard" : "0",
"index" : "users"
},
"status" : 409
}
#get document by id
GET users/_doc/1
{
"_index" : "users",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"user" : "Milk",
"poset_date" : "2021-10-10T 13:10:10",
"message" : "trying out kibana"
}
}
# put index操作会将原文档删除,再将新文档添加,同时version+1
PUT users/_doc/1
{
"user":"Tyron"
}
{
"_index" : "users",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}
#再执行get操作
{
"_index" : "users",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"_seq_no" : 2,
"_primary_term" : 1,
"found" : true,
"_source" : {
"user" : "Tyron"
}
}
# 在原文档中增加字段
POST users/_update/1/
{
"doc": {
"user":"POST",
"poset_date": "2021-10-10T 13:10:10",
"message":"users/_update/1"
}
}
{
"_index" : "users",
"_type" : "_doc",
"_id" : "1",
"_version" : 3,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 1
}
# 在原文档中增加字段
{
"_index" : "users",
"_type" : "_doc",
"_id" : "1",
"_version" : 3,
"_seq_no" : 3,
"_primary_term" : 1,
"found" : true,
"_source" : {
"user" : "POST",
"message" : "users/_update/1",
"poset_date" : "2021-10-10T 13:10:10"
}
}
Bulk API
-
支持在一次 API 调用中,对不同的索引进行操作
-
支持四种类型操作
- Index
- Create
- Update
- Delete
-
可以在 URI 中指定 Index,也可以在请求的 Payload 中进行
-
操作中单条操作失败,并不会影响其他操作
-
返回结果包括了每一条操作执行的结果
批量读取 - mget
- 批量操作,可以减少网络连接所产生的开销,提高性能
批量查询 - msearch
常见错误返回
问题 | 原因 |
---|---|
无法连接 | 网络故障或集群挂了 |
连接无法关闭 | 网络故障或节点出错 |
429 | 集群过于繁忙 |
4XX | 请求体格式有错 |
500 | 集群内部错误 |