前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Elasticsearch 快速开始

Elasticsearch 快速开始

作者头像
波罗学
发布2019-08-26 11:14:42
1.8K0
发布2019-08-26 11:14:42
举报
文章被收录于专栏:码神路漫漫

前言

本文非完全直译译文,主要参考的的是 elasticsearch 6.5 版的官网文档 Getting Started,可以把这篇文章理解为个人学习笔记,我力求详略得当吧。

文末会附上 Getting Started 阅读梳理的思维导图。


为了能更加轻松地进入 elasticsearch 的世界,本文将先从基础角度给介绍了 es 的使用。

什么是 elasticsearch

Elasticsearch 是一款开源的全文搜索与分析引擎,它拥有高扩展、大容量数据的存储和处理特性,有着近乎实时的处理效果。elasticsearch 的使用场景还是比较多的,比如 APP 的搜索服务、ELK 实现日志收集与分析、BI 商业智能等。

本文会逐步引导大家进入 elasticsearch 的世界,初步窥探它的使用。相关内容涉及如下:

  • 了解 elasticsearch 的一些基础但非常核心的概念,比如集群、节点、索引、分片和副本;
  • 学会 elasticsearch 安装与启动,同时为了便于测试,顺带也介绍了 Kibana 的安装启动;
  • 探索集群,介绍集群涉及的一些基础操作,比如健康状态检查、集群节点检查,索引创建等;
  • 更新数据,包括如何进行文档替换、更新,以及如何进行删除,最后通过批处理可以将多个操作组合起来;
  • 数据探索,主要是与搜索和聚合分析相关,介绍了常用的一些搜索 API、Query DSL 和聚合 API 的使用;

整体上的内容还是比较多的。

了解一些基础概念

Elasticsearch 中有一些基础但很核心的概念需要我们提前了解,它们对我们的学习将起到很大帮助。

具体是哪些概念呢?

  • 近实时
  • 集群
  • 节点
  • 索引
  • 类型
  • 文档
  • 分片副本

下面我们将逐一介绍。

近实时

什么是近实时?

它表示一个文档从被索引(存储使文档可搜索)到真正能被搜索之间有一个短暂的延迟,而非实时,这个延迟默认是 1 秒。当然,默认延迟可以修改的。

集群

集群是节点的集合。

集群实现了在多节点上进行大容量数据存储和搜索的能力。每个集群都拥有唯一名称,而节点正是根据集群的名称决定是否加入某个集群。不同环境的集群的名称不能相同,如开发、测试、线上三套环境,集群可分别命名为 logging-dev、logging-test、logging-prod。

节点

节点,集群组成的一部分,负责具体的事务处理,比如数据存储、文档索引、搜索执行等。节点也有唯一个名称,如果没有指定将随机生成。

节点可通过配置集群名称,指定加入哪个集群,节点默认的集群名称是 elasticsearch。如果我们在一个网络环境下启动多个节点,并且它们之间可以相互发现,就将会自动组织一个名称为 elasticsearch 的集群。

索引

索引是一系列相似文档的集合,例如,我们把客户信息存放到一个索引,订单信息存储到另一个索引中。索引可通过名称识别,名称必须小写。当操作文档时,我们需要通过索引名称指定。

索引的数量,集群中并没有限制定义索引的数量。

类型

elasticsearch 6.0 已丢弃功能,不具体介绍了。

有一点需要注意,为与老版本兼容,该功能暂未彻底移除,当前一个索引仍可设置类型,但当前只能指定一个类型。一般情况下,我们设置一个固定 type 即可,比如 _doc。

文档

被索引的基础信息单元,比如一个客户、一件产品、或是一笔订单。文档可用 JSON 形式表示,它是一种非常普遍的数据交换格式。索引中,我们可以存放任意数量的文档。

分片与副本

分片和副本是 elasticsearch 非常核心的概念。

我们知道,elasticsearch 存储的数据量能突破单个硬件的限制,数据处理速度有着近实时的水平。这些都和分片和副本有着很大关系。

分片实现了索引文档分散分布,并且每个切片都是功能完善的,索引是独立的,可能分布在集群中的任意节点。分片的重要性主要体现在使 elasticsearch 存储容量的水平扩展和分布式并行处理都成为了现实。

副本提高了 elasticsearch 的容错能力。网络环境下,异常随时可能发生,比如一些节点或分片从网络中消失。一旦设置了副本,索引就会同时拥有主分片和副本分片。一旦某个分片发生异常,还有其他分片可替代。而且,副本也可以提高请求的处理速度,一个分片上的副本可同时并行处理多个请求。

一句话简述,每个索引可以由多个分片组成,而每个分片也可以拥有多个副本。

介绍完了核心概念,是否已经开始蠢蠢欲动了?开始安装自己的集群吧。

安装与启动

本节主要介绍 elasticsearch 的安装。另外,由于要使用 kibana 的 devtools 控制台,将也会介绍下 kibana 的安装。

安装 elasticsearch

首先安装依赖,elasticsearch 是 Java 开发,6.5 版依赖 Java 8,建议安装 Oracle JDK 1.8.0_131。Java 安装完成后,就可以开始安装 elasticsearch 了。

简单起见,我们只介绍二进制包的安装。

安装过程仅仅三步搞定!

代码语言:javascript
复制
$ curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.4.tar.gz
$ tar -xvf elasticsearch-6.5.4.tar.gz
$ cd elasticsearch-6.5.4/bin
$ ./elasticsearch -d # -d 表示后台启动

安装启动完成后,可通过访问 localhost:9200 确认下实例运行是否正常。

如果想了解 Mac 的 homebrew 安装或 windows 下的 MSI Installer Package 安装,可自行阅读官方文档

安装 kibana

Kibana 的安装与 elasticsearch 的不同,需要区别不同的平台系统。本节将介绍 Mac 与 Linux 下的安装,它们都可以通过下载对应系统的 tar 包完成。

Linux 系统,我们以 Linux x86_64 为例。安装命令如下:

代码语言:javascript
复制
$ wget https://artifacts.elastic.co/downloads/kibana/kibana-6.5.4-linux-x86_64.tar.gz
$ shasum -a 512 kibana-6.5.4-linux-x86_64.tar.gz 
$ tar -xzf kibana-6.5.4-linux-x86_64.tar.gz
$ cd kibana-6.5.4-linux-x86_64/
$ ./bin/kibana

MacOS 系统,安装命令如下:

代码语言:javascript
复制
$ curl -O https://artifacts.elastic.co/downloads/kibana/kibana-6.5.4-darwin-x86_64.tar.gz
$ shasum -a 512 kibana-6.5.4-darwin-x86_64.tar.gz 
$ tar -xzf kibana-6.5.4-darwin-x86_64.tar.gz
$ cd kibana-6.5.4-darwin-x86_64/ 
$ ./bin/kibana

如果希望 kibana 在后台运行,可以通过 nohup 实现。完成后,访问 localhost:5601 下确认状态,它会默认连接本地启动的 elasticsearch 集群。

好吧!我还是不想介绍 Windows 下的安装。

多节点集群

如果希望启动一个多节点集群,我们可以修改下启动命令,在本地同时启动两个节点,集群名称相同情况下,它们将会自动组织成一个新的集群。命令如下:

代码语言:javascript
复制
$ ./bin/elasticsearch -Ecluster.name=cluster_dev -Epath.data=cluster_node01 -Enode.name=node01 -Ehttp.port=9200 -d
$ ./bin/elasticsearch -Ecluster.name=cluster_dev -Epath.data=cluster_node02 -Enode.name=node02 -Ehttp.port=9201 -d

启动成功后,可以进入 kibana 的 devtool 执行 _cat/nodes?v,输出如下:

代码语言:javascript
复制
ip        heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1           29          75   6    3.31                  mdi       -      node01
127.0.0.1           33          75   6    3.31                  mdi       *      node02

我们将会看到集群中已经有了两个节点。

探索集群

经历了前面几步,elasticsearch 集群已经安装完成,但我们要如何与它交流呢?其实,elasticsearch 已经提供了一套全面且功能强大的 REST API,用于与集群交互。REST API 涉及功能包括:

  • 检查集群、节点和索引的健康情况、状态以及统计信息;
  • 管理集群、节点、索引和元数据;
  • 针对索引的增删改查以及搜索 API;
  • 高级搜索功能,比如分页、排序、过滤、脚本处理、聚合等;

本节我们将简单介绍上面提到的部分 API。

集群健康检查

健康检查可以让我们了解集群当前状态,可通过 _cat API 实现。

示例如下:

代码语言:javascript
复制
GET /_cat/health?v

输出结果:

代码语言:javascript
复制
epoch      timestamp cluster     status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1565884060 23:47:40  cluster_dev green           2         2     22  21    0    0        0             0                  -                100.0%

输出结果显示,集群名称为 cluster_dev,状态是 green,当前集群有 2 个节点。

先重点讲讲 green 究竟代表什么意思?

首先,green 表示的是集群的状态,对应字段名称是 status,共有三种状态,分别是 green、yellow 和 red。

  • Green 表示集群运行完全正常(主分片和副本分片都运行正常);
  • Yellow 表示所有主分片可用,但副本没有完全分配;
  • Red 部分数据完全不可用,即无论主分片和副本都非正常运作;

当集群状态是 red 时,仍然可以接收处理搜索请求,但我们需要立刻修复它。

查看集群节点

通过 _cat/nodes,可以列出当前集群下的所有节点,前面在启动一个多节点集群时,我们已经过了使用该 API,不多介绍了。

列出所有索引

_cat/indices?v 能列出集群中的所有索引。说明一下,indices 是 index 的复数形式。

代码语言:javascript
复制
GET _cat/indices

输出如下:

代码语言:javascript
复制
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   us_tweet WXkAeMEvR0eukVOFOM1q3w   5   0          6            0     15.7kb         15.7kb
green  open   gb_user  pbOu0n0XQ96mouQ642eutQ   5   0          1            0      5.7kb          5.7kb
green  open   us_user  idxuhX0LQlekzfbjd6kB5w   5   0          1            0      5.7kb          5.7kb
green  open   gb_tweet SJTleUerT5CaO9Sl-JwIQg   5   0          6            0     15.7kb         15.7kb

我的本地集群经常拿来测试,所以这里会看到已经有很多 index,对于你刚搭建好的集群,输出肯定就是空的。

创建索引

接下来,我们学习下如何创建索引,直接看示例吧。尝试创建一个名为 "customer" 的索引,如下:

代码语言:javascript
复制
PUT customer?pretty

PUT 加上索引名称即可。 customer 索引成功创建后,查看下集群当前索引列表,如下:

代码语言:javascript
复制
GET _cat/indices

输出结果如下:

代码语言:javascript
复制
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
...
green  open   customer 71RYoldbQ6uXMo56t4bSog   5   1          0            0      1.1kb           460b
...

customer 成功创建,包含 5 个主分片和 1 个副本分片,索引中当前的文档数量为 0,索引状态为 green。

索引的状态和集群一样,也是 green、yellow 和 red 这 3 个值,并且含义与集群状态类似。green 是全功能正常,yellow 表示副本未完全分配,red 表示部分主分片不可用。我们可以测试一下,停止集群中的一个节点,这时 customer 的状态将会马上切换为 yellow 状态。

索引和查询文档

在 elasticsearch 中,"索引" 这个名词常常会搞晕我们。一般讲到索引,主要是指它的名词含义,比如我们说,创建一个 customer 索引。但有时,它又是动词,比如我们在增加和更新文档时,常会说索引一个文档,在这种情况下,可以把它理解为存储文档并使其可搜索。

那如何索引一个文档呢?比如,索引一个 ID 为 1 的 customer 文档到 customer 索引中,如下。

代码语言:javascript
复制
PUT /customer/_doc/1?pretty
{
  "name": "John Doe"
}

响应返回:

代码语言:javascript
复制
{
  "_index" : "customer",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

结果表明,我们已经成功创建一个 ID 为 1 的文档。从这里也能看出,在索引一个文档之前,并不要求我们明确创建索引 customer,如果 customer 索引不存在,elasticsearch 将会自动帮助我们创建索引。

检索刚才索引的文档。

代码语言:javascript
复制
GET /customer/_doc/1?pretty

响应如下:

代码语言:javascript
复制
{
  "_index" : "customer",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : { "name": "John Doe" }
}

found 字段表明,我们已经成功检索到了一个 ID 为 1 的文档。_source 中的内容是检索文档的完整内容。

删除索引

让我们删除掉刚刚创建的索引。

代码语言:javascript
复制
DELETE /customer?pretty

如此,我们就成功删除了之前创建的 customer。如果不确定,可以使用 GET _cat/indices 检查下。

文档 API

回顾下前面介绍的那些 API,我们重新再走一遍。

代码语言:javascript
复制
PUT /customer
PUT /customer/_doc/1
{
  "name": "John Doe"
}
GET /customer/_doc/1
DELETE /customer

仔细观察上面的命令,你可能会发现一个比较通用的模式,如下:

代码语言:javascript
复制
<HTTP Verb> /<Index>/<Type>/<ID>

这个模式在 elasticsearch 中非常普遍,记住它,这将对 elasticsearch 学习之旅将会非常有帮助。

更新数据

区别于传统关系型数据库的实时性特点,elasticsearch 是近实时的,也就是说,在文档被 create/update/delete 与搜索结果中出现之间将会有 1 秒的延迟。

文档替换

创建和替换文档本质上都属于索引文档,因而,我们之前用来创建文档的命令同样适用于文档替换。

因为 customer 索引重建过,我们重新创建一个 ID 为 1 的文档。如下:

代码语言:javascript
复制
PUT /customer/_doc/1?pretty
{
  "name": "John Doe"
}

同样的命令即可实现文档更新,我们只需要传递不同的文档内容即可,如下:

代码语言:javascript
复制
PUT /customer/_doc/1?pretty
{
  "name": "Jane Doe"
}

将 ID 为 1 的文档中 name 由 Johh Doe 更新为 Jane Doe。如果指定 ID 文档不存在,将会创建新的文档,否则更新当前文档。

比如,ID 为 2 的文档不存在,通过如下命令创建。

代码语言:javascript
复制
PUT /customer/_doc/2?pretty
{
  "name": "Jane Doe"
}

索引文档时,ID 不是必须的,如果不指定,elasticsearch 会自动为这个文档指定一个随机的 ID,并作为响应的一部分返回给你。

示例如下:

代码语言:javascript
复制
POST /customer/_doc?pretty
{
  "name": "Jane Doe"
}

这种情况下,我们需要使用 POST 代替 PUT 提交请求。

响应结果:

代码语言:javascript
复制
{
  "_index": "customer",
  "_type": "_doc",
  "_id": "Z-RnpGwBe6KTDC6t3MGV",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}

上面可以看到 elasticsearch 为我们生成的文档 ID,Z-RnpGwBe6KTDC6t3MGV。

更新文档

说完文档的索引和替换,我们再来谈谈文档的更新。提前说明,elasticsearch 并非真的去更新文档,它的更新操作与替换类似,包含删除旧文档和索引新文档两个操作。

示例演示,更新前面创建的 ID 为 1 的文档,更新 name 字段为 Jane Doe。

代码语言:javascript
复制
POST /customer/_doc/1/_update?pretty
{
  "doc": { "name": "Jane Doe" }
}

示例 2,更新 name 为 Jane Doe 的同时,增加一个字段 age。

代码语言:javascript
复制
POST /customer/_doc/1/_update?pretty
{
  "doc": { "name": "Jane Doe", "age": 20 }
}

示例 3,使用脚本更新文档,比如将 ID 为 1 的文档的字段 age 加 5。

代码语言:javascript
复制
POST /customer/_doc/1/_update?pretty
{
  "script": "ctx._source.age += 5"
}

上面的例子,ctx._source 表示的是我们将要更新的文档。这里是通过指定 ID 的方式查询要更新的文档,elasticsearch 也可以像 SQL 一样,通过复杂查询实现更新。

删除文档

删除文档最简单直接,HTTP 方法换成 DELETE,指定文档 ID 即可。如下:

代码语言:javascript
复制
DELETE /customer/_doc/2?pretty

和更新类似,删除也可以根据查询结果执行删除,API 是 _delete_by_query。如果是删除索引中的所有文档,直接删除索引更直接点。

批处理

经过前面的学习,我们已经了解了 elasticsearch 一些基础 API 的使用,如文档的索引、更新、删除。这一小节介绍一个新的 API,_bulk API,它支持将多个操作打包成一个请求,实现批处理。这样可以更加高效的执行操作,也能减少网络传递次数。

一个快速入门案例,如下:

代码语言:javascript
复制
POST /customer/_doc/_bulk?pretty
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }

索引了 2 个文档,一个文档 ID 1,name 为 John Doe,另一个文档 ID 2,name 为 Jane Doe。

再看一个案例,如下:

代码语言:javascript
复制
POST /customer/_doc/_bulk?pretty
{"update":{"_id":"1"}}
{"doc": { "name": "John Doe becomes Jane Doe" } }
{"delete":{"_id":"2"}}

批处理包含 2 个操作,更新 ID 为 1 文档的 name 字段和删除 ID 为 2 的文档。

批处理中的一个操作失败并不会导致整个 bulk API 处理失败,如果一个操作失败,剩下来的其他操作仍会继续执行。bulk API 处理完成后,响应结果中会包含每个操作的处理结果。

数据探索

本节内容主要涉及两个方面:搜索与分析。

数据

搜索分析不可缺少数据,我们将使用 elastic 官方提供的数据样本,相对而言,应该比自己的生成更符合真实场景。

一个文档,示例如下:

代码语言:javascript
复制
{
    "account_number": 0,
    "balance": 16623,
    "firstname": "Bradshaw",
    "lastname": "Mckenzie",
    "age": 29,
    "gender": "F",
    "address": "244 Columbus Place",
    "employer": "Euron",
    "email": "bradshawmckenzie@euron.com",
    "city": "Hobucken",
    "state": "CO"
}

官方的数据是用工具随机生成的,工具地址。有兴趣,可以设置自己的数据生成规则。

开始数据加载之前,要先下载数据,下载地址

代码语言:javascript
复制
$ wget https://raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/test/resources/accounts.json

下载完成后,执行如下命令加载数据:

代码语言:javascript
复制
$ curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_doc/_bulk?pretty&refresh" --data-binary "@accounts.json"

查看索引信息

代码语言:javascript
复制
$ curl "localhost:9200/_cat/indices?v"

响应如下:

代码语言:javascript
复制
health status index uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   bank  FFcSux-ETmmUlMJNBCEyqA   5   1       1000            0      957kb        482.3kb

可以看出,我们已经为 bank 成功索引了 1000 个文档。

搜索 API

开始尝试一些简单的搜索。有两种基本的搜索方式:

  • URI Search,通常 URI 参数指定搜索参数。
  • Request Body,在请求内容包含在请求体中发送。

相对而言,Request Body 方式更灵活,包含了全部的搜索支持。而 URI Search 主要在测试时使用,比较方便。

搜索请求通过 _search 执行。一个示例,通过搜索返回 bank 索引中的所有文档。

代码语言:javascript
复制
GET /bank/_search?q=*&sort=account_number:asc&pretty

URI Search 方式实现搜索,通过 q=* 执行匹配全部文档,sort=account_number:asc 指定排序方式。

响应如下:

代码语言:javascript
复制
{
  "took" : 63,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : null,
    "hits" : [ {
      "_index" : "bank",
      "_type" : "_doc",
      "_id" : "0",
      "sort": [0],
      "_score" : null,
      "_source" : {"account_number":0,"balance":16623,"firstname":"Bradshaw","lastname":"Mckenzie","age":29,"gender":"F","address":"244 Columbus Place","employer":"Euron","email":"bradshawmckenzie@euron.com","city":"Hobucken","state":"CO"}
    }, ...
    ]
  }
}

结果中的各个参数函数如下:

  • took 表示搜索执行时间
  • timed_out 搜索是否超时
  • _shards 多少分片参与搜索,以及成功与失败的情况如何。
  • hits 搜索结果
  • hits.total 匹配搜索条件的文档数量
  • hits.hits.sort 排序
  • hits.hits._score 和 max_score,相关度得分,指定排序,字段会被忽略。

通过 Reuqest Body 方式执行与上面相同的操作,如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ]
}

我们下面主要介绍 Request Body 的使用,毕竟它更加强大。

DSL 介绍

DSL,全称 Domain Special Language, 即特定领域语言,elasticsearch 制定了一套 JSON 风格的 DSL 语言。它支持的功能非常全面,刚学习它时,会让我们产生一种恐惧,因为它真的很难。我们可以先从一些简单的例子看起。

查询所有文档,如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match_all": {} }
}

解剖下请求体。query 定义查询语句,match_all 就是我们将会执行的查询语句,表示匹配索引中的所有文档。

执行上面的查询语句默认只会返回 10 条文档,我们可以通过指定 size 参数改变默认获取文档数量。如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match_all": {} },
  "size": 1
}

通过 from 和 size 可以实现分页效果,如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match_all": {} },
  "from": 10,
  "size": 10
}

from 用于指定文档偏移的开始位置,相当于 SQL 中的 offset。

文档默认根据搜索相关度得分排序,不过我们这里是默认匹配全部,所以文档的相关度得分都是1。除了相关度排序,还可以按其他字段,比如 balance 字段。如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": { "balance": { "order": "desc" } }
}

搜索查询语句

继续看下搜索返回文档字段,默认情况下,搜索将会返回文档的所有字段内容。我们可通过 _source 指定只返回部分内容。

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}

如此,搜索将只返回 account_numberbalance 两个字段。 了解的 SQL 的朋友可以将其与 SELECT 指定列类比。

继续看查询部分吧!

前面,通过 match_all 查询匹配了全部文档。现在,我们再引入一个新的查询语句,match,它是基于一个字段的查询。

查询 account_number 为 20 的文档。示例如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match": { "account_number": 20 } }
}

查询 address 包含 mill 的文档。示例如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match": { "address": "mill" } }
}

查询 address 包含 mill 或 lane 的文档。示例如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match": { "address": "mill lane" } }
}

match 基于分词查询,2 个查询单词是 or 的关系。如果我们就要搜索 "mill lane" 呢? 这时可以使用 match_pharse。示例如下:

查询 address 包含 "mill lane" 的文档。示例如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": { "match_phrase": { "address": "mill lane" } }
}

继续介绍 bool 查询,它允许我们将上面这些基础查询组合形成一个复合查询。比如,查询同时包含 "mill" 和 "jane" 的文档。

示例如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

例子中的 bool must 表示文档必须同时满足两个 must 条件。如果是只要满足一个条件即可,我们可以使用 bool should,示例如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

如果要求两者必须不满足,我们可以使用 bool must_not,示例如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": {
    "bool": {
      "must_not": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

bool 查询中还可以将上面的这几种查询同时组合起来,同时包含 must、must_not 和 should。

示例如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
}

注意一点,如果是 must、must_not 和 should 组合时,should 就缺少了必须满足一个才算匹配的限制,这时,我们可以通过 minimum_should_match 指定 should 匹配个数。

更复杂的,bool 查询中还可以包含其他的 bool 查询。这里先不介绍了。

过滤语句

谈到过滤之前,我们就不得不提文档相关度评分,相关度评分是用于衡量搜索语句与文档的匹配程度的一个指标。前面已经提过的查询语句都会参与到这个指标的计算。

但有时,查询仅仅是为了过滤一些不满足条件的文档,我们并不希望它们也参与到相关度评分的计算中,由此,我们并引入了 filter。

前面介绍的 bool 查询中便支持 filter 功能。它可以在不影响相关度评分的情况下,实现文档过滤。如下:

代码语言:javascript
复制
GET /bank/_search
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}

bool 查询中包含了 must 和 filter 两部分。filter 部分通过 range query 实现只查询 blanace 满足指定区间的文档,must 中的 match_all 实现全部文档返回。

除了上面介绍的查询,如 match_all、match、bool、range,elasticsearch 还有很多其它查询可用,这里不详细介绍了。只要掌握了前面的知识,我们已经完全可以照猫画虎。

聚合功能

利用 elasticsearch 的聚合能力,我们可以实现分组统计,可以和 SQL 的 GROUP BY 分组和聚合函数类比。搜索和聚合都是通过 _search 请求实现,同一个请求可同时处理搜索与聚合的请求。这样也可以帮助我们节省必要的网络带宽。

一个例子,按银行卡账号状态(即 state)分组。默认是返回 top 10。如下:

代码语言:javascript
复制
GET bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      }
    }
  }
}

如何 SQL 呢?如下:

代码语言:javascript
复制
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC LIMIT 10;

响应如下:

代码语言:javascript
复制
{
  "took": 29,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped" : 0,
    "failed": 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "group_by_state" : {
      "doc_count_error_upper_bound": 20,
      "sum_other_doc_count": 770,
      "buckets" : [ {
        "key" : "ID",
        "doc_count" : 27
      }, {
        "key" : "TX",
        "doc_count" : 27
      }, {
        "key" : "AL",
        "doc_count" : 25
      }, {
        "key" : "MD",
        "doc_count" : 25
      }, {
        "key" : "TN",
        "doc_count" : 23
      }, {
        "key" : "MA",
        "doc_count" : 21
      }, {
        "key" : "NC",
        "doc_count" : 21
      }, {
        "key" : "ND",
        "doc_count" : 21
      }, {
        "key" : "ME",
        "doc_count" : 20
      }, {
        "key" : "MO",
        "doc_count" : 20
      } ]
    }
  }
}

从上面可以看出,ID 为 Idaho 的数量为 27,紧接着是 TX 数量 27,然后是 AL 共 25 个。上面设置 size 为 0,是为隐藏搜索结果内容,仅仅显示聚合结果。

我们可以在前面的聚合结果的基础上,计算 top 10 的账户余额平均值。如下:

代码语言:javascript
复制
GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword",
        "order": {
          "average_balance": "desc"
        }
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

在 group_by_state 中加入子聚合 average_balance,同时在 group_by_state 中,通过 order 配置实现了按 balance 平均值大小排序的需求。

下面这个例子演示了如何按年龄区间分组,比如 20-29、30-39 和 40-49,并在基础上,继续按性别分组。最后,计算各个分组 balance 的平均值。

代码语言:javascript
复制
GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          },
          {
            "from": 40,
            "to": 50
          }
        ]
      },
      "aggs": {
        "group_by_gender": {
          "terms": {
            "field": "gender.keyword"
          },
          "aggs": {
            "average_balance": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
  }
}

例子中有两个分组 group_by_age 和 group_by_gener 以及一个聚合计算 average_balance。

总的来说,上面的例子还是比较循环渐进的。但主要还是集中在使用层面,并没有太多细节的介绍。如果想了解更多与聚合相关的内容,可自行查询官方文档。

总结

Elasticsearch 可以说是一款即简单又复杂的产品。本文只是简单介绍了它的一些基础,并初步体验了下它的使用。到此,仅仅算是开启了一扇门,elasticsearch 的使用远没有那么简单。

再接再厉吧!朋友!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年08月25日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 什么是 elasticsearch
  • 了解一些基础概念
    • 近实时
      • 集群
        • 节点
          • 索引
            • 类型
              • 文档
                • 分片与副本
                • 安装与启动
                  • 安装 elasticsearch
                    • 安装 kibana
                      • 多节点集群
                      • 探索集群
                        • 集群健康检查
                          • 查看集群节点
                            • 列出所有索引
                              • 创建索引
                                • 索引和查询文档
                                  • 删除索引
                                    • 文档 API
                                    • 更新数据
                                      • 文档替换
                                        • 更新文档
                                          • 删除文档
                                            • 批处理
                                            • 数据探索
                                              • 数据
                                                • 搜索 API
                                                  • DSL 介绍
                                                    • 搜索查询语句
                                                      • 过滤语句
                                                        • 聚合功能
                                                        • 总结
                                                        相关产品与服务
                                                        Elasticsearch Service
                                                        腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
                                                        领券
                                                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档