Elasticsearch - 聚合获取原始数据并分页&排序&模糊查询

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Elasticsearch - 聚合获取原始数据并分页&排序&模糊查询

20190806092132811.jpg

概述

ES版本: 7.6.


13b9cb98e1c6401db8d12f86e8617e6c.png


需要按照主机ID 进行告警时间的汇总,并且还得把主机相关的信息展示出来。

注: 所有的数据都存在索引中, 通过一个DSL查询展示

实际上就是将terms聚合的结果以列表形式分页展示。


第一步 : 聚合获取原始数据并分页

GET index_name/_search
{
  "size": 0,
  "query": {
    "match_all": {}
  },
  "aggs": {
    "getAlarmStatistByHostId": {
      "terms": {
        "field": "host_id",
        "size": 100000,
        "order": {
          "_count": "desc"
        }
      },
      "aggs": {
        "host_details": {
          "top_hits": {
            "size": 1,
            "_source": {
              "include": [
                "host_nameame",
                "host_ip",
                "host_mac"
              ]
            }
          }
        },
        "myBucketSort": {
          "bucket_sort": {
            "from": 0,
            "size": 2,
            "gap_policy": "SKIP"
          }
        }
      }
    },
    "termsCount": {
      "cardinality": {
        "field": "host_id",
        "precision_threshold": 40000
      }
    }
  }
}


知识点:bucket_sort实现分页

  • bucket_sort中 from不是pageNum,如想实现pageNum效果,from=pageNum*size即可;
  • terms聚合的size,实际上size可以尽可能的设置大一点,具体大小按实际情况来看;
"myBucketSort": {
          "bucket_sort": {
            "from": 0,
            "size": 2,
            "gap_policy": "SKIP"
          }
        }


在 bucket_sort 中,可以指定以下其他参数:


from: 从哪个桶开始排序,默认是0,表示从第一个桶开始

size: 每个桶有多少个桶,默认是2,表示每个桶有2个桶 (其实就是每页展示多少条数据)

gap_policy: 桶之间的策略,可选值有:

SKIP: 跳过空桶,默认值

INTERPOLATE: 使用非空桶的最小和最大值来填充空桶

FAIL: 如果遇到空桶,直接失败


所以上述的配置的意思是

  • 从第一个桶开始排序
  • 每个桶有2个子桶
  • 遇到空桶时跳过空桶
    这可以让我们更加精细地控制桶的划分和处理。


知识点:获取 total -----> cardinality 去重

 "termsCount": {
      "cardinality": {
        "field": "host_id",
        "precision_threshold": 40000
      }
    }


field: 指定要计算基数的字段,这里是 host_id

precision_threshold: 基数的精度 threshold,默认为 40000。高于这个阈值,返回的基数为 estimated 值,低于这个阈值,返回 exact 值。

在 Elasticsearch 中,cardinality 算法用来计算字段的基数(不重复的值的个数).


cardinality 算法是通过 HyperLogLog 算法实现的,所以它很高效,可以支持大规模数据的基数统计,并且精度很高。 缺省值为3000


9fa188ed0ceb43349be9ed4c4eae57ef.png


精度阈值选项允许用内存交换精度,并定义了一个唯一的计数,在该计数低于此值时,预计计数接近准确。超过这个值,计数可能会变得有点模糊。支持的最大值是40000,高于这个数字的阈值将具有与40000阈值相同的效果。缺省值为3000。


默认情况下,如果基数超过 40000,cardinality 会返回 estimated 值(估算值),否则返回 exact 值(精确值)。如果文档个数远大于40000,那么会返回estimated值,比如50000, 可以通过 precision_threshold 参数控制这个阈值。


所以,cardinality 很适合用于:


  • 统计网站的访问设备/IP 数量
  • 统计不同产品的数量
  • 统计不同用户的数量

它可以提供近实时的统计,对性能影响很小。


小结

利用bucket_sort来分页,cardinality来获取total


第二步 分页并支持模糊查询

方式一 query 方式

GET attack/_search
{
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "should": [
              {
                "match_phrase": {
                  "host_userName": "guo"
                }
              },
              {
                "match_phrase": {
                  "host_ip": "192.168.198.132"
                }
              }
            ]
          }
        },
        {
          "bool": {
            "filter": [
              {
                "terms": {
                  "host_id": [
                    "f261cd4b-8922-4c1f-bb24-72eec4f4245c",
                    "89bd8783-9cbf-4c8d-9160-da4588ee73d7"
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  },
  "aggs": {
    "getAlarmStatistByHostId": {
      "terms": {
        "field": "host_id",
        "size": 100000,
        "order": {
          "_count": "desc"
        }
      },
      "aggs": {
        "host_details": {
          "top_hits": {
            "size": 1,
            "_source": {
              "include": [
                "host_id",
                "host_userName",
                "host_orgPath",
                "host_ip",
                "host_mac"
              ]
            }
          }
        },
        "myBucketSort": {
          "bucket_sort": {
            "from": 0,
            "size": 2,
            "gap_policy": "SKIP"
          }
        }
      }
    },
    "termsCount": {
      "cardinality": {
        "field": "host_id",
        "precision_threshold": 40000
      }
    }
  }
}


返回

{
  "took" : 19,
  "timed_out" : false,
  "_shards" : {
    "total" : 8,
    "successful" : 8,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "getAlarmStatistByHostId" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "f261cd4b-8922-4c1f-bb24-72eec4f4245c",
          "doc_count" : 10,
          "host_details" : {
            "hits" : {
              "total" : {
                "value" : 10,
                "relation" : "eq"
              },
              "max_score" : 9.781191,
              "hits" : [
                {
                  "_index" : "zfattack-202305",
                  "_type" : "_doc",
                  "_id" : "b19af55c-33ec-4e50-93c2-8ae028d96c5c",
                  "_score" : 9.781191,
                  "_source" : {
                    "host_ip" : "192.168.198.132",
                    "host_mac" : "00-0C-29-CA-E9-4C",
                    "host_orgPath" : """112赣州\ztj单位\ztj部门""",
                    "host_userName" : "guo",
                    "host_id" : "f261cd4b-8922-4c1f-bb24-72eec4f4245c"
                  }
                }
              ]
            }
          }
        }
      ]
    },
    "termsCount" : {
      "value" : 1
    }
  }
}


方式二: 脚本

GET zfattack-*/_search
{
  "size": 0,
  "query": {
    "match_all": {}
  },
  "aggs": {
    "getAlarmStatistByHostId": {
      "terms": {
        "script": {
          "source": "if(doc['host_id'].value.contains('f261cd4b-8922-4c1f-bb24-72eec4f4245c')) {doc['host_id'].value }"
        },
        "size": 100000,
        "order": {
          "_count": "desc"
        }
      },
      "aggs": {
        "host_details": {
          "top_hits": {
            "size": 1,
            "_source": {
              "include": [
                "host_id",
                "host_userName",
                "host_orgPath",
                "host_ip",
                "host_mac"
              ]
            }
          }
        },
        "myBucketSort": {
          "bucket_sort": {
            "from": 0,
            "size": 2,
            "gap_policy": "SKIP"
          }
        }
      }
    },
    "termsCount": {
      "cardinality": {
        "script": {
          "source": "if(doc['host_id'].value.contains('f261cd4b-8922-4c1f-bb24-72eec4f4245c')) {doc['host_id'].value }"
        },
        "precision_threshold": 40000
      }
    }
  }
}


返回

#! Deprecation: Deprecated field [include] used, expected [includes] instead
{
  "took" : 15,
  "timed_out" : false,
  "_shards" : {
    "total" : 8,
    "successful" : 8,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "getAlarmStatistByHostId" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "f261cd4b-8922-4c1f-bb24-72eec4f4245c",
          "doc_count" : 10,
          "host_details" : {
            "hits" : {
              "total" : {
                "value" : 10,
                "relation" : "eq"
              },
              "max_score" : 1.0,
              "hits" : [
                {
                  "_index" : "zfattack-202305",
                  "_type" : "_doc",
                  "_id" : "7b761eaa-8b65-4608-b3d9-89a82c9b1784",
                  "_score" : 1.0,
                  "_source" : {
                    "host_ip" : "192.168.198.132",
                    "host_mac" : "00-0C-29-CA-E9-4C",
                    "host_orgPath" : """112赣州\ztj单位\ztj部门""",
                    "host_userName" : "guo",
                    "host_id" : "f261cd4b-8922-4c1f-bb24-72eec4f4245c"
                  }
                }
              ]
            }
          }
        }
      ]
    },
    "termsCount" : {
      "value" : 1
    }
  }
}

cardinality 的 script

可以通过 cardinality 的 script 参数来达到过滤的效果。

语法是:

"cardinality": {
  "field": "field_name",
  "script": "condition" 
}


这会统计 field_name 字段中满足 script 条件的基数。

例如,有文档:

{ "age": 10 } 
{ "age": 20 }
{ "age": 30 }
{ "age": 40 }


如果我们要统计 age > 30 的基数,可以使用:

"cardinality": {
  "field": "age",
  "script": "doc['age'].value > 30" 
}

这会返回 2,因为只有 age = 40 的文档满足条件。

再比如,要统计同时满足 age > 30 和 gender = “male” 的用户基数,可以使用:

"cardinality": {
  "field": "age",  
  "script": "doc['age'].value > 30 && doc['gender'].value == 'male'" 
}


这里的 script 使用 Elasticsearch 的 Painless 脚本语言,可以非常灵活地设置过滤逻辑。

所以,通过 script 参数,我们可以实现一些过滤条件,然后统计满足这些条件的字段基数,这给我们带来很大灵活性。


除了 cardinality 聚合,在 termsCount 查询中也可以使用 script 过滤:

"termsCount": {
  "cardinality": {
    "field": "age",
    "script": "doc['age'].value > 30" 
  }
}


这会返回一个 filtered 基数,代表 age 大于 30 的值有多少个。

所以 script 参数让 cardinality 和 termsCount 变得更加强大和灵活。

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
4月前
|
SQL JSON 大数据
ElasticSearch的简单介绍与使用【进阶检索】 实时搜索 | 分布式搜索 | 全文搜索 | 大数据处理 | 搜索过滤 | 搜索排序
这篇文章是Elasticsearch的进阶使用指南,涵盖了Search API的两种检索方式、Query DSL的基本语法和多种查询示例,包括全文检索、短语匹配、多字段匹配、复合查询、结果过滤、聚合操作以及Mapping的概念和操作,还讨论了Elasticsearch 7.x和8.x版本中type概念的变更和数据迁移的方法。
ElasticSearch的简单介绍与使用【进阶检索】 实时搜索 | 分布式搜索 | 全文搜索 | 大数据处理 | 搜索过滤 | 搜索排序
|
1月前
|
存储 SQL 监控
|
2月前
|
Web App开发 JavaScript Java
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
这篇文章是关于如何使用Spring Boot整合Elasticsearch,并通过REST客户端操作Elasticsearch,实现一个简单的搜索前后端,以及如何爬取京东数据到Elasticsearch的案例教程。
221 0
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
|
2月前
|
缓存 关系型数据库 API
京东面试题:ElasticSearch深度分页解决方案!
京东面试题:ElasticSearch深度分页解决方案!
|
2月前
|
消息中间件 监控 关系型数据库
MySQL数据实时同步到Elasticsearch:技术深度解析与实践分享
在当今的数据驱动时代,实时数据同步成为许多应用系统的核心需求之一。MySQL作为关系型数据库的代表,以其强大的事务处理能力和数据完整性保障,广泛应用于各种业务场景中。然而,随着数据量的增长和查询复杂度的提升,单一依赖MySQL进行高效的数据检索和分析变得日益困难。这时,Elasticsearch(简称ES)以其卓越的搜索性能、灵活的数据模式以及强大的可扩展性,成为处理复杂查询需求的理想选择。本文将深入探讨MySQL数据实时同步到Elasticsearch的技术实现与最佳实践。
152 0
|
3月前
|
存储 自然语言处理 关系型数据库
ElasticSearch基础3——聚合、补全、集群。黑马旅游检索高亮+自定义分词器+自动补全+前后端消息同步
聚合、补全、RabbitMQ消息同步、集群、脑裂问题、集群分布式存储、黑马旅游实现过滤和搜索补全功能
ElasticSearch基础3——聚合、补全、集群。黑马旅游检索高亮+自定义分词器+自动补全+前后端消息同步
|
4月前
|
存储 缓存 监控
|
4月前
|
自然语言处理 Java 关系型数据库
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
149 1
|
4月前
|
自然语言处理 索引
ElasticSearch 实现分词全文检索 - 测试数据准备
ElasticSearch 实现分词全文检索 - 测试数据准备
57 1
|
4月前
|
数据采集 人工智能 自然语言处理
阿里云Elasticsearch AI语义搜索:解锁未来搜索新纪元,精准洞察数据背后的故事!
【8月更文挑战第2天】阿里云Elasticsearch AI场景语义搜索最佳实践
221 5