es常见用法
2021年9月17日 更新
开启更多功能,提升办公效能

索引settings设置

settings和mapping结构如下:

{
"settings":
{
"index":
{
"number_of_shards":1,
"number_of_replicas":0
}
}
"mapping":
{
"logs": {
"properties": {
"ad_count": {
"type": "long",
"index": false
}
"advertiser_id": {
"type": "long"
}
……
}
}
}


索引settings主要用于配置索引的分片数量、副本数量、refresh间隔等。

常见参数的含义:

  • number_of_shards:设置分片的数量,在集群中通常设置多个分片,表示一个索引库将拆分成多片分别存储不同的节点,提高了ES的处理能力和高可用性,早期版本默认为5,7.x默认为1。
  • number_of_replicas:设置副本的数量,设置副本是为了提高ES的高可靠性,默认为1。
  • refresh_interval:refresh间隔,Refresh Segment到os cache,并且Reopen Segment方式保证搜索可以在较短时间(比如1秒)内被搜索到。此操作有性能消耗,默认1s。


索引mapping简介

mapping映射定义索引中有什么字段、字段的类型等结构信息。相当于数据库中表结构定义。因为lucene索引文档时需要知道该如何来索引存储文档的字段。


type将废弃

ES最先的设计是用索引类比关系型数据库的数据库,用mapping type 来类比表,一个索引中可以包含多个映射类别。这个类比存在一个严重的问题,就是当多个mapping type中存在同名字段时(特别是同名字段还是不同类型的),在一个索引中不好处理,因为搜索引擎中只有 索引-文档的结构,不同映射类别的数据都是一个一个的文档(只是包含的字段不一样而已)

从6.0.0开始限定仅包含一个映射类别定义( “index.mapping.single_type”: true ),兼容5.x中的多映射类别,从7.0开始将移除映射类别。


动态映射

  • Dynamic配置了如何检测新字段并将其添加到映射的详细信息。

该dynamic设置控制是否可以动态添加新字段。它接受三种设置:

  • true:新检测到的字段将添加到映射中。(默认)
  • false:新检测到的字段将被忽略。这些字段将不会被索引,因此将无法搜索,但仍会出现在_source返回的匹配项中。这些字段不会添加到映射中,必须显式添加新字段。
  • strict:如果检测到新字段,则会引发异常并拒绝文档。必须将新字段显式添加到映射中。


Multi-fields多重字段

当我们需要对一个字段进行多种不同方式的索引时,可以使用fields多重字段定义。如一个字符串字段即需要进行text分词索引,也需要进行keyword 关键字索引来支持排序、聚合,或需要用不同的分词器进行分词索引。


数据类型:

  • text / keyword

对字符串类型,在es 2.x版本,用string类型来表示,到了6.x,演化为“text”和“keyword”.其中:

  • text类型

场景:用于索引全文值字段,例如电子邮件正文或产品说明。这些字段是被分词的。分析过程允许Elasticsearch在每个全文字段中搜索单个单词。文本字段不用于排序,很少用于聚合。

  • keyword类型

场景:用于索引结构化内容的字段,例如电子邮件地址,主机名,状态代码,邮政编码或标签。它们通常用于过滤(找到我的所有博客文章,其中 status为published),排序,和聚合。关键字字段只能按其确切值进行搜索。

  • Numeric:Numeric类型中支持8种数据类型,其中:

long:带符号的64位整数,其最小值为,最大值为。 -2^63 ~ 2^63-1

integer:带符号的32位整数,其最小值为,最大值为。 -2^31 ~ 2^31-1

short:带符号的16位整数,其最小值为-32,768,最大值为32,767。

byte:带符号的8位整数,其最小值为-128,最大值为127。

double:双精度64位IEEE 754浮点数,限制为有限值。

float:单精度32位IEEE 754浮点数,限制为有限值。

half_float:半精度16位IEEE 754浮点数,限制为有限值。

scaled_float:由a支持的有限浮点数long,由固定double比例因子缩放。

不支持java.math.bigint类型(即超过2^63-1的上限)

  • Date型

JSON没有日期数据类型,因此Elasticsearch中的日期可以是:

1.包含格式化日期的字符串,例如"2015-01-01"或"2015/01/01 12:10:30"。

2.一个代表毫秒以来的长数字。

3.表示自纪元以来秒数的整数。

在内部,日期转换为UTC(如果指定了时区)并存储为表示自纪元以来毫秒的长数。日期查询在内部转换为此长表示的范围查询,聚合和存储字段的结果将转换回字符串,具体取决于与字段关联的日期格式。

  • Boolean 型

布尔字段接受JSON true和false值,也可以接受被解释为true或false的字符串,


其他类型介绍详见:

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html



搜索API

搜索API端点地址

搜索的端点地址可以是多索引多mapping type的。搜索的参数可作为URI请求参数给出,也可用 request body 给出。


  • URI搜索
GET /twitter/_search?q=user:kimchy
GET /twitter/tweet,user/_search?q=user:kimchy
GET /kimchy,elasticsearch/_search?q=tag:wow
GET /_all/_search?q=tag:wow
GET /_search?q=tag:wow



  • Request Body搜索

Request body 搜索方式以JSON格式在请求体中定义查询 query。请求方式可以是 GET 、POST ,示例:

GET /twitter/_search
{
"query" : {
"term" : { "user" : "kimchy" }
}
}


指定返回字段

  • _source字段过滤源文档中包含哪些字段哪些内容
  • stored_fields指定返回哪些stored的字段
  • docvalue_fields指定返回存储了docValue的字段
  • version指定返回文档的版本字段
  • explain指定返回文档的评分解释(调试比较有用)


过滤查询

  • min_score限制最低评分得分
  • post_filter后置过滤:在查询命中文档、完成聚合后,再对命中的文档进行过滤


sort排序

可以指定按一个或多个字段排序,也可通过_score指定按评分值排序,_doc 按索引顺序排序。默认是按相关性评分从高到低排序。


分页

普通分页

GET /_search
{
"from" : 0, "size" : 10,
"query" : {
"term" : { "user" : "kimchy" }
}
}

注意:搜索请求耗用的堆内存和时间与 from + size 大小成正比。分页越深耗用越大,为了不因分页导致OOM或严重影响性能,ES中规定from + size 不能大于索引setting参数 index.max_result_window 的值,默认值为 10000。


search_after

在指定文档后面取文档,可用于深度分页,即在获取下一页的时候需要传入上次获取的最后一个文档。注意:使用search_after,要求查询必须指定排序,并且这个排序组合值在每个文档唯一(最好排序中包含_id字段,这样可以保证唯一)。 search_after的值用的就是这个排序值。用search_after时 from 只能为0、-1。

首次查询第一页:

GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "elasticsearch"
}
},
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}


后续的查询:

GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "elasticsearch"
}
},
"search_after": [1463538857, "654323"], #传入上次最后一个文档排序的内容
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}


高亮

高亮结果在返回的每个文档中以hightlight节点给出


count API

count查询:获取文档数。


查询模板

很多时候,我们可能会碰到相同的查询情况,这时候就可以定义一个查询模板,然后使用模板进行查询。

注册一个模板:

POST _scripts/<templatename>
{
"script": {
"lang": "mustache",
"source": {
"query": {
"match": {
"title": "{{query_string}}"
}
}
}
}
}


使用模板查询:

GET _search/template
{
"id": "<templateName>", #指定之前注册的模板名称
"params": {
"query_string": "search for these words" #传入查询字符串
}
}


Query DSL

Domain Specific Language:领域特定语言

Elasticsearch基于JSON提供完整的查询DSL来定义查询。

一个查询可由两部分字句构成:

Leaf query clauses 叶子查询字句:Leaf query clauses 在指定的字段上查询指定的值, 如:match, term or range queries. 叶子字句可以单独使用.
Compound query clauses 复合查询字句:以逻辑方式组合多个叶子、复合查询为一个查询

一个查询字句的行为取决于它是用在query context 还是 filter context 中:

Query context 查询上下文:用在查询上下文中的字句回答“这个文档有多匹配这个查询?”。除了决定文档是否匹配,字句匹配的文档还会计算一个字句评分,来评定文档有多匹配,会参与相关性评分。查询上下文由 query 元素表示。
Filter context 过滤上下文:过滤上下文由 filter 元素或 bool 中的 must not 表示。用在过滤上下文中的字句回答“这个文档是否匹配这个查询?”,不参与相关性评分。被频繁使用的过滤器将被ES自动缓存,来提高查询性能。


Match all query

查询所有:match_all、match_none

GET /_search
{
"query": {
"match_all": {}
}
}


全文查询

全文查询,用于对分词的字段进行搜索。会用查询字段的分词器对查询的文本进行分词生成查询。可用于短语查询、模糊查询、前缀查询、临近查询等查询场景。


match query

全文查询的标准查询,它可以对一个字段进行模糊、短语查询。 match queries 接收 text/numerics/dates, 对它们进行分词分析, 再组织成一个boolean查询。可通过operator 指定bool组合操作(or、and 默认是 or ), 以及minimum_should_match 指定至少需多少个should(or)字句需满足。还可用ananlyzer指定查询用的特殊分析器。可以使用minimum_should_match指定最少需要满足几个词匹配。

GET /_search
{
"query": {
"match" : {
"message" : "this is a test" #message是字段名
}
}
}



match phrase query

match_phrase 查询用来对一个字段进行短语查询,可以指定 analyzer、slop移动因子。

GET ftq/_search
{
"query": {
"match_phrase": {
"title": "lucene solr"
}
}
}


match phrase prefix query

match_phrase_prefix 在 match_phrase 的基础上支持对短语的最后一个词进行前缀匹配

查询f开头的:

GET /_search
{
"query": {
"match_phrase_prefix" : {
"message" : "quick brown f"
}
}
}


multi match query

如果你需要在多个字段上进行文本搜索,可用multi_match 。multi_match在 match的基础上支持对多个字段进行文本查询。

GET ftq/_search
{
"query": {
"multi_match" : {
"query": "lucene java",
"fields": [ "title", "content" ]
}
}
}


query string query

query_string 查询,让我们可以直接用lucene查询语法写一个查询串进行查询,ES中接到请求后,通过查询解析器解析查询串生成对应的查询。使用它要求掌握lucene的查询语法。

GET /_search
{
"query": {
"query_string" : {
"default_field" : "content",
"query" : "this AND that OR thus"
}
}
}


simple query string query

simple_query_string 查同 query_string 查询一样用lucene查询语法写查询串,较query_string不同的地方:更小的语法集;查询串有错误,它会忽略错误的部分,不抛出错误。更适合给用户使用。

GET /_search
{
"query": {
"simple_query_string" : {
"query": "\"fried eggs\" +(eggplant | potato) -frittata",
"fields": ["title^5", "body"],
"default_operator": "and"
}
}
}


词项查询

term query

term 查询用于查询指定字段包含某个词项的文档。

POST _search
{
"query": {
"term" : { "user" : "Kimchy" }
}
}


terms query

terms 查询用于查询指定字段包含某些词项的文档。

GET /_search
{
"query": {
"terms" : { "user" : ["kimchy", "elasticsearch"]}
}
}


range query

范围查询

  • gte:大于等于
  • gt:大于
  • lte:小于等于
  • lt:小于
  • boost:查询权重
GET _search
{
"query": {
"range" : {
"age" : {
"gte" : 10,
"lte" : 20,
"boost" : 2.0
}
}
}
}


exits query

查询指定字段值不为空的文档。相当 SQL 中的 column is not null

GET /_search
{
"query": {
"exists" : { "field" : "user" }
}
}


prefix query 词项前缀查询

GET /_search
{ "query": {
"prefix" : { "user" : "ki" }
}
}


wildcard query 通配符查询

GET /_search

{
"query": {
"wildcard" : { "user" : "kiy" }
}
}


regexp query 正则查询

GET /_search
{
"query": {
"regexp":{
"name.first": "s.y"
}
}
}
GET /_search


fuzzy query 模糊查询

GET /_search{
"query": {
"fuzzy" : { "user" : "ki" }
}}


ids 根据文档id查询

GET /_search
{
"query": {
"ids" : {
"type" : "_doc",
"values" : ["1", "4", "100"]
}
}
}


复合查询

constant score query

用来包装另一个查询,将查询匹配的文档的评分设为一个常值。

GET /_search
{
"query": {
"constant_score" : {
"filter" : {
"term" : { "user" : "kimchy"}
},
"boost" : 1.2
}
}
}


bool query

Bool 查询用bool操作来组合多个查询字句为一个查询。 可用的关键字:

must:必须满足
filter:必须满足,但执行的是filter上下文,不参与、不影响评分
should:或
must_not:必须不满足,在filter上下文中执行,不参与、不影响评分


POST _search
{
"query": {
"bool" : {
"must" : {
"term" : { "user" : "kimchy" }
},
"filter": {
"term" : { "tag" : "tech" }
},
"must_not" : {
"range" : {
"age" : { "gte" : 10, "lte" : 20 }
}
},
"should" : [
{ "term" : { "tag" : "wow" } },
{ "term" : { "tag" : "elasticsearch" } }
],
"minimum_should_match" : 1,
"boost" : 1.0
}
}
}


聚合分析

聚合分析是数据库中重要的功能特性,完成对一个查询的数据集中数据的聚合计算,如:找出某字段(或计算表达式的结果)的最大值、最小值,计算和、平均值等。ES作为搜索引擎兼数据库,同样提供了强大的聚合分析能力。


指标聚合metric:是对一个数据集求最大、最小、和、平均值等指标的聚合
桶聚合bucketing:关系型数据库中除了有聚合函数外,还可以对查询出的数据进行分组group by,再在组上进行指标聚合,在 ES 中group by 称为分桶
ES中还提供了矩阵聚合(matrix)、管道聚合(pipleline)。


指标聚合

max min sum avg

查询所有客户中余额最大值(size=0表示不返回其他字段):

POST /bank/_search?
{
"size": 0,
"aggs": {
"masssbalance": {
"max": {
"field": "balance"
}
}
}
}


文档计数

文档计数count:

POST /bank/_doc/_count
{
"query": {
"match": {
"age" : 24
}
}
}


cardinality值去重计数:

POST /bank/_search?size=0
{
"aggs": {
"age_count": {
"cardinality": {
"field": "age"
}
},
"state_count": {
"cardinality": {
"field": "state.keyword"
}
}
}
}



占比百分位对应的值统计

对指定字段(脚本)的值按从小到大累计每个值对应的文档数的占比(占所有命中文档数的百分比),返回指定占比比例对应的值。默认返回[ 1, 5, 25, 50, 75, 95, 99 ]分位上的值。如下中间的结果,可以理解为:占比为50%的文档的age值 <= 31,或反过来:age<=31的文档数占总命中文档数的50%

POST /bank/_search?size=0
{
"aggs": {
"age_percents": {
"percentiles": {
"field": "age"
}
}
}
}


桶聚合

Terms Aggregation 根据字段值项分组聚合

POST /bank/_search?size=0
{
"aggs": {
"age_terms": {
"terms": {
"field": "age" #根据age值项进行分组聚合
}
}
}
}


Range Aggregation 范围分组聚合

POST /bank/_search?size=0
{
"aggs": {
"age_range": {
"range": {
"field": "age",
"ranges": [
{"to":25},
{"from": 25,"to": 35},
{"from": 35}
]
},
"aggs": {
"bmax": {
"max": {
"field": "balance"
}
}
}
}
}
}


Date Range Aggregation 时间范围分组聚合

POST /sales/_search?size=0
{
"aggs": {
"range": {
"date_range": {
"field": "date",
"format": "MM-yyy",
"ranges": [
{ "to": "now-10M/M" },
{ "from": "now-10M/M" }
]
}
}
}
}


Date Histogram Aggregation 时间直方图(柱状)聚合

就是按天、月、年等进行聚合统计。可按 year (1y), quarter (1q), month (1M), week (1w), day (1d), hour (1h), minute (1m), second (1s) 间隔聚合或指定的时间间隔聚合。

POST /sales/_search?size=0
{
"aggs" : {
"sales_over_time" : {
"date_histogram" : {
"field" : "date",
"interval" : "month"
}
}
}
}



9、FAQ

Q1: 单个分片数据量在多少是合理的?

A1: 单个shard大小20~50G是合理范围。


Q2: refresh_interval,refresh间隔怎么设置?

A2: 此操作有性能消耗,默认1s。若要求快速搜索可见,可适当调小;若对可见性时间要求不高,同时期望更高的写入性能,可以将改参数调大。如果特殊要求,保持默认即可。


Q3: text、keyword各自使用的场景?

A3: text类型场景:用于索引全文值字段,例如电子邮件正文或产品说明。这些字段是被分词的。分析过程允许Elasticsearch在每个全文字段中搜索单个单词。文本字段不用于排序,很少用于聚合。

keyword类型场景:用于索引结构化内容的字段,例如电子邮件地址,主机名,状态代码,邮政编码或标签。它们通常用于过滤(找到我的所有博客文章,其中 status为published),排序,和聚合。关键字字段只能按其确切值进行搜索。


Q4: Multi-fields多重字段使用场景?

A4: 当我们需要对一个字段进行多种不同方式的索引时,可以使用fields多重字段定义。如一个字符串字段即需要进行text分词索引,也需要进行keyword 关键字索引来支持排序、聚合,或需要用不同的分词器进行分词索引。

参考:

文档内容大都整理自如下文章,详细请参考:

https://blog.csdn.net/it_dx/article/details/81586283

https://blog.csdn.net/zzh920625/article/details/86666163

https://blog.csdn.net/supermao1013/article/details/84192965

https://blog.csdn.net/supermao1013/article/details/84261526

https://blog.csdn.net/supermao1013/article/details/84311208