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