ElasticSearch 接口教程


ElasticSearch 是一款分布式存储数据库,提供基于 RESTFUL 风格的操作方式,即通过接口请求的方式即可实现数据的增删改查,下面就让我们学习一下相应接口请求格式。

一、概念介绍

1. 索引

Elasticsearch 中并没有库表的概念,取而代之的为索引 (Indices),可以简单的理解为数据库。不过随着 7.x 版本后中对 Types 的弃用,索引此时更像是单表数据库。

2. 类型

Elasticsearch 6.xTypes 概念类似于数据库中的一张表,但随着版本更新,在最新的 7.x 版本中 Types 被逐渐废除,因此一个索引 Indices 下只允许存在一个 Types

3. 文档

Elasticsearch 中每条记录是以文档 (Documents) 的形式存在,相当于 MySQL 等数据表中的一条记录,每条文档都会自动为其分配一个唯一标识。

4. 字段

Fields 即为每条文档中的属性的类型,常用类型包含如下几类:

类型 描述
text 当一个字段需要用于全文搜索(会被分词)则应该使用该类型。
keyword 当一个字段需要按照精确值进行过滤、排序、聚合等操作时则应该使用该类型。
date 时间类型,精度不包含时分秒。
boolean 布尔类型,即 true 与 false。
range 区间类型,取值范围如下:integer_range, long_range, float_range, double_range, date_range, ip_range

二、数据索引

1. 索引创建

通过 PUT 请求创建新索引,请求格式如下,其中 settings 参数非必填。

PUT http://<ip>:<port>/<index_name>

{
    "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 2
    }
}

settings 除了上述的示例外还包含下表参数配置:

参数 数据示例 描述
number_of_shards 2 索引的分片数量。
number_of_replicas 2 索引的副本数量。
refresh_interval 10s 索引刷新间隔,数据写入到可搜索的过程,默认 1s。
index.max_result_window 10000 索引查询返回条数限制,默认 1w 条。
index.mapping.total_fields.limit 200 索引查询返回的字段数,默认 1000。
index.translog.durability request/async 事务日志写入策略,请求后写入 (request),异步写入 (async)。

其中较为让人混淆的即分片数 (number_of_shards) 与副本数 (number_of_replicas),二者具体的配置的值主要依据集群中的节点数量而定,通过 1:1 是一个相对稳定的参照,下面我们着重介绍一下二者的区别。

(1) 分区

number_of_shards 用于执行数据的分片大小,类似于关系型的中的分区操作,以提高存储查询效率。

例如上述中的 "number_of_shards": 3 表示分片数为 3,则会将索引下创建 3 个分片,而每个分片可以位于集群中的不同节点,即减少单个数据文件的大小从而提高性能。

(2) 副本

number_of_replicas 用于指定副本大小,即集群状态多端副本保证数据的安全性以防止数据丢失或损坏。

同样以上述的示例为例,索引创建了 3 个分片且副本为 2,即每个分片包括自身存在 2 份备份,且副本通常也分布于集群内不同节点中,当其中一个副本损坏时另一副本可以保证数据的稳定性。

2. 字段映射

在创建索引时除了 settings 配置参数外,也可通过 mapping 参数指定字段映射。

mapping 即文档记录的结构,虽然在不指定时会根据文档数据类型自动匹配,但可能存在细节差异,为了取得更优的性能建议根据实际情况手动配置,映射内容中的 type 参数上一点中的表格。

PUT http://<ip>:<port>/<index_name>

{
    "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 2
    },
    "mapping": {
        "_doc": {
            "properties": {
                "id": {
                    "type": "keyword"
                },
                "name": {
                    "type": "text"
                }
            }
        }
    }
}

3. 索引别名

Elasticsearch 索引别名是一个指向一个或多个索引的稳定引用名称。

通过使用别名,可以将查询和索引维护从实际索引名称中分离出来,索引别名常用场景如下:

  • 日志切割:对于日志类型的索引,可以使用别名轻松地进行日志切割。
  • 切换版本:可以通过更改别名指向的实际索引,而不必更改应用程序中的查询代码。
  • 滚动升级:在进行索引版本升级时可以创建新版本的索引,通过别名将查询指向新索引,实现滚动升级。

Elasticsearch 中指定索引名称也并不复杂,通过 aliases 参数进行配置,请求格式如下,其中 <alias_name> 为需要设置的别名。

PUT http://<ip>:<port>/<index_name>

{
  "aliases": {
    "<alias_name>": {}
  }
}

如果是在索引创建完成之后添加别名,则可通过 _aliases 接口,请求格式如下:

POST http://<ip>:<port>/_aliases

{
  "actions": [
    {
      "add": {
        "index": "<index_name>",
        "alias": "<alias_name>"
      }
    }
  ]
}

4. 索引删除

通过 DELETE 请求删除索引,删除索引会同步删除其对应下的数据,请求格式如下:

DELETE http://<ip>:<port>/<index_name>

三、数据增改

1. 数据插入

数据插入的请求模板示例如下,其中 <type> 的可选值为:_doc,且 <id> 若未指定则回自动分配。

POST http://<ip>:<port>/<index>/<type>/<id>

{ 
    "field1": "value1", 
    "field2": "value2", 
    "field3": "value3" 
}

2. 数据更新

数据更新的请求模板示例如下:

PUT http://<ip>:<port>/<index>/<type>/<id>

{ 
    "field1": "value1_1", 
    "field2": "value2_1", 
    "field3": "value3_1" 
}

3. 数据删除

数据删除的请求模板示例如下:

DELETE http://<ip>:<port>/<index>/<type>/<id>

四、批量操作

1. 基本格式

Elasticsearch 批量操作的基本请求格式如下,需注意 content 中每一行代表一条记录需要以换行符结束,同时内容必须空出最后一行空白行。

{"action": {"metadata"}}

{content}

其中 action 可选值参考下表:

action 参数
create 创建新的一条记录。
update 更新已有一条记录。
index 若记录存在,则进行覆盖。
delete 删除一条数据记录。

完成 JSON 数据文件的创建后在 PostMan 中可通过下述入口选择上传。

2. 批量插入

(1) 索引不存在

批量插入数据,索引不存在时新建。

POST http://<ip>:<port>/_bulk

// 文件内容
{"create":{"_index": "<index_name>","_type": "_doc","_id": "1"}}
{"id": "1", "name":"alex"}
{"create":{"_index": "<index_name>","_type": "_doc","_id": "2"}}
{"id": "2", "name":"beth"}
(2) 索引存在

批量插入数据,索引必须已存在。

POST http://<ip>:<port>/<index>/_doc/_bulk

// 文件内容
{"create":{"_id": "1"}}
{"id": "1", "name":"alex"}
{"create":{"_id": "2"}}
{"id": "2", "name":"beth"}
(2) 增量插入

批量插入数据,若数据已存在则覆盖。

POST http://<ip>:<port>/<index>/_doc/_bulk

// 文件内容
{"index":{"_id": "1"}}
{"id": "1", "name":"alex"}
{"index":{"_id": "2"}}
{"id": "2", "name":"beth"}

3. 批量更新

批量更新的请求模板示例如下:

POST http://<ip>:<port>/<index>/_doc/_bulk

// 文件内容
{"update":{"_id": "1"}} 
{"doc": {"id": "1"}} 
{"update":{"_id": "2"}} 
{"doc": {"id":"2"}}

4. 批量删除

批量删除的请求模板示例如下:

POST http://<ip>:<port>/<index>/_doc/_bulk

// 文件内容
{"delete":{"_id": "1"}}
{"delete":{"_id": "2"}}

五、数据查询

1. 查询得分

Elasticsearch 中,每个文档的匹配程度可以通过分数 (score) 表示,其反映了文档与查询条件的匹配程度,越匹配的文档得分越高。当执行查询时会计算每个文档的得分,然后按照得分排序返回结果,这个得分是由查询条件中的每个子句(例如,匹配关键词的 must 子句)的相关性计算得出的。

对于 bool 查询中的 must 子句,其中的每个条件都会影响文档的得分,若一个文档满足多个 must 子句的条件,那么它的得分会相应增加。而对于 filter 子句,其中的条件也用于筛选文档但不会影响文档的得分。filter 子句主要用于对文档进行精确匹配和过滤,由于不计算得分,filter 子句的查询更轻量,对于一些不需要计算相关性的场景可以提高性能。

因此,当使用 filter 子句时,查询的主要目的是过滤文档,而不是影响查询结果的排序和相关性。这对于一些特定的过滤条件(如范围查询、精确匹配等)非常有用,因为它们可以更高效地执行,而无需计算和排序相关性得分。

2. 结构查询

通过 _mapping 查询当前索引下的数据字段结构。

GET http://<ip>:<port>/<index>/_mapping

3. 全量查询

通过 Get 查询目标数据,效果等价于 select * from <table>

默认查询仅返回十条数据,若查看多数据需分页进行,同时通过 pretty=true 可格式化返回的结果数据。

GET http://<ip>:<port>/<index_name>/_search


GET http://<ip>:<port>/<index_name>/_search?pretty=true

4. 分页查询

分页查询同理,在请求体内通过 fromsize 指定分页参数,作用类似 MySQL 中的 limitoffset

在设置分页查询时需要注意 Elasticsearch 默认一次性能够返回条数只有 1w 条,若需要查询大批量数据需调整 max_result_window 参数设置返回条数限制。

GET http://<ip>:<port>/<index_name>/_search

{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 10
}

六、条件查询

1. 精准查询

精准查询即与常见关系型中 where 条件中的 = 作用等价,通过 must 查询默认会为文档计算得分。

下述示例的作用效果即等价于 select * from <table> where <column_name> = <column_name>

GET http://<ip>:<port>/<index_name>/_search

{
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "<column_name>": {
              "query": "<column_value>"
            }
          }
        }
      ]
    }
  }
}

同理也可将上述的 must 替换为 filter 从而获取更优的性能。

{
  "query": {
    "bool": {
      "filter": [
        {
          "match_phrase": {
            "<column_name>": {
              "query": "<column_value>"
            }
          }
        }
      ]
    }
  }
}

同时在查询时除了上述的 match_phrase 外还可通过 term 进行过滤。

match_phrase 用于查找包含指定短语的文档,短语中的词必须按照给定的顺序出现,并且是连续的。而 term 查询用于精确匹配字段的值,输入不会被分词器处理,常用于匹配关键字字段或未分词的字段。

2. 区间查询

区间查询即与常见关系型中 where 条件中的 in 作用等价。

下述示例的作用效果即等价于 select * from <table> where <column_name> in (1, 2, 3)

GET http://<ip>:<port>/<index_name>/_search

{
  "query": {
    "bool": {
      "must": [
        {
          "terms": {
            "<column_name>": [1, 2, 3]
          }
        }
      ]
    }
  }
}

3. 范围查询

范围查询即与常见关系型中 where 条件中的 >, >=, <, <= 作用等价。

其中不同的符号对应参考下表:

范围符 ES 关键字
> gt
>= from
< lt
<= to

下述示例的作用效果即等价于 select * from <table> where <column_name> >= 1

GET http://<ip>:<port>/<index_name>/_search

{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "<column_name>": {
              "from": "1"
            }
          }
        }
      ]
    }
  }
}

七、聚合查询

1. 行数统计

Elasticsearch 同样支持关系型数据库中的聚合函数等操作,如下述示例即查询索引中的记录条数。

其中 count_num_rows 为自定义名称,value_count 等价于 count(*)aggregations 可简写为 aggs,其最终效果等价于 select count(*) from <table_name>

GET  http://<ip>:<port>/<index>/_search

{
  "size": 0,
  "aggregations": {
    "count_num_rows": {
      "value_count": {
        "field": "_index"
      }
    }
  }
}

2. 分组查询

同理其支持复杂的分组查询,例如下述示例:

{
  "size": 0,
  "aggs": {
    "group_date": {
      "date_histogram": {
        "field": "<time_field>",
        "interval": "hour",
        "time_zone": "+08:00",
        "format": "yyyy-MM-dd HH:mm:ss"
      },
      "aggs": {
        "num_filter": {
          "bucket_selector": {
            "buckets_path": {
              "count": "_count"
            },
            "script": "params.count > 0"
          }
        }
      }
    }
  }
}

其等价于 MySQL 中的下述查询:

select 
    DATE_FORMAT('<time_field>', '%Y-%m-%d %H:00:00') as time,
    COUNT(*) AS num
from 
    <table_name>
group by 
    time
having 
    num > 0;

注意字段 <time_field> 的类型 type 必须为 date,其中 interval 的可选值如下:

参数 描述
year
quarter 季度
month
week
day
hour 小时
minute 分钟
second

文章作者: 烽火戏诸诸诸侯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
  目录