ElasticSearch入门教程


在日常开发中,我们使用最多的数据应该就是关系型数据库如 MySQL, Oracle 等,其特性为表结构格式统一易于上手,但有一个缺点就是面对海量数据读写性能相对较差。

非关系型数据库中较为出名的就是 Redis, Postgre, Mongo 等,以 Redis 为例,其数据存储于内存之中,读写速度相对关系型有一个质的飞跃,但同时也带来了内存的损耗。

ElasticSearch 是一款分布式存储数据库,在海量数据查询以及模糊查询时有着不错的性能,解决了 MySQL 等数据库性能瓶颈与 Redis 针对大数据量耗费资源的缺点。

一、概念介绍

1. 索引

Elasticsearch 中并没有库表的概念,取而代之的为索引 (Indices),可以理解为传统数据库的 Database

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 参数非必填。

settingsnumber_of_shards 用于执行数据的分片大小,类似于关系型的中的分区操作,以提高存储查询效率;number_of_replicas 用于指定副本大小,即集群状态多端副本保证数据的安全性以防止数据丢失或损坏。

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

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

2. 字段映射

同理在创建索引时可通过 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 索引别名是一个指向一个或多个索引的稳定引用名称。通过使用别名,可以将查询和索引维护从实际索引名称中分离出来,这为在切换索引版本、重建索引等操作时提供了更大的灵活性。

使用索引别名的优点如下:

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

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. 基本格式

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

需要注意的是每一行数据要以换行符结束,同时内容必须空出最后一行空白行。

{"action": {"metadata"}}
{content}

完成 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. 结构查询

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

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

2. 查询得分

Elasticsearch 中,每个文档的匹配程度可以通过一个称为 “分数”(score)的值来表示。分数反映了文档与查询条件的匹配程度,越匹配的文档得分越高。

当执行查询时,Elasticsearch 计算每个文档的得分,然后按照得分排序返回结果。这个得分是由查询条件中的每个子句(例如,匹配关键词的 must 子句)的相关性计算得出的。

对于 bool 查询中的 must 子句,其中的每个条件都会影响文档的得分。如果一个文档满足多个 must 子句的条件,那么它的得分会相应增加。这样,得分可以用来衡量文档与查询条件的匹配程度。

而对于 filter 子句,其中的条件也用于筛选文档,但它们不会影响文档的得分。filter 子句主要用于对文档进行精确匹配和过滤,而不涉及相关性计算。由于不计算得分,filter 子句的查询更轻量,对于一些不需要计算相关性的场景,这可以提高性能。

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

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

// paging query data
GET http://<ip>:<port>/<index_name>/_search

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

六、条件查询

1. 精准查询

精准查询即与常见关系型中 where 条件中的 = 作用等价。

下述示例的作用效果即等价于 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>"
            }
          }
        }
      ]
    }
  }
}

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. 统计查询

select count(*) from <table_name>

其中 count_num_rows 为自定义名称,value_count 等价于 count(*)aggregations 可简写为 aggs

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

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

2. 分组查询

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
{
  "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"
          }
        }
      }
    }
  }
}

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