Elasticsearch7教程

2021-04-05 11:17:07 浏览数 (1)

Elasticsearch7教程

Elasticsearch快速入门,掌握这些刚刚好!

前序

Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。

正排索引和倒排索引

导读

索引(index)作为一种具备各种优势的数据结构,被大量应用在数据检索领域。其中倒排索引数据结构在搜索引擎框架中扮演着非常重要的角色。

假设我们有网页1和网页2:

  • 网页1:厦门SEO顾问潇湘驭文为您提供厦门SEO培训服务。
  • 网页2:SEO是一门艺术。

正排索引

经过搜索引擎初步分词之后,网页1和2的正向索引如下图所示:

假设使用正向索引,那么当你搜索SEO的时候,搜索引擎必须检索网页中的每一个关键词,假设一个网页中包含成千上百个关键词,可想而知,会造成大量的资源浪费。于是倒排索引应运而生。

倒排索引

倒排索引是相对正向索引而言的,你也可以将其理解为逆向索引。它是一种关键词与网页一一对应的数据结构。如下图所示:

从上图可以一目了然,倒排索引可以直接参与排名。

比如你搜索“SEO”,搜索引擎可以快速检索出包含“SEO”搜索词的网页1和网页2,为后续的相关度和权重计算奠定基础,从而大大加快了返回搜索结果的速度。

下载及配置

下载

软件名

下载地址

Elasticsearch

https://www.elastic.co/cn/start

Kibana

https://www.elastic.co/cn/start

Logstash

https://www.elastic.co/cn/downloads/logstash

解决跨域

当使用 elasticsearch-head 会存在跨域问题。

修改 *Elasticsearch *配置文件 ..elasticsearch-7.10.1configelasticsearch.yml

代码语言:javascript复制
# 解决端口 9100 访问 9200 跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"

中文显示

当使用 Kibana 可以设置成中文

修改 Kibana 配置文件 ..kibana-7.10.1-windows-x86_64configkibana.yml

代码语言:javascript复制
# 改成中文
i18n.locale: "zh-CN"

Elasticsearch的基本概念

shard(分片)

单台机器(节点)无法存储大量的索引数据, ES可以把一个完整的索引分成多个分片, 分布到不同的节点上, 从而构成分布式索引. 每个分片都是一个Lucene实例, 也就是说每个分片底层都有一个单独的Lucene提供独立的索引和检索服务, 它们可以托管在集群的任一节点上. 单个Lucene中存储的索引文档最大值为 lucene-5843, 极限是2147483519(=integer.max_value - 128) 个文档. 可使用_cat/shards API 监控分片的大小.

分片好处

允许水平切分/扩展集群容量; 可在多个分片上进行分布式的、并行的操作, 提高系统的性能和吞吐量.

注意事项

分片的数量只能在创建索引前指定, 创建索引后不能修改. 5.x 版本默认不能通过配置文件elasticsearch.yml定义分片个数.

replica(副本)

ES支持为每个Shard创建多个副本, 相当于索引数据的冗余备份. 分片有Primary Shard(主分片)、Replica Shard(副本分片), 建立索引时, 系统会先将索引存储在主分片中, 然后再将主分片中的索引复制到不同的副本中.

副本的重要性

  1. 解决单点问题, 提高可用性和容错性: 某个节点失败时服务不受影响, 可以从副本中恢复;
  2. 提高查询效率和查询时的吞吐量: 搜索可以在所有的副本上并行执行, 提高了服务的并发量.

注意事项

主分片在建立索引时设置, 后期不能修改; 主分片和副本分片不能存储在同一个节点中 —— 无法保证高可用. 5.x版本中, 默认主分片为5个, 默认副本分片数为1个, 即每个主分片各有1个副本分片(共5个副本分片); 可随时修改副本分片的数量. 默认情况下, 每个索引共有 5 primary shard 5 * 1 replica shard = 10 shard. 集群中至少要有2个节点, 这是最少的高可用配置.

index(索引)

索引是具有相似结构的文档的集合, 等同于Solr中的集合, 比如可以有一个商品分类索引, 订单索引. 每个索引都要有唯一的名称, 名称要小写, 通过索引名称来执行索引、搜索、更新和删除等操作. 一个集群中可以有任意多个索引, 只要保证名称不同即可.

document(文档)

文档是存储在ES中的一个个JSON格式的字符串, 是ES索引中的最小数据单元, 由field(字段)构成.

type(类型)

type是index的逻辑分类, 在ES 6.x版本之前, 每个索引中可以定义一个或多个type, 而在6.X版本之后, 一个index中只能定义一个type. 一种type一般被定义为具有一组公共field的document, 比如对博客系统中的数据建立索引, 可以定义用户数据type, 博客数据type, 评论数据type, 也就是每个document都必须属于某一个具体的type, 也就是说每个document都有_type属性.

mapping(映射)

类似于关系数据库中的Table结构, 每个index都有一个映射: 定义索引中每个字段的类型. 所有文档在写进索引之前都会先进行分析, 如何对文本进行分词、哪些词条又会被过滤, 这类行为叫做映射(mapping). 映射可以提前定义, 也可以在第一次存储文档时自动识别. 一般由用户自己定义规则. 类似于Solr中schema.xml约束文件的作用.

field(字段)

字段可以是一个简单的值(如字符串、数字、日期), 也可以是一个数组, 还可以嵌套一个对象或多个对象. 字段类似于关系数据库中表数据的列, 每个字段都对应一个类型. 可以指定如何分析某一字段的值, 即对field指定分词器.

概念关系图

ES的索引中, 各概念的关系为: Field –> Document –> Type –> Index, 索引结构图如下:

注意:在7.0之前,一个Index可以创建多个类型,从7.0开始,一个索引只能创建一个类型,也就是 _doc

与关系型数据库的对比:

Elasticsearch

RDBMS

Index(索引)

DataBase(数据库)

Type(类型)

Table(表)

Document(文档)

Row(行)

Field(字段)

Column(列)

Mapping(映射)

Schema(约束)

Everything is indexed(存储的都是索引)

Index(索引)

Query DSL(ES独特的查询语言)

SQL(结构化查询语言)

RestAPI

CRUD 操作

代码语言:javascript复制
# 查询 movies 的数据
GET movies/_search

# 查询 movies 的数量
GET movies/_count

# 查看所有的索引
GET _cat/indices

# 查询id为24的数据
GET movies/_doc/24
代码语言:javascript复制
# 添加新的文档,如果没有指定id,ES会自动生成id
POST users/_doc
{
  "firstname": "will",
  "lastname": "smith"
}


# 添加id为2的文档,ES不会自动生成id
POST users/_doc/2
{
  "firstname": "will2",
  "lastname": "smith2"
}

# 查询 users 的数据
GET users/_search

# 创建id为2的文档,如果索引中已经存在相同的id,会报错,创建失败;如果不存在相同的id,则创建成功
POST users/_create/2
{
  "firstname": "will2",
  "lastname": "smith2"
}

# 更新id为2的文档,更新指定field
POST users/_update/2
{
  "doc": {
    "firstname": "jack",
    "lastname": "well"
  }
}

# 更新id为2的文档,添加一个field
POST users/_update/2
{
  "doc": {
    "age": 30
  }
}

# 删除id为2的文档
DELETE users/_doc/2

# 删除 users 索引
DELETE users
代码语言:javascript复制
# 创建或修改id为1的文档
PUT users/_doc/1
{
  "firstname": "jack",
  "lastname": "ma"
}

# 创建id为2的文档,如果索引中已经存在相同的id,会报错,创建失败;如果不存在相同的id,则创建成功
PUT users/_create/2
{
  "firstname": "will",
  "lastname": "smith"
}

# 批量查询多个指定index的指定field的值
GET _mget 
{
  "docs" : [
   {"_index": "users", "_id": 1},
   {"_index": "users", "_id": 2}
  ]
}

# 批量插入数据,如果id不存在,则创建;如果id存在,则更新
POST users/_bulk 
{"index" : {"_id" : 3}}
{"firstname": "A", "lastname": "a"}
{"index" : {"_id" : 4}}
{"firstname": "B", "lastname": "b"}
{"index" : {"_id" : 5}}
{"firstname": "C", "lastname": "c"}

URI 查询

代码语言:javascript复制
# 查询title中包含2012的所有电影
GET movies/_search?q=2012

# 查询title中包含2012的所有电影,df(default field)
GET movies/_search?q=2012&df=title

# 查询title中包含2012的所有电影
GET movies/_search?q=title:2012

分页搜索,from表示偏移量,从0开始,size表示每页显示的数量

代码语言:javascript复制
# 查询title中包含2012的所有电影,从第10条开始算起(不包含第10条),查询8条数据
GET movies/_search?q=title:2012&from=10&size=8
代码语言:javascript复制
# 查询title中包含Beautiful或Mind的所有数据
GET movies/_search?q=title:Beautiful Mind
GET movies/_search?q=title:(Beautiful Mind)
GET movies/_search?q=title:( Beautiful  Mind)

# 查询title中包含"Beautiful Mind"这个短语的所有数据
GET movies/_search?q=title:"Beautiful Mind"

# 查询title中既包含Mind,又包含Beautiful的所有数据
GET movies/_search?q=title:(Mind AND Beautiful)

# 查询title中包含Mind,或包含Beautiful的所有数据
GET movies/_search?q=title:(Mind OR Beautiful)

# 查询title中包含Beautiful但不包含Mind的所有数据
GET movies/_search?q=title:(Beautiful NOT Mind)
GET movies/_search?q=title:(Beautiful -Mind)

# 查询title中包含Beautiful且电影上映时间在2012年之后的所有数据
GET movies/_search?q=title:Beautiful AND year:>=2012

# 查询电影上映时间在2018年之后的所有数据
GET movies/_search?q=year:>=2018

# 注意[空格]格式问题
# 查询在2012到2017年的所有数据
GET movies/_search?q=year:(>=2012 AND <2018)

# 查询2016年到2017年上映的电影,开头可以是 { [,但必须以 ] 结尾
GET movies/_search?q=year:{2015 TO 2017]

# ? 代表一个字母
GET movies/_search?q=title:Min?

# 查询title中包含以Min开头的字母的电影
GET movies/_search?q=title:Min*

Analysis

Analysis(只是一个概念),本文分析是将全文本转换为一系列单词的过程,也叫分词。analysis是通过analyzer(分词器)来实现的,可以使用Elasticsearch内置的分词器,也可以自己去定制一些分词器。

除了在数据写入的时候进行分词处理,在查询的时候也可以使用分析器对查询语句进行分词。

analyzer

analyzer是由三部分组成:

  1. Character Filter:将文本中html标签剔除
  2. Tokenizer:按照规则进行分词,在英文中按照空格分词
  3. Token Filter:去掉 stop、world(停顿词,a、an、the、is、are等),然后转换小写

内置分词器

分词器名称

处理过程

Standard Analyzer

默认的分词器,按词切分,小写处理

Simple Analyzer

按照非字母切分(符号、数字被过滤),小写处理

Stop Analyzer

小写处理,停用词过滤(the, a, this)

Whitespace Analyzer

按照空格切分,不转小写

Keyword Analyzer

不分词,直接将输入当做输出

Pattern Analyzer

正则表达式,默认是W (非字符串分隔)

Standard Analyzer

默认的分词器,按词切分,小写处理

代码语言:javascript复制
GET _analyze
{
  "analyzer": "standard",
  "text": ["2 Running quick brown-foxes leap over lazy dog in the summer evening"]
}

Simple Analyzer

按照非字母切分(符号、数字被过滤),小写处理

代码语言:javascript复制
GET _analyze
{
  "analyzer": "simple",
  "text": ["2 Running quick brown-foxes leap over lazy dog in the summer evening"]
}

Stop Analyzer

小写处理,停用词过滤(the, a, this)

代码语言:javascript复制
GET _analyze
{
  "analyzer": "stop",
  "text": ["2 Running quick brown-foxes leap over lazy dog in the summer evening"]
}

Whitespace Analyzer

按照空格切分,不转小写

代码语言:javascript复制
GET _analyze
{
  "analyzer": "whitespace",
  "text": ["2 Running quick brown-foxes leap over lazy dog in the summer evening"]
}

Keyword Analyzer

不分词,直接将输入当做输出

代码语言:javascript复制
GET _analyze
{
  "analyzer": "keyword",
  "text": ["2 Running quick brown-foxes leap over lazy dog in the summer evening"]
}

Pattern Analyzer

正则表达式,默认是W (非字符串分隔)

代码语言:javascript复制
GET _analyze
{
  "analyzer": "pattern",
  "text": ["2 Running quick brown-foxes leap over lazy dog in the summer evening"]
}

Request Body 深入搜索

term 查询

term是表达语义的最小单位,在搜索的时候基本都要使用到term。

term查询的种类:Term Query、Range Query等等。

在ES中,term查询不会对输入的内容进行分词处理,而是作为一个整体,在倒排索引中查找准确的词项,并算分。我们也可以使用 Constant Score 将查询转换为一个 filter,避免算分,利用缓存,提高查询的效率

term 与 terms

term 用于查询单个值,terms用于查询多个值

代码语言:javascript复制
# 查询电影名字中包含有 beautiful 这个单词的所有电影,对于输入的单词不会进行分词的处理。
GET movies/_search
{
  "query": {
    "term": {
      "title": {
        "value": "beautiful"
      }
    }
  }
}
代码语言:javascript复制
# 查询电影名字中包含有 beautiful 或者 mind 的所有电影,对于输入的单词不会进行分词的处理。
GET movies/_search
{
  "query": {
    "terms": {
      "title": [
        "beautiful",
        "mind"
      ]
    }
  }
}

range

搜索排序,使用sort表示,例如按year字段降序排列;

代码语言:javascript复制
# 查询上映时间在2016到2018年的所有电影,根据上映时间进行倒序排序
GET movies/_search
{
  "query": {
    "range": {
      "year": {
        "gte": 2016,
        "lte": 2018
      }
    }
  },
  "sort": [
    {
      "year": {
        "order": "desc"
      }
    }
  ]
}

Constant Score

代码语言:javascript复制
# 查询 title 中包含 beautiful 的所有电影,不进行相关算分,查询数据进行缓存,提高效率
GET movies/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "title": "beautiful"
        }
      }
    }
  }
}

全文查询

全文查询的种类:Match Query、Match Phrase Query、Query String 、Query 等

索引和搜索的时候都会进行分词,在查询的时候,会对输入进行分词,然后每个词项会逐个到底层进行查询,将最终的结果进行合并

match

条件搜索,使用match表示匹配条件,例如搜索出titlebeautiful的文档

代码语言:javascript复制
# 查询电影名字中包含有 beautiful 的所有数据,每页10条,取第二页数据
GET movies/_search
{
  "query": {
    "match": {
      "title": "beautiful"
    }
  },
  "from": 1,
  "size": 10
}

文本类型字段的条件搜索,例如搜索title字段中包含20的文档,对比上一条搜索可以发现,对于数值类型match操作使用的是精确匹配,对于文本类型使用的是模糊匹配

搜索并返回指定字段内容,使用_source表示,例如只返回titleid两个字段内容

代码语言:javascript复制
# 查询电影名字中包含有 beautiful 或者 mind 的所有数据,但只显示 title 和 id 这两个属性
GET movies/_search
{
  "_source": ["title", "id"],
  "query": {
    "match": {
      "title": "beautiful mind"
    }
  }
}

match_phrase

短语匹配搜索,使用match_phrase表示,例如搜索title字段中同时包含beautifulmind的文档

代码语言:javascript复制
# 查询电影名字中包含 beautiful mind 这个短语的所有数据
GET movies/_search
{
  "query": {
    "match_phrase": {
      "title": "beautiful mind"
    }
  }
}

multi_match

代码语言:javascript复制
# 查询 title 或 genre 中包含有 beautiful 或 Adventure 的所有数据
GET movies/_search
{
  "query": {
    "multi_match": {
      "query": "beautiful Adventure",
      "fields": ["title", "genre"]
    }
  }
}

match_all

代码语言:javascript复制
# 查询所有数据
GET movies/_search
{
  "query": {
    "match_all": {}
  }
}

query_string

代码语言:javascript复制
# 查询 title 中包含 beautiful 和 mind 的所有电影
GET movies/_search
{
  "query": {
    "query_string": {
      "default_field": "title",
      "query": "mind AND beautiful"
    }
  }
}


GET movies/_search
{
  "query": {
    "query_string": {
      "default_field": "title",
      "query": "mind beautiful",
      "default_operator": "AND"
    }
  }
}

simple_query_string

simple_query_string覆盖了很多其他查询的用法。

代码语言:javascript复制
# 查询 title 中包含 beautiful 和 mind 的所有电影
GET movies/_search
{
  "query": {
    "simple_query_string": {
      "query": "beautiful   mind",
      "fields": ["title"]
    }
  }
}


GET movies/_search
{
  "query": {
    "simple_query_string": {
      "query": "beautiful mind",
      "fields": ["title"],
      "default_operator": "AND"
    }
  }
}


# 查询 title 中包含 beautiful mind 这个短语的所有电影(用法类似 match_phrase)
GET movies/_search
{
  "query": {
    "simple_query_string": {
      "query": ""beautiful mind"",
      "fields": ["title"]
    }
  }
}


# 查询 title 或 genre 中包含 beautiful 或 mind 的所有电影(用法类似 multi_match)
GET movies/_search
{
  "query": {
    "simple_query_string": {
      "query": "beautiful mind",
      "fields": ["title", "genre"]
    }
  }
}


# 查询 title 中包含 beautiful mind 或者 Modern Romance 这两个短语的所有电影
GET movies/_search
{
  "query": {
    "simple_query_string": {
      "query": ""beautiful mind" | "Modern Romance"",
      "fields": ["title"]
    }
  }
}


# 查询 title 或者 genre 中包含 beautiful 和 mind 这两个词,或者 Comedy 和 Romance 和 Musical 和 Drama 和 Children 这五个词的所有数据
GET movies/_search
{
  "query": {
    "simple_query_string": {
      "query": "(beautiful   mind) | (Comedy   Romance   Musical   Drama   Children)",
      "fields": ["title", "genre"]
    }
  }
}


# 查询 title 中包含 beautiful 和 people,但不包含 Animals 的所有数据
GET movies/_search
{
  "query": {
    "simple_query_string": {
      "query": "beautiful   people   -Animals",
      "fields": ["title"]
    }
  }
}

模糊搜索

代码语言:javascript复制
# 查询 title中从第六个字母开始只要最多纠正一次,就与 neverendign 匹配的所有数据
GET movies/_search
{
  "query": {
    "fuzzy": {
      "title": {
        "value": "neverendign",
        "fuzziness": 1,
        "prefix_length": 5
      }
    }
  }
}

组合查询

组合搜索,使用bool来进行组合,must表示同时满足

条件

说明

must

同时满足

should

满足其中任意一个

must_not

同时不满足

filter

过滤搜索

代码语言:javascript复制
# 查询 title 中包含 beautiful 或 mind 单词,并且上映时间在 2016到2018 年的所有数据
GET movies/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "simple_query_string": {
            "query": "beautiful mind",
            "fields": ["title"]
          }
        },
        {
          "range": {
            "year": {
              "gte": 2016,
              "lte": 2018
            }
          }
        }
      ]
    }
  }
}

搜索过滤,使用filter来表示,例如过滤出year字段在2016-2018的文档

代码语言:javascript复制
# 查询 title 中包含 beautiful 单词,并且上映年份在 2016到2018 年的所有数据,但不会进行相关行算分
GET movies/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "title": "beautiful"
          }
        },
        {
          "range": {
            "year": {
              "gte": 2016,
              "lte": 2018
            }
          }
        }
      ]
    }
  }
}

Mapping

mapping 类似于数据库中的schema,作用如下:

  • 定义索引中的字段类型;
  • 定义字段的数据类型,例如:布尔、字符串、数字、日期
  • 字段倒排索引的设置

数据类型

类型

描述

Text、Keyword

字符串。Keyword的意思是字符串的内容不会被分词处理。Text类型ES会自动的添加一个Keyword类型的子字段。

Date

日期类型

Integer、Float、Long

数字类型

Boolean

布尔类型

Geo_point、Geo_shape

特殊类型

Mapping的定义

语法

代码语言:javascript复制
PUT users
{
  "mappings": {
       // mapping信息
  }
}

定义mapping的建议方式: 写入一个样本文档到临时索引中,ES会自动生成mapping信息,通过访问 mapping信息的api查询mapping的定义,修改自动生成的mapping成为我们需要方式,创建索引,删 除临时索引,简而言之就是 “卸磨杀驴” 。

创建Mapping

代码语言:javascript复制
PUT users
{
  "mappings": {
    "properties": {
      "id": {
        "type": "integer"
      },
      "name": {
        "type": "keyword"
      },
      "job": {
        "type": "keyword"
      },
      "age": {
        "type": "integer"
      },
      "gender": {
        "type": "keyword"
      }
    }
  }
}

填充测试数据

代码语言:javascript复制
PUT users/_bulk
{"index": {"_id": 1}} 
{"id": 1, "name": "Bob", "job": "java", "age": 21, "sal": 8000, "gender": "female"} 
{"index": {"_id": 2}}
{"id": 2, "name": "Rod", "job": "html", "age": 31, "sal": 18000, "gender": "female"} 
{"index": {"_id": 3}} 
{"id": 3, "name": "Gaving", "job": "java", "age": 24, "sal": 12000, "gender": "male"} 
{"index": {"_id": 4}} 
{"id": 4, "name": "King", "job": "dba", "age": 26, "sal": 15000, "gender": "female"} 
{"index": {"_id": 5}} 
{"id": 5, "name": "Jonhson", "job": "dba", "age": 29, "sal": 16000, "gender": "male"} 
{"index": {"_id": 6}} 
{"id": 6, "name": "Douge", "job": "java", "age": 41, "sal": 20000, "gender": "female"} 
{"index": {"_id": 7}} 
{"id": 7, "name": "cutting", "job": "dba", "age": 27, "sal": 7000, "gender": "male"} 
{"index": {"_id": 8}} 
{"id": 8, "name": "Bona", "job": "html", "age": 22, "sal": 14000, "gender": "female"}
{"index": {"_id": 9}} 
{"id": 9, "name": "Shyon", "job": "dba", "age": 20, "sal": 19000, "gender": "female"} 
{"index": {"_id": 10}} 
{"id": 10, "name": "James", "job": "html", "age": 18, "sal": 22000, "gender": "male"}
{"index": {"_id": 11}} 
{"id": 11, "name": "Golsling", "job": "java", "age": 32, "sal": 23000, "gender": "female"} 
{"index": {"_id": 12}} 
{"id": 12, "name": "Lily", "job": "java", "age": 24, "sal": 2000, "gender": "male"} 
{"index": {"_id": 13}} 
{"id": 13, "name": "Jack", "job": "html", "age": 23, "sal": 3000, "gender": "female"} 
{"index": {"_id": 14}} 
{"id": 14, "name": "Rose", "job": "java", "age": 36, "sal": 6000, "gender": "female"} 
{"index": {"_id": 15}} 
{"id": 15, "name": "Will", "job": "dba", "age": 38, "sal": 4500, "gender": "male"} 
{"index": {"_id": 16}} 
{"id": 16, "name": "smith", "job": "java", "age": 32, "sal": 23000, "gender": "male"}

再谈搜索

聚合查询

对搜索结果进行聚合,使用aggs来表示,类似于MySql中的group by

语法

代码语言:javascript复制
GET indexName/_search
{
  "aggs": {
    "aggs_name": {  // 名字自定义
      "AGG_TYPE": {
        // aggregation body
      }
    }
  }
}

单值输出

ES中大多数的数学计算只输出一个值,如:min、max、sum、avg、cardinality

代码语言:javascript复制
# 查询总和工资
GET users/_search
{
  "size": 0, 
  "aggs": {
    "sal_sum": {
      "sum": {
        "field": "sal"
      }
    }
  }
}


# 查询平均工资
GET users/_search
{
  "size": 0,
  "aggs": {
    "avg_sal": {
      "avg": {
        "field": "sal"
      }
    }
  }
}


# 查询总共有多少个岗位,cardinality的值类似于sql中的count distinct,即去重统计总数
GET users/_search
{
  "size": 0,
  "aggs": {
    "count_job": {
      "cardinality": {
        "field": "job"
      }
    }
  }
}

多值输出

ES还有些函数,可以一次性输出很多个统计的数据:terms、stats

代码语言:javascript复制
# 查询工资的信息(数量、最大、最小、平均、总数)
GET users/_search
{
  "size": 0,
  "aggs": {
    "stats_sal": {
      "stats": {
        "field": "sal"
      }
    }
  }
}


# 查询到达不同城市的航班数量
GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "terms_flight_dest": {
      "terms": {
        "field": "DestCountry"
      }
    }
  }
}


# 查询每个岗位有多少人数
GET users/_search
{
  "size": 0,
  "aggs": {
    "terms_job": {
      "terms": {
        "field": "job"
      }
    }
  }
}


# 查询目的地的航班次数以及天气信息
GET kibana_sample_data_flights/_search
{
  "size": 0,
  "aggs": {
    "terms_dest_city": {
      "terms": {
        "field": "DestCityName"
      },
      "aggs": {
        "terms_whether_info": {
          "terms": {
            "field": "DestWeather"
          }
        }
      }
    }
  }
}


# 查询每个岗位下工资的信息(平均、最高、最低)
GET users/_search
{
  "size": 0,
  "aggs": {
    "terms_job_info": {
      "terms": {
        "field": "job"
      },
      "aggs": {
        "stats_sal_info": {
          "stats": {
            "field": "sal"
          }
        }
      }
    }
  }
}


# 查询不同工种的男女数量,然后统计不同工种下男女员工的工资信息
GET users/_search
{
  "size": 0,
  "aggs": {
    "terms_job_info": {
      "terms": {
        "field": "job"
      },
      "aggs": {
        "terms_gender_info": {
          "terms": {
            "field": "gender"
          },
          "aggs": {
            "stats_sal_info": {
              "stats": {
                "field": "sal"
              }
            }
          }
        }
      }
    }
  }
}


# 查询年龄最大的两位员工的信息
GET users/_search
{
  "size": 0,
  "aggs": {
    "top_age_2": {
      "top_hits": {
        "size": 2,
        "sort": [
          {
            "age": {
              "order": "desc"
            }
          }  
        ]
      }
    }
  }
}


# 查询不同区间人员的工资统计信息
GET users/_search
{
  "size": 0,
  "aggs": {
    "range_sal_info": {
      "range": {
        "field": "sal",
        "ranges": [
          {
            "key": "0 <= sal <= 5000", 
            "from": 0,
            "to": 5000
          },
          {
            "key": "5001 <= sal <= 10000",
            "from": 5001,
            "to": 10000
          }
        ]
      }
    }
  }
}


# 以直方图的方式以每5000元为一个区间查看工资信息
## interval:指定的值为一个区间
## extended_bounds:指定区间的范围
GET users/_search
{
  "size": 0,
  "aggs": {
    "histogram_sal_info": {
      "histogram": {
        "field": "sal",
        "interval": 5000,
        "extended_bounds": {
          "min": 0,
          "max": 30000
        }
      }
    }
  }
}


# 查询平均工资中最低工资的工种
GET users/_search
{
  "size": 0,
  "aggs": {
    "job_info": {
      "terms": {
        "field": "job"
      },
      "aggs": {
        "job_avg_sal": {
          "avg": {
            "field": "sal"
          }
        }
      }
    },
    "min_sal_job": {
      "min_bucket": {
        "buckets_path": "job_info>job_avg_sal"
      }
    }
  }
}


# 求工资和工种的信息
GET users/_search
{
  "size": 0,
  "aggs": {
    "job_info": {
      "terms": {
        "field": "job"
      }
    },
    "sal_info": {
      "stats": {
        "field": "sal"
      }
    }
  }
}


# 查询年龄大于30的员工的平均工资
GET users/_search
{
  "size": 0,
  "query": {
    "range": {
      "age": {
        "gte": 30
      }
    }
  },
  "aggs": {
    "avg_sal": {
      "avg": {
        "field": "sal"
      }
    }
  }
}


# 查询Java员工的平均工资
GET users/_search
{
  "size": 0,
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "job": "java"
        }
      },
      "boost": 1.2
    }
  },
  "aggs": {
    "avg_sal": {
      "avg": {
        "field": "sal"
      }
    }
  }
}


# 查询30岁以上的员工的平均工资和所有的工种信息
GET users/_search
{
  "size": 0,
  "aggs": {
    "older_emp": {
      "filter": {
        "range": {
          "age": {
            "gte": 30
          }
        }
      },
      "aggs": {
        "avg_sal": {
          "avg": {
            "field": "sal"
          }
        }
      }
    },
    "job_info": {
      "terms": {
        "field": "job"
      }
    }
  }
}

推荐搜索

在搜索过程中,因为单词的拼写错误,没有得到任何的结果,希望ES能够给我们一个推荐搜索。

代码语言:javascript复制
GET movies/_search
{
  "suggest": {
    # 自定义的名称
    "title_suggestion": {
      "text": "drema",
      "term": {
        "field": "title",
        "suggest_mode": "popular"
      }
    }
  }
}

suggest_mode

说明

popular

推荐词频更高的一些搜索

missing

当没有要搜索的结果的时候才推荐

always

无论什么情况下都进行推荐

自动补全

自动补全应该是我们在日常的开发过程中最常见的搜索方式了。

自动补全的功能对性能的要求极高,用户每发送输入一个字符就要发送一个请求去查找匹配项。ES采取了不同的数据结构来实现,并不是通过倒排索引来实现的;需要将对于的数据类型设置为completion;所以在将数据索引进ES之前需要先定义mapping信息。

需要重新导入数据,先跳过

高亮显示

高亮显示在实际的应用中也会碰到很多。

代码语言:javascript复制
GET movies/_search
{
  "query": {
    "match": {
      "title": "beautiful"
    }
  },
  "highlight": {
    "pre_tags": "<span color='red'>",   # 需要高亮文本的前置 html 内容
    "post_tags": "</span>",             # 需要高亮文本的后置 html 内容
    "fields": {                         # 需要高亮的属性
      "title": {}
    }
  }
}

0 人点赞