ElasticSearch| 文档的CRUD
文档(Document)
Elasticsearch是面向文档的,文档是所有可搜索数据的最小单位
- 日志文件中的日志项
- 一本电影的具体信息/一张唱片的详细信息
- MP3播放器里的一首歌/一篇PDF文档中的具体内容
文档会被序列化成JSON格式,保存在Elasticsearch中
- JSON对象由字段组成,
- 每个字段都有对应的字段类型(字符串/数值/布尔/日期/二进制/范围类型)
每个文档都有一个UniqueID
- 你可以自己指定ID
- 或者通过Elasticsearch自动生成
JSON文档
一篇文档包含了一系列的字段, 类似数据库表中一条记录
JSON文档,格式灵活,不需要预先定义格式
- 字段的类型可以指定或者通过Elasticsearch自动推算
- 支持数组/支持嵌套
CSVfile
----下来csvfile转换为json格式--->
movield, title, genres
1, ToyStory(1995), Adventure| AnimationIChildren| Comedy|Fantasy
{
"year":1995,
"@version":"1",
"genre":[
"Adventure","Animation',
"ChiIdren","Comedy","Fantasy"],
"id":"1",
"title":"ToyStory"
}
文档的元数据
用于标注文档的相关信息
_index 文档所属的索引名
_type 文档所属的类型名
_id 文档唯一ID
_source:文档的原始Json数据
_all: 整合所有字段内容到该字段,已被废除
_version:文档的版本信息
_score:相关性打分
{
"_index":"movies",
"_type":"_doc",
"_id":"1",
"_score":14.69302,
"_source":{
"year":1995,
"@version":"1",
"genre":[
"Adventure",
"Animation',
"ChiIdren",
"Comedy",
"Fantasy"
],
"id":"1",
"title":"Toy Story"
}
}
索引
"movies":{
"settings":{
"index":{
"Creation_date":"1552737458543"
"number_of_shards":"2",
"number_of_replicas":"0",
"uuid":"Qnd71MrNQPGdaeJ90RØtfQ"
"version":{
"created":"6@6@299"
},
"provided_name":"movtes"
}
}
}
Index 索引是文档的容器,是一类文档的结合
- Index体现了逻辑空间的概念:每个索引都有自己的Mapping定义,用于定义包含的文档的字段名和字段类型
- Shard体现了物理空间的概念:索引中的数据分散在Shard上
索引的Mapping与Settings
- Mapping定义文档字段的类型
- Setting定义不同的数据分布
索引的不同语意
① 名词:一个Elasticsearch集群中,可以创建很多个不同的索引
② 动词:保存一个文档到Elasticsearch的过程也叫索引(indexing)
- ES中,创建一个倒排索引的过程
③ 名词:一个B树索引,一个倒排索引
上图是 索引(动词)文档到Elasticsearch的索引(名词)中
Type
PUT index
{
"mappings": {
"properties":{ //Note how there is no top—level key with the type name
"@timestamp":{
"type:"date"
}
}
}
}
PUT index/_doc/1 //_doc becomes the new endpoint for document index,get and delete
requests {
"@timestamp":"2020-02-10"
}
POST index/_bulk
{"index":{"_id":"2"}} //no _type in the URL or in document metadataRead More
{"@timestamp":"2019-03-01"}
{"update": {"_id": "1"}}
{"@timestamp": "2019-03-01"}
在7.0之前,一个Index可以设置多个Types
6.0开始,Type已经被Deprecated 7.0开始,一个索引只能创建一个Type "_doc"
抽象和类比
1. 在7.0之前,一个Index可以设置多个Types
2. 目前Type已经被Deprecated,7.0开始,索引只能创建一个Type: "_doc"
3. 传统关系型数据库和Elasticsearch的区别
- Elasticsearch - Schemaless/相关性/高
性能全文检索
- RDMS - 事务性/Join
REST APT -- 很容易被各种语言调用
一些基本的API
Indices
① 创建Index
PUT Movies
②查看所有Index
_cat/indices
节点、集群、分片及副本
分布式系统的可用性与扩展性
高可用性
- 服务可用性 - 允许有节点停止服务
- 数据可用性 - 部分节点丢失,不会丢失数据
可扩展性
- 请求量提升/数据的不断增长(将数据分布到所有节点上)
分布式特性
Elasticsearch的分布式架构的好处
- 存储的水平扩容
- 提高系统的可用性,部分节点停止服务,整个集群的服务不受影响
Elasticsearch的分布式架构
- 不同的集群通过不同的名字来区分,默认名字"elasticsearch"
- 通过配置文件修改,或者在命令行中 - Ecluster.name=geektime进行设定
- 一个集群可以有一个或者多个节点
节点
节点是一个Elasticsearch的实例
- 本质上就是一个JAVA进程
- 一台机器上可以运行多个Elasticsearch进程,但是生产环境一般建议一台机器上只运行一个Elasticsearch实例
每一个节点都有名字,通过配置文件配置,或者启动时候-E node.name=nodel指定
每一个节点在启动之后,会分配一个UID,保存在data目录下
Master—eligible nodes和Master Node
每个节点启动后,默认就是一个Master eligible节点
- 可以设置 node.master:false 禁止
Master - eligible节点可以参加选主流程,成为Master节点
当第一个节点启动时候,它会将自己选举成Master节点
每个节点上都保存了集群的状态,只有Master节点才能修改集群的状态信息
① 集群状态(Cluster State),维护了一个集群中,必要的信息
- 所有的节点信息
- 所有的索引和其相关的Mapping与Setting信息
- 分片的路由信息
② 任意节点都能修改信息会导致数据的不一致性
Data Node & Coordinating Node
DataNode
- 可以保存数据的节点,叫做DataNode。负责保存分片数据。在数据扩展上起到了至关重要的作用
CoordinatingNode
- 负责接受Client的请求,将请求分发到合适的节点,最终把结果汇集到一起
- 每个节点默认都起到了Coordinating Node的职责
其他的节点类型
HOt&WarmNode
- 不同硬件配置的Data Node,用来实现Hot&Warm架构,降低集群部署的成本
Machine Learning Node
- 负责跑机器学习的Job,用来做异常检测
Tribe Node
- (5.3开始使用Cross Cluster Serarch) Tribe Node 连接到不同的Elasticsearch集群,
- 并且支持将这些集群当成一个单独的集群处理
配置节点类型
- 开发环境中一个节点可以承担多种角色
- 生产环境中,应该设置单一的角色的节点(dedicated node)
分片(Primary Shard & Replica Shard)
主分片,用以解决数据水平扩展的问题。通过主分片,可以将数据分布到集群内的所有节点之上
- 一个分片是一个运行的Lucene的实例
- 主分片数在索引创建时指定,后续不允许修改,除非 Reindex
副本,用以解决数据高可用的问题。分片是主分片的拷贝
- 副本分片数,可以动态题调整
- 增加副本数,还可以在一定程度上提高服务的可用性(读取的吞吐)
分片(Primary Shard & Replica Shard)
一个三节点的集群中,blogs索引的分片分布情况
思考:增加一个节点或改大主分片数对系统的影响?
分片的设定
对于生产环境中分片的设定,需要提前做好容量规划
分片数设置过小
- 导致后续无法增加节点实现水品扩展
- 单个分片的数据量太大,导致数据重新分配耗时
分片数设置过大,7开始,默认主分片设置成1,解决了over-sharding的问题
- 影响搜索结果的相关性打分,影响统计结果的准确性
- 单个节点上过多的分片,会导致资源浪费,同时也会影响性能
查看集群健康状况
GET _cluster/health
GET _cat/nodes //查看node的相关信息
GET _cat/shards //查看shards的相关信息
GET _cluster/health
{
"CIuster_name":"geektime",
"status":"green",
"timed_out":false,
"number_of_nodes":2, //一共两个节点,
"number_of_data_nodes":2, //这两个节点都承担了data node的角色
"active_primary_shards":37, //一共37个主分片
"active_shards":70,
"relocating_shards":0,
"initializing_shards":0,
"unassigned_shards":0,
"delayed_unassigned_shards":0,
"number_of_pending—tasks":0,
"number_of_in_flight_fetch":0,
"task_max_waiting_in_queue_millis":0,
"active_shards_percent_as_number":100.0
}
Green - 主分片与副本都正常分配
Yellow - 主分片全部正常分配,有副本分片未能正常分配
Red - 有主分片未能分配,例如当服务器的磁盘容量超过85%时,去创建了一个新的索引
文档的基本CRUD
Create一个文档
支持自动生成文档ID和指定文档ID两种方式: 通过调用POST my_index/_doc/ 系统会自动生成ID
使用HTTP PUT my_index/_doc/1/_create 创建时, URI中显示指定_create, 此时如果该id 的文档已经存在,则操作失败。
DELETE users
############Create Document############
#create document. 自动生成 _id : KS5tOXcBQn2iJa_jWk65
POST users/_doc
{
"user" : "Mike",
"post_date" : "2019-04-15T14:12:12",
"message" : "trying out Kibana"
}
#create document. 指定Id。如果id已经存在,报错
PUT users/_doc/1?op_type=create
{
"user" : "Jack",
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
#create document. 指定 ID 如果已经存在,就报错
PUT users/_doc/1/_create
{
"user" : "kris",
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
# "reason": "[_doc][1]: version conflict, document already exists (current version [1])",
Get 一个文档
找到文档,返回HTTP 200
文档元信息
-
-
- _index/ _type/
- 版本信息,同一个id的文档,即使被删除,Version号也会不断增加
- _source中默认包含了文档的所有原始信息
-
找不到文档,返回HTTP 404
### Get Document by ID
#Get the document by ID
GET users/_doc/1
Index文档
Index和Create 不一样的地方:如果文档不存在,就索引新的文档。
否则现有文档会被删除,新的文档被索引。版本信息 +1 ;
即 PUT my_index/_doc/1/_create ,如果文档存在会报错;
PUT my_index/_doc/1 ,如果文档存在就先删除再index文档,_version加1 ;
update文档
# Update方法不会删除原来的文档,而是实现真正的数据更新
# Post方法 /Payload需要包含在"doc"中
### Index & Update
#Update 指定 ID (先删除,在写入)
# 修改某个字段, updated, 会把之前的先删掉,再put,版本号+1
PUT users/_doc/1
{
"user" : "Mike"
}
#查询得到, 之前的user、post_date、message被删除了
GET users/_doc/1
#GET users/_doc/1
#在原文档上增加字段, 不会删除重新put
POST users/_doc/1/_update
{
"doc":{
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
}
GET users/_doc/1
Bulk API
常见错误返回
### Bulk 操作
#执行两次,查看每次的结果
#执行第1次
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test2", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
#执行第2次
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test2", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
### mget 操作
GET /_mget
{
"docs" : [
{
"_index" : "test",
"_id" : "1"
},
{
"_index" : "test",
"_id" : "2"
}
]
}
#URI中指定index
GET /test/_mget
{
"docs" : [
{
"_id" : "1"
},
{
"_id" : "2"
}
]
}
GET /_mget
{
"docs" : [
{
"_index" : "test",
"_id" : "1",
"_source" : false
},
{
"_index" : "test",
"_id" : "2",
"_source" : ["field3", "field4"]
},
{
"_index" : "test",
"_id" : "3",
"_source" : {
"include": ["user"],
"exclude": ["user.location"]
}
}
]
}
### msearch 操作
POST kibana_sample_data_ecommerce/_msearch
{}
{"query" : {"match_all" : {}},"size":1}
{"index" : "kibana_sample_data_flights"}
{"query" : {"match_all" : {}},"size":2}
### 清除测试数据
#清除数据
DELETE users
DELETE test
DELETE test2