• Elasticsearch-Kibana-学习笔记


    1.背景

    1.1 简介

    Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。Elasticsearch 的实现原理主要分为以下几个步骤,首先用户将数据提交到Elasticsearch 数据库中,再通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名,打分,再将返回结果呈现给用户。
    更多知识参考:《Elasticsearch 简介》

    Elasticsearch 具有以下特征

    • Elasticsearch 很快。 由于 Elasticsearch 是在 Lucene 基础上构建而成的,所以在全文本搜索方面表现十分出色。Elasticsearch 同时还是一个近实时的搜索平台,这意味着从文档索引操作到文档变为可搜索状态之间的延时很短,一般只有一秒。因此,Elasticsearch 非常适用于对时间有严苛要求的用例,例如安全分析和基础设施监测。
    • Elasticsearch 具有分布式的本质特征。 Elasticsearch 中存储的文档分布在不同的容器中,这些容器称为分片,可以进行复制以提供数据冗余副本,以防发生硬件故障。Elasticsearch 的分布式特性使得它可以扩展至数百台(甚至数千台)服务器,并处理 PB 量级的数据。
    • Elasticsearch 包含一系列广泛的功能。 除了速度、可扩展性和弹性等优势以外,Elasticsearch 还有大量强大的内置功能(例如数据汇总和索引生命周期管理),可以方便用户更加高效地存储和搜索数据。
    • Elastic Stack 简化了数据采集、可视化和报告过程。 人们通常将 Elastic Stack 称为 ELK Stack(代指ElasticsearchLogstashKibana),目前 Elastic Stack 包括一系列丰富的轻量型数据采集代理,这些代理统称为 Beats,可用来向 Elasticsearch 发送数据。通过与 Beats 和 Logstash 进行集成,用户能够在向 Elasticsearch 中索引数据之前轻松地处理数据。同时,Kibana 不仅可针对 Elasticsearch 数据提供实时可视化,同时还提供 UI 以便用户快速访问应用程序性能监测 (APM)、日志和基础设施指标等数据。

    1.2 学习参考

    1.3 本例测试版本

    复制代码
    {
      "name" : "xxx.168.xx.4",
      "cluster_name" : "my-application",
      "cluster_uuid" : "xxxxxxxxx",
      "version" : {
        "number" : "7.12.1",
        "build_flavor" : "default",
        "build_type" : "tar",
        "build_hash" : "xxxxxxxxxxxx",
        "build_date" : "2021-04-20T20:56:39.040728659Z",
        "build_snapshot" : false,
        "lucene_version" : "8.8.0",
        "minimum_wire_compatibility_version" : "6.8.0",
        "minimum_index_compatibility_version" : "6.0.0-beta1"
      },
      "tagline" : "You Know, for Search"
    }
    复制代码

    2.DSL语法学习

    2.1基础知识

    数据类型

    官方参考文档:《Field datatypes》。可查看不同版本的支持数据类型。
    重点理解:

    String字符串的两种数据格式 keyworld,text的区别

    • text:会分词,然后进行索引,用于全文搜索。支持模糊、精确查询,不支持聚合。
    • keyword:不进行分词,直接索引,keyword用于关键词搜索,支持模糊、精确查询,支持聚合。
    如果不指定类型,ElasticSearch字符串将默认被同时映射成text和keyword类型,会自动创建下面的动态映射(dynamic mappings):
    复制代码
    "mappings" : {
          "properties" : {
            "color" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            }
           }
    复制代码
    直接使用color字段不支持聚合,但使用color.keyword支持聚合操作。

    日期/时间自定义格式

    • yyyy-MM-dd HH:mm:ss
    • yyyy-MM-dd
    • epoch_millis(毫秒值)
    定义日期字段类型参考如下映射:
    复制代码
    PUT my_index
    {
      "mappings": {
        "_doc": {
          "properties": {
            "date": {
              "type":   "date",
              "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
            }
          }
        }
      }
    }
    复制代码
    • 数组(数组类型直接声明为text,传入的数组初始化数据类型需一致),object,nested复杂类型;
    • 聚合/排序时,哪些数类型的字段支持:
    默认是根据相关度算分(_score)来排序,但是也支持自定义方式对搜索结果排序。可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。
    若字段类型为text,不支持聚合等操作。也不推荐在Text字段上启用fielddata,因为field data和其缓存存储在堆中,这使得它们的计算成本很高。计算这些字段会造成延迟,增加的堆占用会造成集群性能问题。
    • text常见分词器

    type类型

    根据Elasticsearch版本升级改造,去掉type。一个业务存储数据(类似于mysql数据表)为一个index。
    number_of_shards:分片数(ES 7后,默认分片数为1)
    number_of_replicas:每个分片的备份数量

    2.2构建index

    复制代码
    PUT /study_index
    {
      "settings": {
        "index": {
          "number_of_shards": 1,
          "number_of_replicas": 1 
        }
      },
    
      "mappings": {
          "properties": {
            "study_id": {
              "type": "integer"  
            },
             "price": {
              "type": "double"  
            },
            "content": {
              "type": "text"  
            },
             "title": {
              "type": "keyword"  
            },
            "study_name" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "study_date": {
              "type": "date",
              "format": "yyyy-MM-dd"
            },
            "study_time": {
              "type": "date",
              "format": "yyyy-MM-dd HH:mm:ss"
            },
            "study_millis": {
              "type": "date",
              "format": "epoch_millis"
            },
             "study_array": {
              "type": "text"
            },
             "study_object": {
              "type": "object"
            },
             "study_nested": {
              "type": "nested"
            },
            "location": {
              "type": "geo_point"
            }
          }
        }
    }
    复制代码

    初始化数据

    PUT /study_index/_bulk
    { "index": {}}
    { "study_id" : 2, "price" : 188.55, "content" : "养乐多1 test","title":"养乐多哇哈哈","study_name":"测试,中国人都爱喝", "study_date" : "2022-06-28","study_time" : "2022-10-28 12:22:32","study_millis":"1657626972000","study_array":["养乐多","哇哈哈","饮料"],"study_object":[ { "name":"wang", "age":18 }, { "name":"ling", "age":21 } ],"study_nested":[ { "name":"ma", "sex":1 }, { "name":"zhang", "sex":2 } ],"location":[ -72.34, 41.12 ]  }

    2.3基础DSL查询语句

    filter查询

    过滤器,会查询对结果进行缓存,不会计算相关度,避免计算分值,执行速度非常快。

    组合(bool)查询

    bool 可以用来合并多个过滤条件查询结果的布尔逻辑,它包含这如下几个操作符:
    • must : 多个查询条件的完全匹配,相当于 and。
    • must_not ::多个查询条件的相反匹配,相当于 not。
    • should : 至少有一个查询条件匹配, 相当于 or。

    match

    match查询属于高级查询,他会根据你查询的字段类型不一样,采用不同的查询方式,更加灵活多变。
    • 查询的是日期或者是数值的话,他会将你基于的字符串查询内容转换为日期或者数值对待。
    • 查询的内容是一个不能被分词的内容(keyword),match查询不会对你指定的查询关键字进行分词。
    • 查询的内容是一个可以被分词的内容(text),match会将你指定的查询内容根据一定的方式去分词,去分词库中匹配指定的内容。
    match查询,实际底层就是多个term查询,将多个term查询的结果给你封装到了一起而已。
    • match_phrase查询分析文本,并从分析文本中创建短语查询
    • match_phrase_prefix 做匹配

    term

    • term代表完全匹配,不进行分词器分析
    • term 查询的字段需要在mapping的时候定义好,否则可能词被分词。传入指定的字符串,查不到数据

    wildcard

    类似于mysql中的like语法,基于**可做左右匹配。
    英文查询没问题,中文查询有问题。中文查询的问题体现在单个汉字查询,没问题。多个字查询,则不支持。
    中文使用时,将字段设置为keyword类型,支持多个汉字匹配。将对应字段加上keyword也支持,如:study_name.keyword。
    中文含义是:避免以*或?开头的模式。这会增加查找匹配项所需的迭代次数并降低搜索性能。
    • ? : 支持模糊匹配单个字符。举例:Ma?s 仅能匹配:Mars, Mass, 和 Maps。
    • *: 支持模糊匹配零个或者多个字符。举例:Ma*s 能匹配:Mars, Matches 和 Massachusetts等。
    模糊查询,如中国人都喜欢,可以基于“*中国*”匹配,也可以基于“中??都*” 匹配。
    复制代码
    GET /study_index/_search 
    {
      "query": {
        "wildcard": {
          "study_name.keyword":  "*中??都*"
        }
      }
    }
    复制代码
    模糊查询的性能都不高,wildcard也不例外。不过在ES7.9中引入了一种新的wildcard 字段类型,该字段类型经过优化,可在字符串值中快速查找模式。wildcard 类型出现的目的:一方面避免了某些场景下分词查询不准确的问题,另一方面也解决了通配符和正则检索的效率问题。
    复制代码
     PUT my-study_index
    {
      "mappings": {
        "properties": {
          "my_wildcard_test": {
            "type": "wildcard"
          }
        }
      }
    }
    复制代码

    fuzzy

    fuzzy也是一种模糊查询,我理解它其实属于比较轻量级别的模糊查询。fuzzy中有个编辑距离的概念,编辑距离是对两个字符串差异长度的量化,及一个字符至少需要处理多少次才能变成另一个字符,比如lucene和lucece只差了一个字符他们的编辑距离是1。
    其实fuzzy有个fuzziness参数,可以赋值为0,1,2和AUTO,默认其实是AUTO。
    AUTO的意思是,根据查询的字符串长度决定允许的编辑距离,规则是:
    • 0..2 完全匹配(就是不允许模糊)
    • 3..5 编辑距离是1
    • 大于5 编辑距离是2
    其实仔细想一下,即使限制了编辑距离,查询的字符串比较长的情况下需要查询的词项也是非常巨大的。所以fuzzy还有一个选项是prefix_length,表示不能被 “模糊化” 的初始字符数,通过限制前缀的字符数量可以显著降低匹配的词项数量。
    更多模糊查询参考:《Elasticsearch中的模糊查询》

    constant_score 以非评分模式查询

    查询price为68.55的记录

    mysql对比:select * from study_index where price=68.55
    复制代码
    GET /study_index/_search 
    {
      "query": {
        "term": {
          "price": 68.55
        }
      }
    }
    复制代码

    查询study_id为[1,2,3,4]的数据,price大于100,study_date在一个时间区间的数据

    mysql对比:select * from study_index where price>100 and study_id in (1,2,3,4) and study_date between '2020-01-01' and '2022-09-01' and content like '%test%'
    # 直接查询
    GET /study_index/_search 
    {
        "query":{
            "bool":{
                "must":[
                    {
                        "terms":{
                            "study_id":[1, 2, 3, 4]
                        }
                    },
                    {
                        "wildcard":{
                            "content":"*test*"
                        }
                    },
                    {
                        "range":{
                            "price":{
                                "gte":100
                            }
                        }
                    },
                    {
                        "range":{
                            "study_date":{
                                "gte":"2020-01-01",
                                "lte":"2022-09-01"
                            }
                        }
                    }
                ]
            }
        }
    }
    
    # 过滤数据查询
     GET /study_index/_search 
    {
        "query":{
            "bool":{
                "must":[
                    {
                        "terms":{
                            "study_id":[1, 2, 3, 4]
                        }
                    },
                    {
                        "wildcard":{
                            "content":"*test*"
                        }
                    }
                ],
                "filter": [
                  {
                    "range":{
                            "price":{
                                "gte":100
                            }
                    }
                  },
                  {
                    "range":{
                      "study_date":{
                                "gte":"2020-01-01",
                                "lte":"2022-09-01"
                            }
                  }
                  }
                ]
            }
        }
    }
      
     # 查询时不计算关联分数 
     GET /study_index/_search 
    {
        "query":{
          "constant_score": {
            "filter": {
               "bool":{
                "must":[
                    {
                        "terms":{
                            "study_id":[1, 2, 3, 4]
                        }
                    },
                  
                    {
                        "wildcard":{
                            "content":"*test*"
                        }
                    }
                ],
                "filter": [
                  {
                    "range":{
                            "price":{
                                "gte":100
                            }
                    }
                  },
                  {
                    "range":{
                      "study_date":{
                                "gte":"2020-01-01",
                                "lte":"2022-09-01"
                            }
                  }
                  }
                ]
            }
            },
            "boost": 1.2
          }
           
        }
    }      
    View Code

    查询商户ID为3582,订单号为360102199003072618,按时间范围过滤,按下单时间倒序,每次查询100条

    左匹配

    mysql对比:like 'wang%'
    prefix query,match_phrase_prefix均支持左匹配。
    复制代码
    {
                        "match_phrase_prefix":{
                            "content":"wang"
                        }
                    }
                    
    { "query": {
        "prefix" : { "author": "方" }
      }
    }
    复制代码

    结果集返回指定字段 (_source)

     在query同一级,"_source":["字段1","字段2",...]

    排序分页查询

    text类型无法排序,keyword类型可以
    复制代码
    GET /study_index/_search 
    {
        "query":{
            "bool":{
                "must":[
                    {
                        "match_phrase_prefix":{
                            "content":"乳"
                        }
                    },
                  {
                    "range": {
                      "price": {
                        "gte": 10,
                        "lte": 20000
                      }
                    }
                  }
                ]
            }
        }
        ,
        "sort": [
          {
            "price": {
              "order": "desc"
            }
          },
          {
            "study_id": {
              "order": "desc"
            }
          }
        ],
         "_source": ["study_millis","price","title","study_array"], 
      "from":0,
      "size": 20
    }
    复制代码

    分组聚合

    "size": 0:表示只展示分组统计的字段,不展示原始数据;
    基于title分组,并基于平均价格排序;
    复制代码
    GET /study_index/_search 
    {
      "size": 0, 
      "aggs": {
        "title_group": {
          "terms": {
            "field": "title",
            "order": {
              "avg_price": "desc"
            }
          },
          "aggs": {
            "avg_price": {
              "avg": {
                "field": "price"
              }
            }
          }
        }
      }
    }
    复制代码

    基于区间统计聚合

    复制代码
     GET /study_index/_search 
    {
      "size": 0, 
      "aggs": {
        "age_group_price":{
          "range": {
            "field": "price",
            "ranges": [
              {
                "from": 1,
                "to": 100
              },
              {
                "from": 100,
                "to":1000
              },
               {
                "from": 1000,
                "to":100000
              }
            ]
          }
        }
      }
    }
    复制代码

    高亮显示

    展示content内容中,高亮显示test
    复制代码
     GET /study_index/_search 
            { 
        "query": {
            "match": {
                "content": "test"
            }
        },
        "highlight": {
            "pre_tags": [
                "<span>"
            ],
            "post_tags": [
                "span>"
            ],
            "fields": {
                "content": {}
               
            }
        }
    }
    复制代码

    深分页

    分页方式 性能 优点 缺点 场景
    from + size 灵活性好,实现简单 深度分页问题 数据量比较小,能容忍深度分页问题
    scroll 解决了深度分页问题 无法反应数据的实时性(快照版本)维护成本高,需要维护一个 scroll_id 海量数据的导出(比如笔者刚遇到的将es中20w的数据导入到excel)需要查询海量结果集的数据
    search_after 性能最好不存在深度分页问题能够反映数据的实时变更 实现复杂,需要有一个全局唯一的字段连续分页的实现会比较复杂,因为每一次查询都需要上次查询的结果 海量数据的分页
    第一步获取scroll
    复制代码
     GET /study_index/_search?scroll=2m
            { 
              
        "query": {
          "fuzzy": {
            "content":{
                         "value":"test"   
                }
          }
        },
        "size": 3
    }    
    复制代码
    第二步基于scroll查询
    基于scroll_id查询时,查询语句不用再写索引名称,直接编写_search/scroll 。
    GET /_search/scroll?pretty
    {
     "scroll" : "1m", 
     "scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFkdzQVVFd29IVEZ5VE13ZEZNV2dUMkEAAAAAAADAgBY4VDlNWHdpN1NTV2JXM20wT0pOdEVn" 
    }   

    3.Kibana数据展示

    Kibana基础知识:《如何开始使用 Kibana》
    Kibana 是用于在 Elasticsearch 中可视化数据的强大工具。 这是开始探索你的 Elasticsearch 数据的方法。Kibana 是一种免费及开放的分析和可视化工具,可通过基于浏览器的界面轻松搜索,可视化和探索大量数据。 除了 Elasticsearch,Logstash 和 Beats 之外,Kibana 是 Elastic Stack(以前称为 ELK Stack)的核心部分。
    在最新的 Elastic Stack 中,它也被称之为 Data View。Elasticsearch 将数据存储在索引中-如果你更熟悉关系数据库,则它们在某种程度上类似于表。 索引模式告诉 Kibana 你想探索哪些Elasticsearch 索引。 你可以在 Elasticsearch 中为特定索引创建索引模式,也可以使用通配符*同时查询多个索引。 在 Kibana 中可以有多个索引模式(就像数据库中有很多表一样)。 在创建可视化或搜索数据时,你将需要选择要在其上进行搜索的索引模式。

    3.1简单分析学习数据

     

     
  • 相关阅读:
    C++基础知识点
    认识Redis以及Redis的安装
    央国企、金融信创改造必备的Windows AD域控国产替代方案
    如何在华为 Ascend 设备上运行模型
    实操演练 | 不使用联接查询多个表
    Presto查询慢SQL原因排查
    Dubbo捕获自定义异常问题
    常见的css面试题(持续更新,欢迎补充)
    wsl使用vscode连接,远程安装C/C++ 拓展时,报错
    Eureka详解
  • 原文地址:https://www.cnblogs.com/wlandwl/p/es.html