ElasticSearch查询怎么使用

这篇文章主要讲解了“ElasticSearch查询怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“ElasticSearch查询怎么使用”吧!

搜索api

有两种方法执行搜索:第一种是通过REST request Uri 发送搜索参数,第二种是通过REST request body。第二种方法允许你用json格式定义更丰富的查询参数。我们将会用第一种方法做一个例子,但之后都会专一地使用第二种方法做实验。

_search 返回 bank索引的所有文档

GET /bank/_search?q=*&sort=account_number:asc

q=* :查询所有

返回结果如下:

{
  "took" : 82,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : null,
    "hits" : [ {
      "_index" : "bank",
      "_type" : "account",
      "_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"}
    }, {
      "_index" : "bank",
      "_type" : "account",
      "_id" : "1",
      "sort": [1],
      "_score" : null,
      "_source" : {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"}
    }, ...
    ]
  }
}
  • took-elasticsearch执行搜索花费的毫秒数

  • timed_out-告诉我们这次搜索是否超时

  • _shards- 告诉我们搜索了多少个分片,以及搜索成功和失败的分片数

  • hits-搜索返回的文档结果

  • hits.total 一共命中了多少结果

  • sort-搜索排序规则,如果没有该字段,则按相关度排序

  • _score和max_score 暂时先忽略这个参数(文档得分,反映相关度)

下面用request body方法执行和上面一样的搜索操作:

GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ]
}

query 字段说明查询内容

match_all是执行查询操作的匹配类型 , match_all是匹配所有文档的意思。

不同点是我们用json格式的请求体代替了_search api uri中的q=*参数。

必须要知道的是:当我们接收到返回结果的时候,elasticsearch已经完全处理了这个请求,不会维护任何的服务器资源或游标到你的返回结果中。这与类似sql这样的平台形成鲜明的对比,sql允许你先取前面的一部分数据,然后连续不断的通过服务器端的游标再去取剩下的数据。

基本语法

除了query参数,我们也可以传递其他参数去影响查询结果。在上一章节的例子我们传递了一个sort参数,这里我们传递一个size

GET /bank/_search
{
  "query": { "match_all": {} },
  "size": 1
}

注意,如果size没有指定,默认值是10.

下面这个例子匹配所有文档,并返回第11-20的文档:

GET /bank/_search
{
  "query": { "match_all": {} },
  "from": 10,
  "size": 10
}

from参数指定从第几个文档开始返回,size参数指定一共返回多少个文档。这个特性是对分页功能是十分重要的。如果from没有指定,默认值是0。

下面的例子按账户余额倒序查询前10个结果(默认size大小):

GET /bank/_search
{
  "query": { "match_all": {} },
  "sort": { "balance": { "order": "desc" } }
}

match查询

现在我已经看见过一些基础的查询参数,让我们挖掘更多关于query DSL 的信息。首先看看返回文档的字段。默认所有的字段都会被返回。文档原始内容被称为源(对应hits中的_source 键)。如果我们不想返回文档的所有字段,也可以仅仅要求接口返回部分字段。

下面的例子展示如何返回 account_number 和balance(在_source里面)这个两个字段:

GET /bank/_search
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}

注意上述操作只是减少了返回的字段,但是_source字段还是存在的,只是仅返回account_numberbalance字段

如果你曾经学过sql,上述概念就和sql select filed list from 差不多。

现在,让我们继续学习查询语法。之前,我们已经看到过match_all查询类型使用来匹配所有文档的。现在,我们介绍一种新的查询类型match,他是基于字段搜索的(即,通过匹配一个特定的字段或一组字段执行搜索)

下面的例子返回账号number是20的文档:

GET /bank/_search
{
  "query": { "match": { "account_number": 20 } }
}

下面的例子返回所有地址字段包含mill的账户文档

GET /bank/_search
{
  "query": { "match": { "address": "mill" } }
}

下面的例子返回地址字段包含“mill”或者“lane”的账户

GET /bank/_search
{
  "query": { "match": { "address": "mill lane" } }
}

match_phrase查询(短语匹配)

下面的例子是match的变种(match_phrase),它返回所有地址字段包含词组“mill lane”的账户

GET /bank/_search
{
  "query": { "match_phrase": { "address": "mill lane" } }
}

bool查询

现在,让我介绍一下布尔查询。bool查询允许我们把多个match查询合并到一个查询中。

下面的例子合并了两个match查询并返回所有地址字段同时包含“mill”和“lane”的账户

GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

上述例子的bool must子句指定:当所有的查询都返回true的时候,才认为匹配文档。

与此相反,下面这个这个例子合并两个match查询,并返回所有地址地段包含“mill”或“lane”的账户

GET /bank/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

上述例子,bool should 子句只要文档满足其中一个查询,就认为匹配。

下面的例子合并了两个match查询,并返回所有地址字段既不包含“mill”也不包含“lane”的账户:

GET /bank/_search
{
  "query": {
    "bool": {
      "must_not": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

上面的例子中,bool must_not子句指定当所有查询都不满足的时候,就认为匹配文档。

我们也可以把mustshouldmust_not同时组合到bool子句。此外,我们也可以组合bool 到任何一个bool子句中,实现复杂的多层bool子句嵌套逻辑。

下面的例子返回所有年龄是40岁但不是住在ID州的账户:

GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
}

filter查询

在之前的章节,我们跳过了一个小细节:文档得分(搜索结果的_score字段).文档得分是一个数字值,它代表关键字和文档内容的相关度估值。 文档得分越高说明相关度越高,文档得分越少,说明相关度越少。

但查询不一定都需要产生文档得分,特别在过滤文档集合的时候。为了避免不必要的文档得分计算,Elasticsearch会检查这种情况并自动的优化这种查询。

在前面章节介绍的bool查询也支持filter子句,它允许你使用一个查询语句去过滤其它子句的匹配结果,同时不会改变文档的得分。我们介绍一下range查询,并把它作为例子,它允许我们通过一个范围值去过滤文档。通常用于数字或日期过滤。

这个例子使用bool查询返回所有账户余额在20000-30000之间的文档。换句话说,我们需要查找余额大于20000小于30000的账户:

GET /bank/_search
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}

仔细分析上面的例子,bool查询包含了一个match_all查询(查询部分)和一个range查询(过滤部分)。我们也可以用任何其它的查询语句代替查询和过滤部分的语句。对于上面的例子,因为所有文档都是指定范围之内的,他们从某种意义上来说是等价的(equally),即他们的相关度都是一样的(filter子句查询,不会改变得分)。

除了 match_all,match,bool,range查询,还有很多种类的查询,但我们不在这里一一介绍。从现在开始,我们对查询已经有一个基础的了解,把学到的知识应用到其他查询类型应该也没什么难度。

term查询

GET /bank/_search
{
  "query": {
    "term": {
      "address": "789 Madison"
    }
  }
}

match精确匹配

GET /bank/_search
{
  "query": {
    "match": {
      "address.keyword": "789 Madison"
    }
  }
}

term,match,match_phase,query_string,keyword精确匹配的区别

1. match

match:模糊匹配,需要指定字段名,但是输入会进行分词,比如"hello world"会进行拆分为hello和world,然后匹配,如果字段中包含hello或者world,或者都包含的结果都会被查询出来,也就是说match是一个部分匹配的模糊查询。查询条件相对来说比较宽松。

2. term

term: 这种查询和match在有些时候是等价的,比如我们查询单个的词hello,那么会和match查询结果一样,但是如果查询"hello world",结果就相差很大,因为这个输入不会进行分词,就是说查询的时候,是查询字段分词结果中是否有"hello world"的字样,而不是查询字段中包含"hello world"的字样,elasticsearch会对字段内容进行分词,"hello world"会被分成hello和world,不存在"hello world",因此这里的查询结果会为空。这也是term查询和match的区别。

3. match_phase

match_phase:会对输入做分词,但是需要结果中也包含所有的分词,而且顺序要求一样。以"hello world"为例,要求结果中必须包含hello和world,而且还要求他们是连着的,顺序也是固定的,hello that word不满足,world hello也不满足条件。

4. query_string

query_string:和match类似,但是match需要指定字段名,query_string是在所有字段中搜索,范围更广泛。

5. keyword精确匹配

不同于term,keyword精确匹配要求查询的字段必须等于

一般我们全文检索字段用match,其他非text字段匹配用term

执行聚合(Executing Aggregations)

聚合功能能够分组并统计你的数据。最简单的说法就是等价于sql group by 语句和sql的聚合函数。使用elasticsearch,你可以同时在一个请求中返回需要查询的数据以及这些数据的多种聚合运算结果。在单个请求中就可以同时查询数据和进行多次聚合运算是非常有意义的,他可以降低网络请求的次数。

下面的例子把state字段的内容分组,并按照每一组的文档数量倒序排序,返回数量最多的前10(默认值)组数据:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      }
    }
  }
}

上面的聚合运算等价于执行下面的sql:

SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC

返回结果(仅展示一部分):

{
  "took": 29,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "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州有27个账户,随后的TX州有27个账户,AL州有25个账户。

注意我们设置size=0是因为我不需要查询文档,只需要查询聚合结果。

基于上述例子,下面的例子除了分组还会计算每个州的账户的平均余额:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

注意我们是如何把average_balance聚合嵌入到group_by_state聚合中。这种模式适合于所有的聚合。你可以按你的需求重复嵌套聚合子句,汇总你的数据。

基于上面的例子,我们加入了按每个州的账户平均余额倒序排序的限制(说明了上一层聚合可以使用下一层聚合的运算结果):

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword",
        "order": {
          "average_balance": "desc"
        }
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

下面例子讲述了我们如何按年龄组分组(20-29,30-39,40-49),然后按性别分组,最后获取每个组中每个性别的账户平均余额。(例如:年龄段在20-29的女性用户的账户平均余额)

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

最后一个例子,查出所有年龄分布,并且这些年龄段中性别M的平均薪资和F的平均薪资以及这个年龄段的总体平均薪资

GET /bank/_search
{
  "size": 0, 
  "aggs":{
    "aggAgg": {
      "terms": {
        "field": "age"
      },
      "aggs": {
        "ageBalanceAvg":{
          "avg": {
            "field": "balance"
          }
        },
        "genderAgg":{
          "terms":{
            "field": "gender.keyword"
          },
          "aggs": {
            "avgAvg":{
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
  }
}

感谢各位的阅读,以上就是“ElasticSearch查询怎么使用”的内容了,经过本文的学习后,相信大家对ElasticSearch查询怎么使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

原创文章,作者:306829225,如若转载,请注明出处:https://blog.ytso.com/225658.html

(0)
上一篇 2022年1月8日
下一篇 2022年1月8日

相关推荐

发表回复

登录后才能评论