小太阳的博客

ElasticSearch和Kibana

ElasticSearch是什么

Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。

Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。不过,Elasticsearch不仅仅是Lucene和全文搜索,我们还能这样去描述它:

  • 分布式的实时文件存储,每个字段都被索引并可被搜索
  • 分布式的实时分析搜索引擎
  • 可以扩展到上百台服务器,处理PB级结构化或非结构化数据
  • 自动维护数据的分布到多个节点的索引的建立,还有搜索请求分布到多个节点的执行
  • 自动维护数据的冗余副本,保证一些机器宕机后,不会丢失任何的数据

而且,所有的这些功能被集成到一个服务里面,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。

ElasticSearch核心概念

  • Near Realtime(NRT):近实时。从写入数据到数据可以被搜索到有延迟(大概1秒);基于Elasticsearch执行搜索和分析可以达到秒级
  • Cluster:集群。包含多个节点,每个节点属于哪个集群是通过一个配置(集群名称,默认是Elasticsearch来决定的),对于中小型企业来说,刚开始一个集群就一个节点很正常
  • Node:节点。集群中的一个节点,节点也有一个名称(默认是随机分配的),节点名称很重要(在执行运维管理操作的时候),默认节点会去加入一个名称为“Elasticsearch”的集群。如果直接启用一堆节点,那么它们会自动组成一个Elasticsearch集群,当然,一个节点也可以组成一个Elasticsearch集群
  • Document:文档。Elasticsearch中最小数据单元,一个document可以是一条客户数据,一条商品分类数据,一条订单数据,通常用JSON数据结构表示,每个index下的type中,都可以去存储多个document。一个document相当于关系型数据库中的一行数据。
  • Index:索引。包含一堆有相似结构的的文档数据。比如可以有一个客户索引、商品分类索引、订单索引,索引有一个名称。ElasticSearch存储数据的地方,可以理解成关系型数据库中的数据库概念。
  • Type:类型。每个索引里都可以有一个或多个type,type是index中的一个逻辑数据分类,一个type下的document,都有相同的field。比如博客系统,有一个索引,可以定义用户数据type,博客数据type,评论数据type
  • shard:单台机器无法存储大量数据,Elasticsearch可以将一个索引中的数据切分为多个shard,分布在多台服务器上存储。有了shard就可以横向扩展,存储更多的数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个shard都是一个lucene index
  • replica:任何一个服务器随时可能故障或宕机,此时shard可能就会丢失,因此,可以为每个shard创建多个replica副本。replica可以在shard故障时提供备用服务,保证数据不丢失,多个replica还可以提升搜索操作的吞吐量和性能。primary shard(建立索引时一次设置,不能修改,默认5个)。replica shard(随时修改数量,默认1个),默认每个索引10个shard,5个primary shard,5个replica shard,最小的高可用配置是2台服务器
  • mapping(映射):mapping定义了每个字段的类型、字段所使用的分词器等。相当于关系型数据库中的表结构。

ES与关系型数据库的对应关系

  • index(索引):相当于mysql的库
  • 映射:相当于mysql 的表结构
  • document(文档):相当于mysql的表中的数据。1个document代表1条记录。

倒排索引

倒排索引:将文档进行分词,形成词条和id的对应关系即为反向索引。

以唐诗为例,我们大脑中的索引一般是正向的。

比如,说出包含“前”的诗句:

正向索引:由《静夜思》联想到床前明月光--->“前”字

反向索引:“前”字-->床前明月光-->《静夜思》。分次后:床前、明月、月光、床、前等等都会指向床前明月光

反向索引的实现就是对诗句进行分词,分成单个的词,由词推据,即为反向索引。

如果指向床前明月光等诗句,那么古诗词的数据那么多,存储也是问题,所以直接存储诗词名,先查询到诗词名,再根据诗词名找到对应诗句。

ES数据类型

简单数据类型

字符串类型

text:会分词,不支持聚合
keyword:不会分词,将全部内容作为一个词条,支持聚合
注:聚合相当于mysql 中的sum(求和)等聚合函数。

数值类型

long:64位整数
integer:32位整数
short:16位整数
byte:8位整数。-128 ~ 127
double(双精度)
float(单精度)
half_float(半精度)
scaled_float(可缩放的float)

布尔类型

true或false

二进制类型

binary(不常用)

范围类型

integer_range
float_range
long_range
double_range
date_range

日期类型

date

复杂数据类型

数组

[ ] Nested: nested (for arrays of JSON objects 数组类型的JSON对象) 

对象

{ } Object: object(for single JSON objects 单个JSON对象)

Kibana操作

创建索引

PUT person

查询索引

GET person

添加映射

PUT /person/_mapping
{
  "properties":{
    "name":{
      "type":"text"
    },
    "age":{
      "type":"integer"
    }
  }
}

查询映射

GET person/_mapping

删除索引

DELETE person

创建索引并添加映射

PUT person
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "integer"
      }
    }
  }
}

添加映射字段

PUT person/_mapping
{
  "properties": {
    "address": {
      "type": "text"
    }
  }
}

添加文档,指定ID

# 指定ID添加使用PUT或POST都可以
PUT person/_doc/id1
{
  "name":"张三",
  "age":20,
  "address":"北京"
}

添加文档,不指定ID(默认生成)

# 不指定ID需用POST请求
POST person/_doc
{
  "name":"李四",
  "age":25,
  "address":"河北"
}

查询文档(根据ID查询)

GET person/_doc/id1

查询所有文档(默认10条)

GET person/_search

查询所有文档(match_all)

# 使用size控制每页显示多少条

GET person/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,
  "size": 100
}

词条查询(term)

# term不会分词查询
GET person/_search
{
  "query": {
    "term": {
      "address":{
        "value": "测试"
      }
    }
  },
  "from": 0,
  "size": 100
}

分词查询(match)

# match会先对条件分词,然后对分词后的各个词条进行等值匹配,然后取并集
GET person/_search
{
  "query": {
    "match": {
      "address": "测试北京"
    }
  },
  "from": 0,
  "size": 100
}

# operator设置取交集或并集or或and
GET person/_search
{
  "query": {
    "match": {
      "address": {
        "query": "测试北京",
        "operator": "or"
      }
    }
  },
  "from": 0,
  "size": 100
}

分词模糊查询

# 上面的查询是等值匹配,如查询北京,包含北京的词会被查到,如果单独写一个北,那么将不会和北京匹配。

# wildcard查询,模糊查询,?或*通配符匹配
# wildcard格外注意,通配符不能写到左侧,与mysql一样会全部倒排索引扫描
GET person/_search
{
  "query": {
    "wildcard": {
      "address": {
        "value": "北*"
      }
    }
  },
  "from": 0,
  "size": 100
}

# 正则查询
GET person/_search
{
  "query": {
    "regexp": {
      "address": "\\w+(.)*"
    }
  },
  "from": 0,
  "size": 100
}

# 前缀查询
GET person/_search
{
  "query": {
    "prefix": {
      "address": {
        "value": "北"
      }
    }
  },
  "from": 0,
  "size": 100
}

范围查询(range)

# 年龄在25-30岁
GET person/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 25,
        "lte": 30
      }
    }
  },
  "from": 0,
  "size": 100
}

排序

# 年龄在25-30岁,并根据年龄排序
GET person/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 25,
        "lte": 30
      }
    }
  },
  "from": 0,
  "size": 100,
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

多字段查询(queryString)

# queryString
# 会对查询条件分词,然后对分词后的词条等值匹配,默认取并集
# 可以指定多个查询字段
GET person/_search
{
  "query": {
    "query_string": {
      "fields": ["name", "address"], 
      "query": "李四 OR 北京"
    }
  },
  "from": 0,
  "size": 100
}

# simple_query_string,和queryString的区别是不支持OR或AND
# 会对查询条件分词,然后对分词后的词条等值匹配,默认取并集
# 可以指定多个查询字段
GET person/_search
{
  "query": {
    "simple_query_string": {
      "fields": ["name", "address"], 
      "query": "李四测试"
    }
  },
  "from": 0,
  "size": 100
}

多条件查询(boolQuery)

# boolQuery 连接查询
# must(and):条件必须成立,会计算得分
# must_not(not):条件必须不成立
# should(or):条件可以成立
# filter:条件必须成立,性能比must高,不会计算得分
GET person/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "name": {
              "value": "李四测试"
            }
          }
        }
      ]
    }
  }
}

# filter不计算得分
GET person/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "name": {
              "value": "李四测试"
            }
          }
        }
      ]
    }
  }
}

# must多条件 
GET person/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "name": {
              "value": "李四测试"
            }
          }
        },
        {
          "match": {
            "address": "北京"
          }
        }
      ]
    }
  }
}

# should多条件
GET person/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "name": {
              "value": "李四测试"
            }
          }
        },
        {
          "match": {
            "address": "北京"
          }
        }
      ]
    }
  }
}

修改文档(若ID不存在则添加)

PUT person/_doc/id1
{
  "name":"张三",
  "age":25
}

删除文档(根据ID删除)

DELETE person/_doc/ltnno3oB3DGDGB_xHuOh

批量操作

POST _bulk
{"delete": {"_index": "person", "_id": "id1"}}
{"delete": {"_index": "person", "_id": "id2"}}
{"create": {"_index": "person", "_id": "id4"}}
{"name": "张三", "age": 25, "address": "我爱北京天安门"}
{"update": {"_index": "person", "_id": "id5"}}
{"doc": {"name": "赵六修改测试", "address": "北京房山"}}

聚合分析

语法

GET test_search_index/_search
{
    "size": 0,
    //关键词,与query同级,aggregation可以简写为aggs
    "aggs": {
        //自定义聚合名称,返回的结果也会在这个名称下
        "aggregation_name": {
            //聚合分析的定义,包含type和body定义
            "aggregation_type": {
                <aggregation_body>
            }
        }
        //子查询
        [,"aggs":{[<sub_aggregation>]+}]?
    }
    //可以包含多个聚合分析
    [,"<aggregation_name_2>": {...}]*
}

ES将聚合分析分为4类

  • Bucket:分桶类型,类似SQL中的Group By语法
  • Metric:指标分析类型,如计算最大值、最小值、平均值等
  • Pipeline:管道分析类型,基于上一级的局和分析结果进行再分析
  • Matrix:矩阵分析类型

Bucket聚合分析

按照一定的规则将文档分配到不同的桶中,达到分类分析的目的。如分3个桶,第1个桶是年龄小于18岁的数据,第2个桶是18-60岁的数据,第3个桶是60岁以上的数据。返回的数据在buckets里面。

Bucket聚合分析允许通过添加子分析来进一步进行分析,该子分析可以是Bucket也可以是Metric。所以是可以嵌套的。

按照Bucket分桶策略,常见Bucket聚合分析如下:

  • Terms
  • Range
  • Date Range
  • Histogram
  • Date Histogram

Terms 条件

GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义的名称
        "jobs": {
            //关键词
            "terms": {
                //指定字段
                "field": "job.keyword",
                //指定返回数量
                "size": 5
            }
        }
    }
}

range 范围

GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义的名称
        "salary_range": {
            //关键词
            "range": {
                //指定字段
                "field": "salary",
                "ranges": [
                    {
                        //key的名字可以自定义
                        "key": "<10000"
                        "to": 10000
                    },
                    {
                        "from": 10000,
                        "to": 20000
                    }
                ]
            }
        }
    }
}

Date Range 日期范围

GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义的名称
        "date_range": {
            //关键词
            "range": {
                //指定字段
                "field": "birth",
                //指定日期返回结果格式
                "format": "yyyy",
                //指定日期,可以使用date math
                "ranges": [
                    {
                        "from": 1980,
                        "to": 1990
                    },
                    {
                        "from": 1990,
                        "to": 2000
                    }
                ]
            }
        }
    }
}

Histogram 直方图,以固定间隔的策略来分割数据

GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义的名称
        "salary_hist": {
            //关键词
            "histogram": {
                //指定字段
                "field": "salary",
                //指定间隔大小
                "interval": 5000,
                //指定数据范围
                "extended_bounds": {
                    "min": 0,
                    "max": 40000
                }
            }
        }
    }
}

Date Histogram 日期的直方图或柱状图,是时序数据分析中常用的聚合分析类型

GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义的名称
        "by_year": {
            //关键词
            "date_histogram": {
                //指定字段
                "field": "birth",
                //指定间隔大小
                "interval": "year",
                //指定日期格式
                "format": "yyyy"
            }
        }
    }
}

Metric聚合分析

返回的数据在metrics里面。

单值分析

只输出一个分析结果:

  • min,max,avg,sum
  • cardinality
Min 最小
GET test_search_index/_search
{
    //如果不想返回文档,size设置为0,那么返回的hits就没有了
    "size": 0,
    "aggs": {
        //自定义的名称
        "min_age": {
            //关键词,最小
            "min": {
                //字段
                "field": "age"
            }
        }
    }
}
Max 最大
GET test_search_index/_search
{
    //如果不想返回文档,size设置为0,那么返回的hits就没有了
    "size": 0,
    "aggs": {
        //自定义的名称
        "max_age": {
            //关键词,最大
            "max": {
                //字段
                "field": "age"
            }
        }
    }
}
Avg 平均
GET test_search_index/_search
{
    //如果不想返回文档,size设置为0,那么返回的hits就没有了
    "size": 0,
    "aggs": {
        //自定义的名称
        "avg_age": {
            //关键词,平均
            "avg": {
                //字段
                "field": "age"
            }
        }
    }
}
Sum 求和
GET test_search_index/_search
{
    //如果不想返回文档,size设置为0,那么返回的hits就没有了
    "size": 0,
    "aggs": {
        //自定义的名称
        "sum_age": {
            //关键词,求和
            "sum": {
                //字段
                "field": "age"
            }
        }
    }
}
cardinality 去重后的数量
# 类似 distinct count概念,去重后的个数
GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        "count_of_job": {
            "cardinality": {
                "field": "name"
            }
        }
    }
}
组合使用
GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        "sum_age": {
            "sum": {
                "field": "age"
            }
        },
        "min_age": {
            "min": {
                "field": "age"
            }
        },
        "max_age": {
            "max": {
                "field": "age"
            }
        },
    }
}

多值分析

输出多个分析结果:

  • stats,extended stats
  • percentile,percentile rank
  • top hits
stats min\max\avg\sum\count
GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义名称
        "stats_age": {
            //关键词,返回一系列数值类型的统计值,包含min\max\avg\sum\count
            "ststs": {
                "field": "age"
            }
        }
    }
}
extended stats 更多的统计数据
GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义名称
        "exstats_stats_age": {
            //关键词,对stats做了扩展,包含了更多的统计数据,如方差、标准差等
            "extended_stats": {
                "field": "age"
            }
        }
    }
}
percentile 百分位数统计
GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义名称
        "per_age": {
            //关键词
            "percentiles": {
                "field": "salary",
                //只返回哪些,不定义返回所有
                "percents": [
                  95, 99, 99.9
                ]
            }
        }
    }
}
percentile rank 百分位数排名
GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义名称
        "per_salary": {
            //关键词
            "percentile_rank": {
                "field": "salary",
                //指定只返回哪些,不定义返回所有
                "values": [11000, 30000]
            }
        }
    }
}
top hits 分桶后获取最匹配的顶部文档列表
GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义名称
        "jobs": {
            //分桶聚合
            "terms": {
                "field": "job"
            },
            //子查询
            "aggs": {
                "top_employee": {
                    "top_hits": {
                        //返回10条
                        "size": 10,
                        "sort": [
                            {
                                "age": {
                                    "order": "desc"
                                }
                            }
                        ]
                    }
                }
            }
        }
    }
}

Bucket+Metric聚合分析

示例1

GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义名称,第一层聚合
        "jobs": {
            //分桶聚合
            "terms": {
                //首先对job分桶
                "field": "job",
                "size": 10
            },
            //第二层聚合
            "aggs": {
                //自定义名称
                "age_range": {
                    //关键字,范围查询
                    "range": {
                        //基于job分桶的结果,再分桶
                        "field": "age",
                        "ranges": [
                            {"to":20},
                            {"from":20,"to":30},
                            {"from":30}
                        ]
                    }
                }
            }
        }
    }
}

示例2

GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义名称,第一层聚合
        "jobs": {
            //分桶聚合
            "terms": {
                //首先对job分桶
                "field": "job",
                //分桶内的数据条数
                "size": 10
            },
            //第二层聚合
            "aggs": {
                //自定义名称
                "salary": {
                    //关键字,指标分析
                    "stats": {
                        //基于job分桶的结果,再分桶
                        "field": "salary"
                    }
                }
            }
        }
    }
}

Pipeline聚合分析

针对聚合分析的结果再次进行聚合分析,而且支持链式调用

Pipeline的分析结果会输出到原结果中,根据输出位置的不同,分为两类:

  • Parent结果内嵌到现有的聚合分析结果中:Derivative求导数、Moving Average平均、Cumulative Sum累计求和
  • Sibling结果与现有聚合分析结果统计:Max\Min\Avg\Sum Bucket、Stats\Extended Stats Bucket、Percentiles Bucket
// 订单月平均销售额?
GET test_search_index/_search
{
    "size": 0,
    "aggs": {
        //自定义名称,第一层聚合
        "sales_per_month": {
            "date_histogram": {
                //首先按照月份分桶
                "field": "date",
                "interval": "month"
            },
            //第二层聚合
            "aggs": {
                //自定义名称
                "sales": {
                    //关键字,求和
                    "sum": {
                        //基于月份分桶后的结果,对price求和
                        "field": "price"
                    }
                }
            }
        }
    }
}

Copyright © 2023,版权所有 - 小太阳的博客 - 黑ICP备2023000004号