ES入门:查询和聚合
—theme: theme-blue —
安装完ElasticSearch 和 Kibana后我们开始学习
为了方便测试,使用kibana的dev tool来进行学习测试:
测试工具
从索引文档开始
插入
向 Elasticsearch 索引 customer 的 _doc 类型的文档 id 为 1 的文档发送 PUT 请求的例子。
请求体为 JSON 格式,包含一个字段 name 和其值 DLBoy。
Elasticsearch 支持多种请求方法来对索引进行操作,其中包括 GET、POST、PUT、DELETE 等等。
在这个例子中,我们使用的 PUT 方法将更新或创建一个新的文档:
PUT /customer/_doc/1
{
"name": "DLBoy"
}
/customer/_doc/1
,其中customer
是索引的名称,\_doc
通常是文档类型(在Elasticsearch 7.x及更高版本中,文档类型通常被忽略),而1
是文档的唯一标识ID。
使用 PUT 方法提交文档时,如果指定的 id 已经存在,则该文档将被更新;如果不存在则该文档将被创建。在 POST 方法中,不需要提供 id 参数, Elasticsearch 会生成一个唯一的 id 。
查询
批量索引文档
下载测试数据
- 下载 accounts.json (如果无法下载,也可以clone ES的官方仓库在新窗口打开,选择本文中使用的版本分支,然后进入/docs/src/test/resources/accounts.json目录获取)
数据的格式如下:
批量插入数据
- 将accounts.json拷贝至指定目录,我这里放在
/opt/
下面
执行
curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_bulk?pretty&refresh" --data-binary "@/opt/accounts.json"
解释
curl
: 这是一个命令行工具,用于发起HTTP请求。-H "Content-Type: application/json"
: 这是HTTP请求头,指定请求的内容类型为JSON。-XPOST
: 这指示curl执行HTTP POST请求。"localhost:9200/bank/_bulk?pretty&refresh"
: 这是目标Elasticsearch服务器的URL,它指定了索引名称"bank",并在URL中使用"_bulk"来指示批量导入操作。pretty
参数是可选的,用于格式化响应以使其更易阅读,refresh
参数用于在导入完成后刷新索引,以使新数据立即可用。--data-binary "@/opt/accounts.json"
: 这是HTTP请求的数据部分,它指定了要导入的数据文件的路径,这里是"/opt/accounts.json"。@
符号表示要上传文件的路径。这个文件包含了要批量导入的JSON数据。
查看状态
curl "localhost:9200/_cat/indices?v=true" | grep bank
查询数据
查询所有
match_all
表示查询所有的数据,sort
即按照什么字段排序
GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
]
}
解释
这是一个Elasticsearch批量导入数据的响应示例。响应包含了以下信息:
"took" : 1
: 表示处理请求所花费的时间,以毫秒为单位。"timed_out" : false
: 表示请求没有超时。"_shards"
: 提供了与索引分片相关的信息,包括总分片数、成功的分片数、跳过的分片数和失败的分片数。"total"
: 表示索引总共包含了1个分片。在分布式环境下,索引通常被分成多个分片以提高性能和可伸缩性。这里的值为1,表示索引可能是单一分片的。"successful"
: 表示成功完成的分片数。在这里,所有的分片操作都成功,所以值为1。"skipped"
: 表示跳过的分片数。在这个响应中,没有分片被跳过,所以值为0。"failed"
: 表示失败的分片数。在这个响应中,没有分片失败,所以值为0。"hits"
: 这是一个包含有关查询匹配文档的信息的部分。"total"
: 提供了匹配查询条件的总文档数,这里是1000个文档。这是符合查询条件的文档总数。"relation"
: 表示与总文档数的关系,这里是"eq",表示匹配文档的数量等于总文档数。其他可能的关系包括"gte"(大于或等于)、“lte”(小于或等于)等,根据查询条件的具体情况而定。"hits"
: 这是一个文档数组,包含了查询匹配的文档。每个文档都包括了以下信息:- “_index”: 文档所属的索引名称,这里是"bank"。
- “_type”: 文档的类型,通常在Elasticsearch 7.x及更高版本中使用"_doc"。
- “_id”: 文档的唯一标识ID。
- “_score” - 文档的相关性得分(使用match_all时不适用)
- “_source”: 包含文档的实际数据。在这个示例中,包含了账户信息,如账号号码、余额、姓名、年龄、性别、地址等。
- “sort” - 文档的排序位置(不按相关性得分排序时)
这个响应示例表明批量导入操作成功,共导入了1000个文档,并提供了匹配的文档详细信息。这些信息可用于后续的搜索和分析操作。
分页查询
from和size两个字段
GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
],
"from": 10,
"size": 10
}
指定字段查询
如果要在字段中搜索特定字词,可以使用match
查询address 字段中包含 mill 或者 lane的数据;
GET /bank/_search
{
"query": {
"match": {
"address": "Holmes Lane"
}
}
}
"query"
: 查询请求的主体,指示Elasticsearch执行查询操作。"match"
: 查询类型,表示执行一个文本匹配查询。"address"
: 要匹配的字段名称,这里是"address"字段。"Holmes Lane"
: 要匹配的文本内容,这里是"Holmes Lane"。查询将在"address"字段中查找包含"Holmes Lane"的文本。
由于ES底层是按照分词索引的,所以上述查询结果是address 字段中包含 Holmes 或者 Lane 的数据
查询段落匹配
查询的条件是 address字段中包含 “Holmes Lane”,则可以使用match_phrase
GET /bank/_search
{
"query": {
"match_phrase": {
"address": "Holmes Lane"
}
}
}
"query"
: 查询请求的主体,指示Elasticsearch执行查询操作。"match_phrase"
: 查询类型,表示执行一个短语匹配查询。"address"
: 要匹配的字段名称,这里是"address"字段。"Holmes Lane"
: 要匹配的短语,这里是"Holmes Lane"。查询将在"address"字段中查找包含完整短语"Holmes Lane"的文本。
多条件查询:
如果要构造更复杂的查询,可以使用bool
查询来组合多个查询条件。
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": "40" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}
"query"
: 查询请求的主体,指示Elasticsearch执行查询操作。"bool"
: 查询类型,表示执行一个布尔查询,它可以包含多个条件。"must"
: 这是一个数组,包含了必须匹配的条件。在这里,我们要求文档的"age"字段必须匹配值"40"。"must_not"
: 这也是一个数组,包含了不能匹配的条件。在这里,我们要求文档的"state"字段不能匹配值"ID"。
Query or Filter
must,should,must_not
和 filter
都是bool
查询的子句。
那么filter
和query
子句有啥区别呢?
查询条件
在bool
查询的子句中同时具备query,must 和 filter
GET /bank/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"state": "ND"
}
}
],
"filter": [
{
"term": {
"age": "40"
}
},
{
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
]
}
}
}
Elasticsearch查询的示例,使用HTTP GET请求来搜索名为"bank"的索引中的文档。这个查询是一个复杂的布尔查询,包含了多个子查询条件,同时指定了必须匹配的条件和过滤条件。以下是这个查询的各个部分的解释:
- HTTP方法:
GET
,表示发起一个查询请求。 - 路径:
/bank/_search
,这是指定要搜索的索引名称为"bank",并且执行搜索操作。 - 请求正文:这是一个包含查询条件的JSON请求体,用于定义查询的细节。在这个示例中,查询条件如下:
"query"
: 查询请求的主体,指示Elasticsearch执行查询操作。"bool"
: 查询类型,表示执行一个布尔查询,它可以包含多个条件。"must"
: 这是一个数组,包含了必须匹配的条件。在这里,我们要求文档的"state"字段必须匹配值"ND",即北达科他州。"filter"
: 这是一个数组,包含了过滤条件,这些条件用于排除文档。在这里,有两个过滤条件:"term"
: 这是一个精确匹配查询条件,要求文档的"age"字段必须精确匹配值"40"。"range"
: 这是一个范围查询条件,要求文档的"balance"字段的值必须在20000到30000之间(包括20000和30000)。
所以,这个查询的目的是从"bank"索引中查找文档,这些文档同时满足以下条件:位于北达科他州(“state"字段匹配"ND”),年龄为40,账户余额在20000到30000之间。
只包含filter的查询:
GET /bank/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"age": "40"
}
},
{
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
]
}
}
}
在Elasticsearch中,query
和filter
都用于定义搜索条件,但它们之间有重要的区别,主要涉及到搜索的目的和结果处理方式。以下是它们的主要区别:
- 目的:
- Query(查询):主要用于筛选和排序文档以匹配搜索查询,以便找到相关性最高的文档。查询条件会计算文档的相关性得分,然后对文档进行排序,以使最相关的文档排在前面。
- Filter(过滤):主要用于筛选文档,不涉及相关性得分或排序。过滤条件用于精确匹配文档,通常用于排除不符合条件的文档。
- 计算开销:
- Query(查询):查询条件可能需要较大的计算开销,因为它们计算文档的相关性得分并进行排序。这在某些情况下可能会导致查询变得较慢。
- Filter(过滤):过滤条件通常具有较小的计算开销,因为它们不涉及相关性得分或排序。这使得过滤条件在性能上更高效。
- 结果处理方式:
- Query(查询):查询结果会包括文档的相关性得分,文档按照相关性排序。查询条件用于找到最相关的文档,通常用于全文搜索等情况。
- Filter(过滤):过滤条件返回文档的精确匹配结果,结果不包括相关性得分。过滤条件用于精确筛选文档,通常用于精确匹配、范围查询、布尔条件等情况。
总之,query
主要用于搜索和排序文档,通常在需要考虑相关性的情况下使用,如全文搜索。而filter
主要用于筛选文档,通常在需要精确匹配和排除的情况下使用,如范围查询、精确匹配、布尔条件等。根据搜索需求,可以选择使用query
、filter
或它们的组合,以达到所需的搜索目标。
聚合查询
我们知道SQL中有group by,在ES中它叫Aggregation,即聚合运算。
简单聚合
比如我们希望计算出account.json的数据中每个州的统计数量, 使用aggs
关键字对state
字段聚合,被聚合的字段无需对分词统计,所以使用state.keyword
对整个字段统计
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
}
}
}
}
- “size”: 这指定了搜索结果的大小,这里是0,表示不返回实际文档结果,只返回聚合结果。
- “aggs”: 这是用于定义聚合的部分。
- “group_by_state”: 这是聚合的名称,可以自定义。
- “terms”: 这是一种聚合类型,表示按照指定字段的值进行分组。在这里,我们希望按照"state.keyword"字段的值进行分组。
- “field”: 这是要用于分组的字段,这里是"state.keyword",表示按照州的关键字值进行分组。
所以,这个查询的目的是执行一个名为"group_by_state"的聚合,根据文档中的"state.keyword"字段的值进行分组。它将生成一个分组列表,其中包含每个不同州的值,并统计每个州的文档数量。由于"size"设置为0,不会返回实际文档结果,只返回聚合结果,以供进一步分析或显示聚合数据。这种聚合操作对于分析文档集的统计信息非常有用。
Elasticsearch聚合操作的响应结果,具体包括了"aggregations"部分解释:
- “aggregations”: 这是包含聚合结果的部分。
- “group_by_state”: 这是聚合的名称,与查询中定义的聚合名称一致。
- “doc_count_error_upper_bound”: 这是文档计数错误的上限,通常为0。它表示文档计数的错误限制,如果值大于0,表示可能存在计数错误。
- “sum_other_doc_count”: 这是其他文档计数的总和,743表示总共有743个文档分配到了除分桶之外的"其他"类别中。
- “buckets”: 这是分桶(buckets)的数组,包含了每个分组的信息。
- 每个"bucket"包括以下信息:
- “key”: 分组的键,即"state.keyword"字段的值。
- “doc_count”: 分组中的文档计数,表示每个州拥有的文档数量。
在这个示例中,"group_by_state"聚合对"state.keyword"字段进行了分组,并列出了每个州的文档数量。例如,“TX”(得克萨斯州)有30个文档,“MD”(马里兰州)有28个文档,以此类推。这种聚合操作有助于了解文档集中各个分组的统计信息,通常用于数据分析和可视化。
嵌套聚合
ES处理聚合条件的嵌套。
计算每个州的平均结余。涉及到的就是在对state分组的基础上,嵌套计算avg(balance):
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
- “size”: 这指定了搜索结果的大小,这里是0,表示不返回实际文档结果,只返回聚合结果。
- “aggs”: 这是用于定义聚合的部分。
- “group_by_state”: 这是聚合的名称,用于按州进行分组。
- “terms”: 这是一种聚合类型,表示按照指定字段的值进行分组,这里是"state.keyword"字段的值。
- “aggs”: 这是在每个州分组内执行的嵌套聚合。
- “average_balance”: 这是嵌套聚合的名称,用于计算每个州的平均账户余额。
- “avg”: 这是嵌套聚合的类型,表示计算平均值。
- “field”: 这是用于计算平均值的字段,这里是"balance"字段,表示计算每个州的账户余额的平均值。
所以,这个查询的目的是执行一个名为"group_by_state"的聚合,根据文档中的"state.keyword"字段的值进行分组。在每个分组内,还执行了一个名为"average_balance"的嵌套聚合,计算每个州的平均账户余额。由于"size"设置为0,不会返回实际文档结果,只返回聚合结果,以供进一步分析或显示聚合数据。这种聚合操作对于分析文档集的统计信息非常有用,包括平均值、总和、最小值、最大值等。
这是执行Elasticsearch聚合操作后的响应结果,具体包括了"aggregations"部分的解释:
- “aggregations”: 这是包含聚合结果的部分。
- “group_by_state”: 这是聚合的名称,与查询中定义的聚合名称一致。
- “doc_count_error_upper_bound”: 这是文档计数错误的上限,通常为0。它表示文档计数的错误限制,如果值大于0,表示可能存在计数错误。
- “sum_other_doc_count”: 这是其他文档计数的总和,743表示总共有743个文档分配到了除分桶之外的"其他"类别中。
- “buckets”: 这是分桶(buckets)的数组,包含了每个分组的信息。
- 每个"bucket"包括以下信息:
- “key”: 分组的键,即"state.keyword"字段的值,表示各个州的名称。
- “doc_count”: 分组中的文档计数,表示每个州的文档数量。
- “average_balance”: 这是嵌套聚合计算的平均账户余额的结果。每个分组都包括一个"average_balance"字段,其中包含了平均值。
在这个示例中,"group_by_state"聚合对"state.keyword"字段进行了分组,列出了每个州的文档数量,并计算了每个州的平均账户余额。例如,“TX”(得克萨斯州)有30个文档,平均账户余额为26073.3,“MD”(马里兰州)有28个文档,平均账户余额为26161.535714285714,以此类推。这种聚合操作非常有助于对文档集进行统计和分析,以获得有关每个分组的信息。
聚合结果排序
通过在aggs中对嵌套聚合的结果进行排序
对嵌套计算出的avg(balance),这里是average_balance,进行排序
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword",
"order": {
"average_balance": "desc"
}
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
- “size”: 这指定了搜索结果的大小,这里是0,表示不返回实际文档结果,只返回聚合结果。
- “aggs”: 这是用于定义聚合的部分。
- “group_by_state”: 这是聚合的名称,用于按州进行分组。
- “terms”: 这是一种聚合类型,表示按照指定字段的值进行分组,这里是"state.keyword"字段的值。
- “order”: 这是一个选项,用于指定排序方式,这里按照嵌套聚合"average_balance"的降序排列。
- “aggs”: 这是在每个州分组内执行的嵌套聚合。
- “average_balance”: 这是嵌套聚合的名称,用于计算每个州的平均账户余额。
- “avg”: 这是嵌套聚合的类型,表示计算平均值。
- “field”: 这是用于计算平均值的字段,这里是"balance"字段,表示计算每个州的账户余额的平均值。
这个查询的目的是执行一个名为"group_by_state"的聚合,根据文档中的"state.keyword"字段的值进行分组,同时计算每个州的平均账户余额,并按照平均余额的降序排列结果。由于"size"
设置为0,不会返回实际文档结果,只返回聚合结果,以供进一步分析或显示聚合数据。这种聚合操作有助于找到平均账户余额最高的州。
- 点赞
- 收藏
- 关注作者
评论(0)