elasticsearch的基本操作与常见问题
增删改查
新增
带ID新增
PUT /test20210628/_doc/1
{
"name": "zhangsan"
}
POST /test20210628/_doc/2
{
"name": "zhangsan"
}
不带ID新增
POST /test20210628/_doc
{
"name": "zhangsan"
}
POST 可以适用带ID及不带ID的新增,但是PUT只能用于带ID的新增
修改
覆盖更新
PUT /test20210628/_doc/1
{
"name": "lisi"
}
POST /test20210628/_doc/2
{
"name": "lisi"
}
增量更新
PUT /test20210628/_doc/1/_update
{
"doc": {
"age": 8
}
}
批量条件脚本更新
脚本语言:painless,类似javascript
不带参数
POST /normal_form_index/_update_by_query
{
"query": {
"exists": {
"field": "form_data.SYNC_1.developerName"
}
},
"script": {
"source": "if(ctx._source.form_data.SYNC_1.developerName=='a'){ctx._source.form_data.SYNC_1.developerName='b'}"
}
}
默认下最多五分钟内编译75个脚本,如果执行超过这个数额脚本,会报 Too many dynamic script compilations within, max: [75/5m] 的错误
如果要修改这个数值可以按以下格式发送请求修改限制数值,以下示例将限制修改成1分钟100个
或者使用带参数的脚本更新
PUT _cluster/settings
{
"transient" : {
"script.max_compilations_rate" : "100/1m"
}
}
带参数
POST /normal_form_index/_update_by_query
{
"query": {
"exists": {
"field": "form_data.SYNC_1.developerName"
}
},
"script": {
"source": "if(ctx._source.form_data.SYNC_1.developerName==params['developerName']){ctx._source.form_data.SYNC_1.developerName=params['newDeveloperName']}",
"params": {
"developerName": "a",
"newDeveloperName": "b"
}
}
}
删除
注意:es性能非常好,删除非常快,删除的数据基本上不可恢复,做数据操作时要注意数据安全与备份
DELETE /test20210628/_doc/1
批量条件删除
POST /normal_form_index/_delete_by_query
{
"query": {
"exists": {
"field": "form_data.SYNC_1.developerName"
}
}
}
查询
精确查询
POST /_search
{
"query": {
"term" : { "user" : "Kimchy" }
}
}
POST /_search
{
"query": {
"terms" : { "user" : ["kimchy", "elasticsearch"]}
}
}
通配符查询
*
:可以匹配0个或多个字符
?
:可以匹配1个字符
POST /_search
{
"query": {
"wildcard": {
"user": {
"value": "ki*y"
}
}
}
}
范围查询
GET _search
{
"query": {
"range" : {
"age" : {
"gte" : 10,
"lte" : 20,
}
}
}
}
GET _search
{
"query": {
"range" : {
"timestamp" : {
"gt" : "2020-01-01 00:00:00",
"lt" : "2021-01-01 00:00:00"
}
}
}
}
匹配查询
GET /_search
{
"query": {
"match" : {
"message" : "this is a test"
}
}
}
排序
POST /_search
{
"query" : {
"term" : { "product" : "chocolate" }
},
"sort" : [
{"price" : {"order" : "asc"}
]
}
from&size
from
+size
不能超过index.max_result_window
默认为 10,000的索引设置。
GET /_search
{
"from" : 0, "size" : 10,
"query" : {
"term" : { "user" : "kimchy" }
}
}
布尔查询
must:子查询必须全部满足,有助于相关性分数提升。
filter:子查询必须全部满足,但不计算相关性分数。
should:子查询可以被满足,如果有must或filter存在,满足should的文档会被加分,没有满足should的文档也可以,如果没有must或filter存在,被查出来的文档至少满足should的一个子查询。
must_not:子查询匹配文档将被过滤,不计算相关性分数。
POST _search
{
"query": {
"bool" : {
"must" : {
"term" : { "user" : "kimchy" }
},
"filter": {
"term" : { "tag" : "tech" }
},
"must_not" : {
"range" : {
"age" : { "gte" : 10, "lte" : 20 }
}
},
"should" : [
{ "term" : { "tag" : "wow" } },
{ "term" : { "tag" : "elasticsearch" } }
],
"minimum_should_match" : 1,
"boost" : 1.0
}
}
}
聚合查询
//平均、最小、最大
POST /_search?size=0
{
"aggs" : {
"avg_grade" : { "avg" : { "field" : "grade" } },
"min_grade" : { "min" : { "field" : "grade" } },
"max_grade" : { "max" : { "field" : "grade" } }
}
}
//result
{
"took" : 1547,
"timed_out" : false,
"num_reduce_phases" : 4,
"_shards" : {
"total" : 1536,
"successful" : 1536,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 27275931,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"max_grade" : {
"value" : 3
},
"min_grade" : {
"value" : 1
},
"avg_grade" : {
"value" : 2
}
}
}
//聚合
POST /ci/_search
{
"aggs": {
"test": {
"terms": {
"field": "class_key",
"size": 5
},
"aggs": {
"max_date": {
"max": {
"field": "create_time"
}
}
}
}
}
}
//result
{
"took" : 28,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 54992,
"max_score" : 1.0,
"hits" : [
//...
]
},
"aggregations" : {
"test" : {
"doc_count_error_upper_bound" : 70,
"sum_other_doc_count" : 5743,
"buckets" : [
{
"key" : "linux",
"doc_count" : 15791,
"max_date" : {
"value" : 1.624006092E12,
"value_as_string" : "2021-06-18 08:48:12"
}
},
{
"key" : "test0331",
"doc_count" : 10155,
"max_date" : {
"value" : 1.591180035E12,
"value_as_string" : "2020-06-03 10:27:15"
}
},
{
"key" : "test0603",
"doc_count" : 10051,
"max_date" : {
"value" : 1.600773229E12,
"value_as_string" : "2020-09-22 11:13:49"
}
},
{
"key" : "ip_endpoint",
"doc_count" : 9513,
"max_date" : {
"value" : 1.624880818E12,
"value_as_string" : "2021-06-28 11:46:58"
}
},
{
"key" : "switch",
"doc_count" : 3731,
"max_date" : {
"value" : 1.59350316E12,
"value_as_string" : "2020-06-30 07:46:00"
}
}
]
}
}
}
数据迁移&数据备份
快照
elasticsearch-dump(第三方插件)
需要nodejs 10.x 以上版本,可以将数据导出成文件 或 在两个集群间进行直接迁移
具体参考 https://github.com/elasticsearch-dump/elasticsearch-dump
Reindex(同库备份、异库迁移)
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
默认情况下 _reindex 以1000的大小滚动批次,可以使用size字段进行批次带下的修改,还可以设置slices参数进行查询优化:
POST _reindex?slices=auto
{
"source": {
"index": "source",
"size": 10000
},
"dest": {
"index": "dest"
}
}
远程迁移(需要在目标集群的协调节点配置文件上修改reindex.remote.whitelist
,添加源集群http地址):
POST _reindex
{
"source": {
"remote": {
"host": "http://otherhost:9200",
"username": "user",
"password": "pass"
},
"index": "source",
"query": {
"match": {
"test": "data"
}
}
},
"dest": {
"index": "dest"
}
}
常见问题
新增数据后,马上查询,查询不到新增的数据
?refresh
参数
在新增,修改,删除和 批量的API支持设置,refresh
以控制当申请所做的更改可见搜索。这些是允许的值:
空字符串或 true
操作发生后立即刷新相关的主分片和副本分片(而不是整个索引),以便更新的文档立即出现在搜索结果中。只有在仔细考虑和验证它不会导致性能不佳后,才应该这样做,无论是从索引还是搜索的角度来看。
wait_for
在回复之前等待通过刷新使请求所做的更改可见。这不会强制立即刷新,而是等待刷新发生。Elasticsearch 会自动刷新每更改一次的分片,index.refresh_interval
默认为一秒。该设置是动态的。在任何支持它的 API 上调用Refresh API 或设置refresh
为true
也会导致刷新,进而导致已经运行的请求refresh=wait_for
返回。
false
(默认)
不执行与刷新相关的操作。此请求所做的更改将在请求返回后的某个时间点可见。
如何查看集群健康状态&分片重新挂载
//查询集群健康度
GET /_cluster/health
GET /_cat/health?v
//查看分片未挂载原因
GET /_cluster/allocation/explain
//将未分配的分片,重新挂在在节点上
GET /_cluster/reroute?retry_failed=true
status:
green: 所有分片都已经分配。
yellow: 所有主分片都已经分配,但至少有一个副本分片没有分配。
red: 至少有一个主分片没有分配,因此部分数据会不可用。
日志在哪里看
默认日志路径:elasticsearch目录\logs
一般看{集群名称}.log
就可以,日志达到一定大小,会自动压缩,每天剩余的日志也会自动压缩。
gc日志看gc.log
,历史的gc日志以gc.log.{序号}
命名
数据可以查询,但无法写入
有数据修改请求的时候发生这个错误
[FORBIDDEN/12/index read-only / allow delete (api)] - read only elasticsearch indices
cluster.routing.allocation.disk.watermark.low
:控制磁盘使用的低水位线。它默认为85%
,这意味着 Elasticsearch 不会将分片分配给磁盘使用率超过 85% 的节点。它还可以设置为绝对字节值(如500mb
),以防止 Elasticsearch 在可用空间少于指定量时分配分片。此设置对新创建的索引的主分片没有影响,特别是对以前从未分配过的任何分片。
cluster.routing.allocation.disk.watermark.high
:控制高水位线。它默认为90%
,这意味着 Elasticsearch 将尝试将分片从磁盘使用率高于 90% 的节点重新定位。它还可以设置为绝对字节值(类似于低水位线)以在节点的可用空间少于指定量时将分片从节点重新定位。此设置会影响所有分片的分配,无论之前是否已分配。
cluster.routing.allocation.disk.watermark.flood_stage
:控制洪水位线,默认为 95%
。Elasticsearch对每个在节点上分配了一个或多个分片并且至少有一个超过泛洪阶段的磁盘的索引强制执行只读索引块 ( index.blocks.read_only_allow_delete
)。此设置是防止节点耗尽磁盘空间的最后手段。当磁盘利用率低于高水位线时,必须手动释放索引块。
解决方法:1. 扩大磁盘 2. 删除历史索引,释放空间 3.更改水位线配置
解除只读:
//单个
PUT /twitter/_settings
{
"index.blocks.read_only_allow_delete": null
}
//全部
PUT /_all/_settings
{
"index.blocks.read_only_allow_delete": null
}
查询文本精确和通配符查询都查不出来
Keyword | Text | |
---|---|---|
精确查询 | 支持 | 支持(分词后的词) |
通配符查询 | 支持 | 支持(分词后的词) |
匹配查询 | 不支持 | 支持 |
排序 | 支持 | 不支持 |
普通聚合 | 支持 | 不支持 |
6.x迁移到7.x需要注意什么
Transport Client 在7.0 中已弃用,将在8.0被删除,推荐使用Rest High Level Client。
type在7.0已经弃用,在创建mapping时,如果需要显示设置type,需要在url上添加include_type_name=true
,在增删改查API中,_doc
将替换原先type部分成为固定组成部分。
//新增
PUT twitter/_doc/user-kimchy
{
"type": "user",
"name": "Shay Banon",
"user_name": "kimchy",
"email": "shay@kimchy.com"
}
//查询
GET twitter/_search
{
"query": {
"bool": {
"must": {
"match": {
"user_name": "kimchy"
}
},
"filter": {
"match": {
"type": "tweet"
}
}
}
}
}
//显示设置mapping并带上type名称
PUT index-1-01?include_type_name=true
{
"mappings": {
"type": {
"properties": {
"bar": {
"type": "long"
}
}
}
}
}
6.x中每个索引默认创建5个索引,1个副本,在7.x 中如果没有额外设置,每个索引默认1个分片,1个副本。
数据删除了能不能恢复
不能
参考资料
6.8版本官方文档
滚动升级es版本
映射字段类型
集群健康度
映射类型在7.x中被删除
异库reindex迁移
基于磁盘的分片分配