Elasticsearch笔记 基础入门
概念
ES是一个实时的分布式搜索分析引擎,它被用作全文检索,结构化检索,分析以及这三个功能的组合;
集群内的原理
集群
一个运行中的 Elasticsearch 实例称为一个节点,而集群是由一个或者多个拥有相同 cluster.name
配置的节点组成, 它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。
选举模式
集群通过选举模式推选出主节点。
主节点
主节点负责管理集群范围内的所有变更。比如新增,删除索引,新增,删除节点等。
主节点不负责管理文档和搜索等操作,所以即便流量增加也不会引发瓶颈。
每个节点都知道任意文档所处的位置。
副节点
集群健康
GET /_cluster/health
通过status字段指示当前集群是否正常运行
- green: 所有主分片和副分片都运行正常
- yellow: 所有主分片都运行正常,但不是所有副分片都运行正常。
- red: 有主分片没能正常运行。
索引
索引是指向一个或者多个物理分片的逻辑命名空间。
索引名,这个名字必须小写,不能以下划线开头,不能包含逗号。
PUT /blogs
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
倒排索引
关系型数据库采用索引列的方式(比如B树)提高查询速度。
ES采用倒排索引的方式达到相同的目的
分片
一个分片是一个底层的工作单元,它仅保存了全部数据中的一部分。
主分片
分片是一个底层的工作单元,它仅仅保存了全部数据的一部分。
每个分片都是一个Lucene的实例,它本身是一个完整的搜索引擎。
一个主分片最大存储INTEGER.MAX_VALUE-128个文档。(正负20亿)
不可变更
副本分片
副本分配是主分片的拷贝,副本分片作为硬件故障时保护数据不丢失的冗余备份,并为索引和返回文档等读操作提供服务。
可随时变更
水平扩容
索引的主分片数量是不可变更的,副本分片可以随时改变。
通过增加副本分片数量可以提高检索速度。
节点不变,一味地增加副本数量是无效的。副本之间抢夺节点性能。节点数量才是扩容的基本。
创建索引时,指定3个主分片,1个副本分片。含义是每个主分片各拥有一个副本分片。相当于6个分片。
一个节点下建立多少个副本分片都是没有意义的,因为节点挂掉数据全丢。
节点与分片的1比1配比,是N个节点对应N个分片。既每个节点下保存一个分片。
应对故障
当某个节点异常时,ES自动丢弃,并在正常节点下完善分片结构。
当异常节点恢复时,ES会重新分配分片结果,并争取重用历史数据仅同步变更数据。
数据输入和输出
文档的概念
它是指最顶层或者根对象, 这个根对象被序列化成 JSON 并存储到 Elasticsearch 中,指定了唯一 ID。
字段的名字可以是任何合法的字符串,但 不可以 包含英文句号(.)。
文档元数据
- _index 文档在哪里存放
- 索引名必须小写,不能以下划线开头,不能包含逗号。
- _type 文档表示的文档类型
- 支持大小写,不能以下划线或者句号开头,不应该包含逗号,长度限制256个字符。
- _id 文档唯一标识
- _version 文档版本号(隐藏元数据)
- 文档每次变更版本号发生递增。
文档操作
保存文档-自定义id(相同id则覆盖)
PUT /{index}/{type}/{id}
{
"field": "value",
...
}
保存文档-自动id(GUID,不重复,不会覆盖)
PUT /{index}/{type}
{
"field": "value",
...
}
创建新文档(拒绝覆盖)
PUT /website/blog/123?op_type=create
{ ... }
PUT /website/blog/123/_create
{ ... }
获取完整文档
GET /website/blog/123
GET /website/blog/123?pretty
?pretty用于美化返回结果格式
获取_source部分文档
GET /website/blog/123?_source
GET /website/blog/123/_source
获取_source部分文档的一部分内容
GET /website/blog/123?_source=field1,field2,...
获取多个文档
GET /_mget
{
"docs" : [
{
"_index" : "website",
"_type" : "blog",
"_id" : 2
},
{
"_index" : "website",
"_type" : "pageviews",
"_id" : 1,
"_source": "views"
}
]
}
通过docs数组组装多个条件进行批量获取,返回数据分组返回。
返回结果永远是200,需要判断结果断定查询结果
检查文档是否存在
HEAD /website/blog/123
仅返回状态码 200表示存在404表示不存在
更新整个文档
PUT /website/blog/123
{
"title": "My first blog entry",
"text": "I am starting to get the hang of this...",
"date": "2014/01/02"
}
在ES中文档是不可变更的,所以更新操作是先删除后新增。_version递增
更新部分文档
POST /website/blog/1/_update
{
"doc" : {
"tags" : [ "testing" ],
"views": 0
}
}
- 步骤拆分
- 从旧文档构建JSON
- 更新该JSON
- 删除旧文档
- 保存一个新文档
在ES中文档是不可变更的,所以更新操作是先删除后新增。_version递增
更新文档不存在时引入默认值
POST /website/pageviews/1/_update
{
"script" : "ctx._source.views+=1",
"upsert": {
"views": 1
}
}
通过upsert为不存在的属性初始值
处理更新冲突(操作冲突)
- 悲观并发控制(不采用)
- 读取数据的时候对数据加锁。阻止其他线程使用。
- 乐观并发控制-内部控制(默认采用)
- 比对_version属性,不一致则失败。ES不允许操作_version属性。
- 乐观并发控制-外部控制(可选采用)
- 指定自定义_version字段。
- 比对_version属性,入参_version大于存储_version则成功,反则失败。
更新冲突重试机制
POST /website/pageviews/1/_update?retry_on_conflict=5
{
"script" : "ctx._source.views+=1",
"upsert": {
"views": 0
}
}
通过retry_on_conflict属性设置失败后重试次数。仅仅在更新顺序不重要的情况下适用。例如访问计数功能。
删除文档
DELETE /website/blog/123
如果文档不存在,_version一样会累加,新增后_version不再是1.
批量操作(非事物操作)
bulk API允许在单个步骤中进行多次create、index、update、delete请求。
最后一定要以\n结尾,delete操作不需要body
批量操作并非越大越好,多次尝试找到平衡点,建议1000~5000一个批次。
格式
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
...
实例1
POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title": "My first blog post" }
{ "index": { "_index": "website", "_type": "blog" }}
{ "title": "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} }
{ "doc" : {"title" : "My updated blog post"} }
实例2
POST /website/log/_bulk
{ "index": {}}
{ "event": "User logged in" }
{ "index": { "_type": "blog" }}
{ "title": "Overriding the default type" }
减少重复录入_index、_type,参数为空,自动从URL中提取。
文章中部分内容来源于:
Elasticsearch: The Definitive Guide by Clinton Gormley and Zachary Tong (O’Reilly). Copyright 2015 Elasticsearch BV, 978-1-449-35854-9。