ElasticSearch 入门教程


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

一、概念介绍

1. 索引

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

2. 类型

在 Elasticsearch 6.x 中 Types 概念类似于数据库中的一张表,但随着版本更新,在最新的 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 个分片,拆分减小单个数据文件的大小从而提高性能,且每个分片可以位于集群中的不同节点。

(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. 分页查询

分页查询同理,在请求体内通过 from 与 size 指定分页参数,作用类似 MySQL 中的 limit 和 offset。

在设置分页查询时需要注意 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 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
赏
  目录