elasticsearch

1.es初识

1.1es的功能

(1)分布式的搜索引擎和数据分析引擎

搜索:百度,网站的站内搜索,IT系统的检索
数据分析:电商网站,最近7天牙膏这种商品销量排名前10的商家有哪些;新闻网站,最近1个月访问量排名前3的新闻版块是哪些
分布式,搜索,数据分析

(2)全文检索,结构化检索,数据分析

全文检索:我想搜索商品名称包含牙膏的商品,select * from products where product_name like "%牙膏%"
结构化检索:我想搜索商品分类为日化用品的商品都有哪些,select * from products where category_id='日化用品'
部分匹配、自动完成、搜索纠错、搜索推荐
数据分析:我们分析每一个商品分类下有多少个商品,select category_id,count(*) from products group by category_id

(3)对海量数据进行近实时的处理

分布式:ES自动可以将海量数据分散到多台服务器上去存储和检索
海联数据的处理:分布式以后,就可以采用大量的服务器去存储和检索数据,自然而然就可以实现海量数据的处理了
近实时:检索个数据要花费1小时(这就不要近实时,离线批处理,batch-processing);在秒级别对数据进行搜索和分析

跟分布式/海量数据相反的:lucene,单机应用,只能在单台服务器上使用,最多只能处理单台服务器可以处理的数据量

1.2 es的适用场景

国外

(1)维基百科,类似百度百科,牙膏,牙膏的维基百科,全文检索,高亮,搜索推荐
(2)The Guardian(国外新闻网站),类似搜狐新闻,用户行为日志(点击,浏览,收藏,评论)+社交网络数据(对某某新闻的相关看法),数据分析,给到每篇新闻文章的作者,让他知道他的文章的公众反馈(好,坏,热门,垃圾,鄙视,崇拜)
(3)Stack Overflow(国外的程序异常讨论论坛),IT问题,程序的报错,提交上去,有人会跟你讨论和回答,全文检索,搜索相关问题和答案,程序报错了,就会将报错信息粘贴到里面去,搜索有没有对应的答案
(4)GitHub(开源代码管理),搜索上千亿行代码
(5)电商网站,检索商品
(6)日志数据分析,logstash采集日志,ES进行复杂的数据分析(ELK技术,elasticsearch+logstash+kibana)
(7)商品价格监控网站,用户设定某商品的价格阈值,当低于该阈值的时候,发送通知消息给用户,比如说订阅牙膏的监控,如果高露洁牙膏的家庭套装低于50块钱,就通知我,我就去买
(8)BI系统,商业智能,Business Intelligence。比如说有个大型商场集团,BI,分析一下某某区域最近3年的用户消费金额的趋势以及用户群体的组成构成,产出相关的数张报表,**区,最近3年,每年消费金额呈现100%的增长,而且用户群体85%是高级白领,开一个新商场。ES执行数据分析和挖掘,Kibana进行数据可视化

国内

(9)国内:站内搜索(电商,招聘,门户,等等),IT系统搜索(OA,CRM,ERP,等等),数据分析(ES热门的一个使用场景)

1.3 es的特点

(1)可以作为一个大型分布式集群(数百台服务器)技术,处理PB级数据,服务大公司;也可以运行在单机上,服务小公司
(2)Elasticsearch不是什么新技术,主要是将全文检索、数据分析以及分布式技术,合并在了一起,才形成了独一无二的ES;lucene(全文检索),商用的数据分析软件(也是有的),分布式数据库(mycat)
(3)对用户而言,是开箱即用的,非常简单,作为中小型的应用,直接3分钟部署一下ES,就可以作为生产环境的系统来使用了,数据量不大,操作不是太复杂
(4)数据库的功能面对很多领域是不够用的(事务,还有各种联机事务型的操作);特殊的功能,比如全文检索,同义词处理,相关度排名,复杂数据分析,海量数据的近实时处理;Elasticsearch作为传统数据库的一个补充,提供了数据库所不不能提供的很多功能

2.es介绍

2.1、lucene和elasticsearch的前世今生

lucene,最先进、功能最强大的搜索库,直接基于lucene开发,非常复杂,api复杂(实现一些简单的功能,写大量的java代码),需要深入理解原理(各种索引结构)

elasticsearch,基于lucene,隐藏复杂性,提供简单易用的restful api接口、java api接口(还有其他语言的api接口)
(1)分布式的文档存储引擎
(2)分布式的搜索引擎和分析引擎
(3)分布式,支持PB级数据

开箱即用,优秀的默认参数,不需要任何额外设置,完全开源

关于elasticsearch的一个传说,有一个程序员失业了,陪着自己老婆去英国伦敦学习厨师课程。程序员在失业期间想给老婆写一个菜谱搜索引擎,觉得lucene实在太复杂了,
就开发了一个封装了lucene的开源项目,compass。后来程序员找到了工作,是做分布式的高性能项目的,觉得compass不够,就写了elasticsearch,让lucene变成分布式的系统。

2.2、elasticsearch的核心概念

(1)Near Realtime(NRT):近实时,两个意思,从写入数据到数据可以被搜索到有一个小延迟(大概1秒);基于es执行搜索和分析可以达到秒级

(2)Cluster:集群:
包含多个节点,每个节点属于哪个集群是通过一个配置(集群名称,默认是elasticsearch)来决定的,对于中小型应用来说,刚开始一个集群就一个节点很正常
(3)Node:
节点,集群中的一个节点,节点也有一个名称(默认是随机分配的),节点名称很重要(在执行运维管理操作的时候),默认节点会去加入一个名称为“elasticsearch”的集群,如果直接启动一堆节点,那么它们会自动组成一个elasticsearch集群,当然一个节点也可以组成一个elasticsearch集群

(4)Document&field:
文档,es中的最小数据单元,一个document可以是一条客户数据,一条商品分类数据,一条订单数据,通常用JSON数据结构表示,每个index下的type中,都可以去存储多个document。一个document里面有多个field,每个field就是一个数据字段。

product document

{
  "product_id": "1",
  "product_name": "高露洁牙膏",
  "product_desc": "高效美白",
  "category_id": "2",
  "category_name": "日化用品"
}

(5)Index:
索引,包含一堆有相似结构的文档数据,比如可以有一个客户索引,商品分类索引,订单索引,索引有一个名称。一个index包含很多document,一个index就代表了一类类似的或者相同的document。比如说建立一个product index,商品索引,里面可能就存放了所有的商品数据,所有的商品document。
(6)Type:
类型,每个索引里都可以有一个或多个type,type是index中的一个逻辑数据分类,一个type下的document,都有相同的field,比如博客系统,有一个索引,可以定义用户数据type,博客数据type,评论数据type。

商品index,里面存放了所有的商品数据,商品document

但是商品分很多种类,每个种类的document的field可能不太一样,比如说电器商品,可能还包含一些诸如售后时间范围这样的特殊field;生鲜商品,还包含一些诸如生鲜保质期之类的特殊field

type,日化商品type,电器商品type,生鲜商品type

日化商品type:product_id,product_name,product_desc,category_id,category_name
电器商品type:product_id,product_name,product_desc,category_id,category_name,service_period
生鲜商品type:product_id,product_name,product_desc,category_id,category_name,eat_period

每一个type里面,都会包含一堆document


{
  "product_id": "2",
  "product_name": "长虹电视机",
  "product_desc": "4k高清",
  "category_id": "3",
  "category_name": "电器",
  "service_period": "1年"
}


{
  "product_id": "3",
  "product_name": "基围虾",
  "product_desc": "纯天然,冰岛产",
  "category_id": "4",
  "category_name": "生鲜",
  "eat_period": "7天"
}

(7)shard ************************************************:
单台机器无法存储大量数据,es可以将一个索引中的数据切分为多个shard,分布在多台服务器上存储。有了shard就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,
提升吞吐量和性能。每个shard都是一个lucene index。
(8)replica ************************************************:
任何一个服务器随时可能故障或宕机,此时shard可能就会丢失,因此可以为每个shard创建多个replica副本。replica可以在shard故障时提供备用服务,保证数据不丢失,
多个replica还可以提升搜索操作的吞吐量和性能。primary shard(建立索引时一次设置,不能修改,默认5个),replica shard(随时修改数量,默认1个),
默认每个索引10个shard,5个primary shard,5个replica shard,最小的高可用配置,是2台服务器。

2.3、elasticsearch核心概念 vs. 数据库核心概念

Elasticsearch			数据库

-----------------------------------------

Document			行
Type				表  (type将在8.x版本弃用)
Index				库

2.4 es分布式架构

2.4.1 es对复杂分布式机制的透明隐藏特性
Elasticsearch是一套分布式的系统,分布式是为了应对大数据量

隐藏了很多复杂的分布式机制:

1.分片机制(我们之前随随便便就将一些document插入到es集群中去了,我们有没有care过数据怎么进行分片的,数据到哪个shard中去)

2.cluster discovery(集群发现机制,我们之前在做那个集群status从yellow转green的实验里,直接启动了第二个es进程,那个进程作为一个node自动就发现了集群,并且加入了进去,还接受了部分数据,replica shard)

3.shard负载均衡(举例,假设现在有3个节点,总共有25个shard要分配到3个节点上去,es会自动进行均匀分配,以保持每个节点的均衡的读写负载请求)

shard副本,请求路由,集群扩容,shard重分配
2.4.2 es的垂直扩容与水平扩容
垂直扩容:采购更强大的服务器, 成本非常高昂,而且会有瓶颈,假设世界上最强大的服务器容量就是10T,但是当你的总数据量达到5000T的时候,你要采购多少台最强大的服务器啊

水平扩容:业界经常采用的方案,采购越来越多的普通服务器,性能比较一般,但是很多普通服务器组织在一起,就能构成强大的计算和存储能力

普通服务器:1T,1万,100万
强大服务器:10T,50万,500万

扩容对应用程序的透明性
2.4.3 增减或减少节点时的数据rebalance
保持负载均衡

master节点

(1)创建或删除索引
(2)增加或删除节点
2.4.4 节点平等的分布式架构
(1)节点对等,每个节点都能接收所有的请求
(2)自动请求路由
(3)响应收集

2.5 shard&replica机制再次梳理以及单node环境中创建index图解

1.一个index可以包含一个或多个shard
2.每个shard都是一个最小的单元,承载部分数据,底层就是个lucene实例,完整的建立索引和处理请求的能力
3.增减节点时, shard会自动在nodes中负载均衡
4.primary shard和replica shard,每个document肯定只存在于某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard中
5.replica shard是primary shard 的副本,负责容错,以及承担读请求负载
6.primary shard的数量在创建索引的时候就固定了,replica shard的数量可以随时修改
7.(7.x版本)primary shard的默认数量为1,replica默认是1
8.primary shard是不能和自己的replica shard放在同一个节点上(否则节点宕机,primary shard和副本都丢失,起不到容错的作用),但是可以和其他primary shard 的 replica shard放在同一个节点上
2.5.1 单台node下,创建index是什么样子?
1.单node环境下,创建一个index,有3个primary shard,3个replica shard
2.集群status是yellow
3.这个时候,会将三个primary shard 分配到仅有的一个node上,另外3个replica shard是无法分配的
4.集群可以正常工作,但是一旦出现节点宕机,数据全部丢失,而且集群不可用,无法承接任何请求
PUT /test_index
{
    "settings":{
        "number_of_shards": 3,
         "number_of_replicas": 1  ---->每个shard一个replica副本
    }
}
2.5.2 两台node下,replica shard是如何分配的?
1.replica shard分配:3个primary shard,3个replica shard,1node
2.primary-----> replica 同步
3.读请求: primary/replica 两者都可以承接读请求
2.5.3 图解横向扩容过程,如何超出扩容极限,以及如何提升容错性
1.primary&replica自动负载均衡
2.每个node有更少的shard,IO/CPU/Memory资源给每个shard分配更多,每个shard性能更好
3.扩容的极限,6个sahrd(3 primary,3 replica),最多扩容到6台机器,每个shard可以占用单台服务器的所有资源,性能最好
4.超出扩容极限,动态修改replica的数量,9个shard(3primary 6 replica)扩容到9台机器,比3台机器时,拥有3倍的读吞吐量
5.3台机器小,9个shard(3 primary,6 replica)资源更少,但是容错性更好,最多容纳两台机器宕机,6个shard只能容纳1台机器宕机
2.5.4 图解es容错机制,master选举,replica容错,数据恢复
步骤:
1.9 shard,3node
2.master宕机,自动master选举,red
3.replica容错,新master将replica提升为primary shard,yellow
4.重启宕机node,新master 会 copy relica到该node,使用原有的shard并同步宕机后的修改,green

2.6 初步解析document的核心元数据: _index, _type(8.x版本将完全启用),__id

1._index元数据
(1).代表一个document存在哪个index中
(2).类似的数据放在一个索引,非类似的数据放不同的索引,例: product_index(商品数据) sales_index(销售数据)
(3).index中包含吗了很多类似的document
(4).索引名称必须是小写的,不能用下划线开头,不能包含逗号
2._type元数据(已过时)
(1).代表document属于index中的哪个分类
(2).一个索引通常会划分多个type,逻辑上对index中有些许不同的几类数据进行分类
(3).type名称可以使大小或者小写,但是同时不能用下划线开头,不能包含逗号
3._id元数据
(1).代表document的唯一标识,与index和type一起,可以唯一标识和定位一个document
(2).我们可以动手指定document的id,也可以不指定,由es自动为我们创建一个ID


手动指定document的id:
1.根据应用情况来说,是否满足手动指定document id 的前提
     如果是导入已有数据(例如从数据库中导入),建议手动指定id
自动生成document的id:
     如果是es作为主要存储数据源,那么数据生成后便可以通过es自动来生成id
自动生成的id,长度为20个字符,URL安全,base64编码,GUID,分布式系统并行生成时不可能会发生冲突
2.6.1_document的_source元数据以及定制返回结果解析
1._source元数据: 我们写入的json数据,默认情况下原封不动的在_source结构中响应回来


GET product/_search
{
  "query": {
    "match": {
      "name": "yagao"
    }
  },
  "_source": ["name","desc"]
}
2.6.2__document的全量替换,强制创建以及文档删除等操作的分析
如果写入数据时,document的ID不存在则是新增,存在则是全量替换(es的修改操作其实就是全量替换)
而es做全量替换时,是先将老数据标记为deleted,还并没有物理删除,当内存空间不足时,才会将标记为deleted的数据进行物理删除

强制创建:
PUT test_index/_doc/id/_create
{
  "name":"erlv"
}
2.6.3 ES的并发冲突问题

见图

悲观锁与乐观锁两种并发控制方案

悲观锁:(优点:方便,直接加锁,不需要额外的操作  缺点:并发能力低)
任何情况下,都会对数据上锁,上锁之后,只有持有锁的线程能够操作该条数据,其他线程阻塞,操作完释放锁,此时其他线程读到的一定是最新数据,当然锁的种类有很多,(行锁,表锁,读锁,写锁)

乐观锁:(优点:并发能力高  缺点:代码侵入性高一些)
不加锁,但是每条数据都会有version的概念,两条线程读取同一条数据,版本号皆为 1,但是A线程先修改完数据并将版本号+1,此时B线程提交修改时,发现此时的version已经和他读取数据数据的version不同了,那么B需要重新读取最新数据,再次对数据进行操作,然后再提交


那么ES如何基于_version使用乐观锁进行并发控制的呢?

1.第一次创建document的时候,_version=1,每次对该document做增删改时,version都会+1
2.写入es的数据会由primary shard同步至replica shard中,es内部是多线程异步去改的,那么如果前后两个用户的写入请求乱序了,es内部是会自动把顺序错误的请求抛弃掉,以至于最终修改成功的数据一定是最后发出的请求

(这个用的是version_type=external的方式,这种是可以用外部的版本号来实现乐观锁控制的,每次都请求给出的版本号必须要大于当前_version)
PUT test_index/_doc/9?version=5&version_type=external
{
  "name":"tiancheng"
}

如果发送的版本号没有大于当前版本号,则报错
{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[9]: version conflict, current version [6] is higher or equal to the one provided [5]",
        "index_uuid": "nXU59-OnR8afmwK0_b75aw",
        "shard": "2",
        "index": "test_index"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[9]: version conflict, current version [6] is higher or equal to the one provided [5]",
    "index_uuid": "nXU59-OnR8afmwK0_b75aw",
    "shard": "2",
    "index": "test_index"
  },
  "status": 409
}

在乐观锁成功阻止并发问题之后,尝试正确的完成更新
再次去get 最新的版本号,然后重新发出修改请求携带正确的版本号参数

7.x版本乐观锁实现----------------------------------------------
PUT test_index/_doc/9?if_seq_no=6&if_primary_term=1
{
  "name":"tiancheng_dzt"
}
使用的是seq_no 和 primary_term
2.6.4 partial update
什么是partial update? 其实就是传参传局部字段,es实现document数据的局部字段更新,并非之前的全量替换实现数据的修改(这是表象)
但是es内部其实也是生成一个新的document,然后将field进行更新,再将老的document标记为deleted

优点:减少了网络数据传输的开销
POST test_index/_update/9
{
  "doc": {
    "price": 7891
  }
}
2.6.5grovy脚本实现partial update
es,其实是有个内置的脚本支持的,可以基于grovy脚本实现各种各样的复杂操作

POST test_index/_update/9
{
  "script": "ctx._source.nums+=1"    -----> 把test_index中的document的id=9的数据的nums字段的值+1
}


Groovy存在内存泄露+安全漏洞问题,,7.x版本使用的是painless脚本

2.7剖析document数据路由原理(优化点)

document路由到shard是什么意思?
在es中,1个index会分布在多个shard上,那么当你添加一条数据(也就是document)时,es会将该数据放在index的
哪个shard上呢?这个过程,就称之为document routing,数据路由

路由算法:shard =hash(routing)& number_of_primary_shards

有公式可看出,决定一个document在哪个shard上,最重要的一个值就是routing值,默认是_id,也可以手动指定,相同的routing值,每次过来,从hash函数中产出的hash值一定是相同的,无论hash值是几,无论是什么数字,对number_of_primary_shards求余数,结果一定是在0~number_of_primary_shards-1之间这个范围内的


_id or custom routing value
默认的routing就是id
也可以在发送请求的时候,手动指定一个routing value,比如说put /index/type/id?routing=user_id
手动指定routing value是很有用的,可以保证说,某一类document一定被路由到一个shard上去,那么在后续进行
应用级别的负载均衡,以及提升批量读取的性能的时候,是很有帮助的


primary shard为什么不可变?
就是上述的那样,数据存储到哪个具体的shard上是根据路由算法决定的,同时起到决定性因素的是routingid 和 primary shard的个数,作为同一个数据,如果shard增加了一个后,那么路由算法得出的结果和之前的很可能会不一样,会导致es去错误的shard上取数据,从而也取不到

2.8 document的增删改内部实现原理

1. 客户端发送请求至es,会先任意选择一个node,这个node就是coordinating node(协调节点)
2.coordinating node,对document进行路由,将请求转发给对应的	node(有primary shard)(根据2.7所述路由算法转发)
3.实际的node上的primary shard处理请求,然后将数据同步到replica shard
4.coordinating node,如果发现primary shard 和 replica shard都搞定之后,就返回响应给客户端


document的搜索
截止到第2步骤,和增删改的内部处理都是一样的,但是转发到具体shard时,他会两次发到primary shard,两次发到replica shard,均匀的让这两种shard处理所有读请求,以提升吞吐量

2.9写一致性原理以及quorum机制深入剖析

1.consistency: one(primary shard) all(all shard) quorum(default)
在发送任何增删改操作时,都可以带上一个consistency参数,指明我们想要的写一致性是什么?
post /index/_doc/id?consistency=quorm
one:要求写操作,只要有一个primary shard 是active的,就可以执行这个写操作
all:要求写操作,必须所有的primary shard和replica shard都是活跃的,才可以执行这个写操作
quorum: 要求所有的shard中大部分shard是活跃的,int((primary+number_of_replicas) /2 )+1,当number_of_replicas >1 才生效

2.如果节点少于quorum数量,可能导致quorum不齐全,进而导致无法执行任何写操作
但是在es中,只有number_of_replica>1时,quorum才会生效
3.quorum不齐全时,wait,默认1分钟,timeout,100,30s
post /index/_doc/id?timeout=30(默认毫秒,可以加单位,例:30s) ,可以自定义超时时间


bulk api的奇特json格式与底层性能优化关系大解密

如果用正常的json格式:
例:
{
    "":""
}
1.bulk中的每个操作都可能要转发到不同node的shard去执行
2.如果采用比较良好的json数组格式
 (1). 将json数组解析为JSONArray对象(这个时候在内存中会发生拷贝)
 (2). 对每个请求中的document进行路由
 (3). 为路由到同一个shard上的多个请求,创建一个请求数组
 (4). 将这个请求数组序列化
 (5). 将序列化后的数据发送到对应的节点上去

3.耗费更多内存,更多的jvm gc开销

如果使用es规定的json格式:
{"action":{"":""}}\n
1.直接按照换行符切割json
2.对每两个一组的json,读取meta,进行document路由
3.直接将对应的json发送到node上去
4.不需要将json数组解析为一个JSONArray对象,形成一份大数据的拷贝,浪费内存空间,尽可能的保证性能

3.搜索引擎

3.1 search结果深入解析

3.2 deep paging

当from +size > max_result_window时,es将返回错误

解决方案 1:
1.可以通过设置max_result_window的值来调整es的最大返回记录数(会影响性能,不推荐)
[root@dnsserver ~]# curl -XPUT "127.0.0.1:9200/custm/_settings" -d 
'{ 
    "index" : { 
        "max_result_window" : 50000 
    }
}

解决方案 2: 游标

解决方案 3: search_after (推荐,但不能跳页)
GET asset_test1/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "reportDate": "desc",
      "id":"desc"
    }
  ]
}

GET asset_test1/_search
{
  "query": {
    "match_all": {}
  },
  "size": 2, 
  "search_after":[1611100800000,"*001755D30AC84BC449753AA9FBCC0A93E73285A8"],
  "sort": [
    {
      "reportDate": "desc",
      "id":"desc"
    }
  ]
}

3.3 query String语法 和 _all metadata的原理和作用

1.query String的基础用法
GET asset_test1/_search?q=address:120.202.101.81
GET asset_test1/_search?q=-address:120.202.101.81  field中必须不能包含关键词的数据被搜索出来
GET asset_test1/_search?q=+address:120.202.101.81  field中必须包含关键词的数据被搜索出来


2._all metadata的原理和作用
all元数据,document all fields at index time,支持all fields search
直接可以搜索所有的field,任意一个field包含指定的关键字就可以被搜索出来,
那么难道是对每一个field都进行一次搜索吗? 
不是的,利用es中的_all元数据,插入数据时,es会自动将多个field的值全部用字符串的方式串联起来,变成一个长的字符串,作为_all的值,同时建立索引
GET asset_test1/_search?q=120.202.101.81   q后面直接跟字段的值

3.4 mapping是什么

如果没有设置field的mapping,es会dynamic设置filed的mapping
mapping包含了每个field对应的数据类型,以及如何分词等设置
数据类型
核心数据类型
  • string 字符串

字符类型

说明

text

⽤于全⽂索引,搜索时会自动使用分词器进⾏分词再匹配。字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项

keyword

不分词,搜索时需要匹配完整的值

  • numberic 数值

整数类型

说明 (1byte(字节)=8bit(位、比特))

byte

(1字节)-128 到127(- 2^7 到 2^7– 1)

short

(2字节)-32,768到32,767 (- 2^15 到 2^15– 1)

integer

(4字节)-2,147,483,648到2,147,483,647 (- 2^31 到 2^31– 1)

long

(8字节)(- 2^63 到 2^63– 1)

浮点类型

说明

float

32位单精度IEEE 754浮点类型

double

64位双精度IEEE 754浮点类型

half_float

16位半精度IEEE 754浮点类型

scaled_float

缩放类型的的浮点数(比如价格只需要精确到分,price为57.34的字段缩放因子为100,存起来就是5734)

  • date 日期

日期类型

说明

date

JSON中没有日期类型,所以在ELasticsearch中,日期类型可以是以下几种:
日期格式的字符串:e.g. “2015-01-01” or “2015/01/01 12:10:30”.
long类型的毫秒数( milliseconds-since-the-epoch)
integer的秒数(seconds-since-the-epoch)
  • 1
  • 2
  • 3
  • 4
  • date nanoseconds 日期纳秒

日期纳秒类型

说明

date_nanos

  • boolean 布尔

布尔类型

说明

boolean

true/false

  • binary 二进制

二进制类型

说明

binary

该binary类型接受二进制值作为 Base64编码的字符串

  • range 范围

范围类型

说明

integer_range

一个带符号的32位整数范围,最小值为,最大值为。 -2^31到 2^31-1

float_range

一系列单精度32位IEEE 754浮点值

long_range

一系列带符号的64位整数,最小值为,最大值为。 -2^63 到 2^63-1

double_range

一系列双精度64位IEEE 754浮点值

date_range

自系统时代以来经过的一系列日期值,表示为无符号的64位整数毫秒

ip_range

支持IPv4或 IPv6(或混合)地址的一系列ip值

2 复杂数据类型
  • object 对象

对象类型

说明

object

对象,用于单个JSON对象

  • nested 嵌套

对象类型

说明

array

嵌套JSON对象数组

3 地理数据类型
  • Geo-point 地理位置数据(纬度-经度)

地理位置数据类型

说明

geo_point

geo_point为纬度/经度点

  • Geo-shape 地理形状数据类型

地理形状数据类型

说明

geo_shape

geo_shape映射将geo_json几何对象映射到geo_shape类型,用于多边形等复杂形状

4 专用的数据类型

专用的数据类型

说明

ip

ip用于IPv4和IPv6地址

Completion data type

提供自动完成建议

Token count

计算字符串中令牌的数量

mapper-murmur3

在索引时计算值的哈希并将其存储在索引中

mapper-annotated-text

annotated-text 索引包含特殊标记的文本(通常用于标识命名实体)

Percolator

接受来自query-dsl的查询

Join

为同一索引内的文档定义父/子关系

Rank feature

记录数字功能以提高查询时的点击率

Rank features

记录数字功能以提高查询时的点击率

Dense vector

记录浮点值的密集向量

Sparse vector

记录浮点值的稀疏向量

Search-as-you-type

针对查询进行优化的类文本字段,以实现按需输入完成

Alias

为现有字段定义别名。

Flattened

Allows an entire JSON object to be indexed as a single field

Shape

shape 对于任意笛卡尔几何

Histogram

histogram 用于百分位数聚合的预聚合数值。

Constant keyword

keyword当所有文档具有相同值时的情况的 专业化。

3.5 精确匹配和全文搜索的对比分析

1.exact value
 搜索的字段值必须完全相等才能搜索出来
 
2.full text
  (1)缩写 vs 全程:cn vs china
  (2)格式转化: like liked likes
  (3)大小写: Tom vs tom
  (4)同义词: like vs love
  
  可以对值进行拆分后匹配,也可以通过 缩写,时态,大小写,同义词进行匹配

3.6 倒排索引核心原理

normalization 建立倒排索引的时候,会执行一个操作,也就是说对拆分出的各个单词进行相应的处理,以提升后面搜索的时候能够搜索到相关联的文档的概率

什么是分词器?

3.7 query与filter深入对比: 相关度 性能

filter ,仅仅只是按照搜索条件过滤出需要的数据而已

query,会去计算每个document相对于搜索条件的相关度,并按照相关度进行排序
一般来说,如果你是在进行搜索,需要将最匹配搜索条件的数据先返回,那么用query,如果你只是想根据一些条件筛选出
一部分数据,不关注其排序,那么用filter

两者性能对比:
filter:不需要计算相关度分数,不需要按照相关度分数进行排序,同时还有内置的自动cache最常用filter的功能
query: 相反,要计算相关度分数,按照分数进行排序,而且无法cache结果

3.8 解决字符串排序问题

如果对一个string field进行排序,结果往往不准确,因为分词后是多个单词,再排序就不是我们想要的结果了,
通常解决方案是,将一个string field建立两次索引,一个分词,用来进行搜索,一个不分词,用来排序


我们可以对这个字段创建映射的时候,建两个索引,一个正常的倒排索引,一个正排索引,并且如果想对string字段进行排序,需要将filedata设置为true
例如:
{
    mappings:{
        properties:{
            "name":"text aa bb",
            "fields":{
                "raw":{
                    "type":"keyword"
                }
            },
            "filedata": true
        }
    }
}

然后排序的时候,就可以用name.row来进行排序,可以看到name的值有可能会被分词,那么name.row就是用整个字段在排序
GET XXX/_search
{
    "query":{
        "match_all":{}
    },
    "sort":[
        {
            "name.row": "desc"
        }
    ]
}

3.9 相关度评分的算法解密

算法介绍:
ES使用的是 term frequency/inverse document frequency算法,简称为TF/IDF算法
term frequency:搜索本文中的各个词条在field中出现了多少次,出现次数越多,就越相关 
(按搜索内容出现的次数加分)

Inverse document frequency:搜索文本中的各个词条在整个索引的所有文档中出现了多少次,出现的次数越多,就越不相关
()

Field-length norm:field 长度,field越长,相关度越弱
_score是如何被计算出来的

get /idnex/_search?explain 可以查看评分是如何算出来的

3.10 doc value

搜索的时候,要依靠倒排索引,排序的时候,需要依靠正排索引,看到每个document的每个field,然后进行排序,所谓的正排索引,其实就是doc values在建立索引的时候,一方面会建立倒排索引,以供搜索用;一方面会建立正排索引,也就是
doc values,以供排序,聚合,过滤等操作使用.
doc value 是被保存在磁盘上的,此时如果内存足够,os会自动将其缓存在内存中,性能还是会很高,如果内存不足够,os
会将其写入磁盘上.

4.检索及聚合API

面向文档的搜索分析引擎

(1)应用系统的数据结构都是面向对象的,复杂的
(2)对象数据存储到数据库中,只能拆解开来,变为扁平的多张表,每次查询的时候还得还原回对象格式,相当麻烦
(3)ES是面向文档的,文档中存储的数据结构,与面向对象的数据结构是一样的,基于这种文档数据结构,es可以提供复杂的索引,全文检索,分析聚合等功能
(4)es的document用json数据格式来表达

        总结一句话:  es面向文档,复杂的数据结构可以直接以复杂的形式存进es中

4.1.简单的集群管理

(1)快速检查集群的健康状况

es提供了一套api,叫做cat api,可以查看es中各种各样的数据

green:每个索引的primary shard和replica shard都是active状态的

yellow:每个索引的primary shard都是active状态的,但是部分replica shard不是active状态,处于不可用的状态

red:不是所有索引的primary shard都是active状态的,部分索引有数据丢失了

GET /_cat/health?v

epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent

1488006741 15:12:21  elasticsearch yellow          1         1      1   1    0    0        1             0                  -                 50.0%

epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent

1488007113 15:18:33  elasticsearch green           2         2      2   1    0    0        0             0                  -                100.0%

epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent

1488007216 15:20:16  elasticsearch yellow          1         1      1   1    0    0        1             0                  -                 50.0%

如何快速了解集群的健康状况?green、yellow、red?

green:每个索引的primary shard和replica shard都是active状态的

yellow:每个索引的primary shard都是active状态的,但是部分replica shard不是active状态,处于不可用的状态

red:不是所有索引的primary shard都是active状态的,部分索引有数据丢失了

为什么现在会处于一个yellow状态?

我们现在就一个笔记本电脑,就启动了一个es进程,相当于就只有一个node。现在es中有一个index,就是kibana自己内置建立的index。由于默认的配置是给每个index分配5个primary shard和5个replica shard,而且primary shard和replica shard不能在同一台机器上(为了容错)。现在kibana自己建立的index是1个primary shard和1个replica shard。当前就一个node,所以只有1个primary shard被分配了和启动了,但是一个replica shard没有第二台机器去启动。

做一个小实验:此时只要启动第二个es进程,就会在es集群中有2个node,然后那1个replica shard就会自动分配过去,然后cluster status就会变成green状态。

(2)快速查看集群中有哪些索引

GET /_cat/indices?v

health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size

yellow open   .kibana rUm9n9wMRQCCrRDEhqneBg   1   1          1            0      3.1kb          3.1kb

(3)简单的索引操作(7.4.2版本 创建索引默认shard和replica 都是1个)

创建索引:PUT /test_index?pretty

health status index                           uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .monitoring-kibana-7-2021.01.23 c33ZPct_STeNqsZbUQ1qqA   1   0       8638            0      2.5mb          2.5mb
yellow open   cmdi                            D0EfxtOMSI2Ok8PQIE1S3g   1   1          2            0     12.7kb         12.7kb

删除索引:DELETE /test_index?pretty

health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size

yellow open   .kibana rUm9n9wMRQCCrRDEhqneBg   1   1          1            0      3.1kb          3.1kb

创建索引

PUT product
{
  "mappings": {
    "properties": {
      "desc" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "price" : {
          "type" : "long"
        },
        "producer" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "tags" : {
          "type": "text",
        "fielddata": true
        }
    }
  }
}

集群环境创建索引

PUT test1
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "age":{
        "type": "long"
      },
      "address":{
        "type":"keyword"
      }
    }
  }
}

修改索引映射

修改原本已存在的字段的映射是不被允许的,但是新增一个字段的映射是允许的
PUT test_index/_mapping
{
  "properties": {
    "new_field": {
      "type": "text"
    }
  }
}


1.先创建一个新的索引及映射
xxx
2.使用reindex将老索引里的数据迁移至新索引中
POST _reindex
{
  "source": {
    "index": "product"
  },
  "dest": {
    "index": "product_new"
  }
}

4.2数据的CRUD操作

1)新增商品:新增文档,建立索引

es会自动建立index和type,不需要提前创建,而且es默认会对document每个field都建立倒排索引,让其可以被搜索

PUT /index/type/id
{
  "json数据"
}

POST /product/_doc/1

{
  "_index": "ecommerce",
  "_type": "product",
  "_id": "1",
  "_version": 1, (************涉及到es的乐观锁的并发控制策略)
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "created": true
}

POST /product/_doc/2
{
    "name" : "jiajieshi yagao",
    "desc" :  "youxiao fangzhu",
    "price" :  25,
    "producer" :      "jiajieshi producer",
    "tags": [ "fangzhu" ]
}

POST /product/_doc/3
{
    "name" : "zhonghua yagao",
    "desc" :  "caoben zhiwu",
    "price" :  40,
    "producer" :      "zhonghua producer",
    "tags": [ "qingxin" ]
}
通过id查询文档
GET /product/_doc/id
通过id删除文档
DELETE  /product/_doc/id

4.3检索

query DSL

DSL: Domain Specifield Language  特定领域的语言
搜索全部

GET product/_search

结果:
took:耗费了几毫秒
timed_out:是否超时,这里是没有
_shards:数据拆成了1个分片,所以对于搜索请求,会打到所有的primary shard(或者是它的某个replica shard也可以)
hits.total:查询结果的数量,3个document
hits.max_score:score的含义,就是document对于一个search的相关度的匹配分数,越相关,就越匹配,分数也高
hits.hits:包含了匹配搜索的document的详细数据
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "name" : "zhonghua yagao",
          "desc" : "caoben zhiwu",
          "price" : 40,
          "producer" : "zhonghua producer",
          "tags" : [
            "qingxin"
          ]
        }
      }
    ]
  }
}
搜索name有yagao的按照 价格排序 并分页
GET product/_search
{
  "query": {
    "match": {
      "name": "yagao"
    }
  }, 
  "sort": [
    {
      "price": {
        "order": "desc"
      }
    }
  ],
  "from": 1,
  "size": 1
}
指定返回字段
GET product/_search
{
  "query": {
    "match": {
      "name": "yagao"
    }
  },
  "_source": ["name","desc"]
}
query filter

range 可以放在query里,也可以放在filter里,区别是filter查的话不会计算相关度的评分

如果直接使用filter不用bool的话,可以用constant_score

GET product/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "yagao"
          }
        }
      ], 
      "filter": {
        "range": {
          "price": {
            "gte": 32,
            "lte": 40
          }
        }
      }
    }
  }
}

GET /test1/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "address": "dzt is good"
        }
      },
      "boost": 1.2
    }
  }
}
全文检索

结果:
通过name搜索值为 “yagao”,文档中本身所有数据的name都包含 “yagao”,所以看见结果每条数据的评分都差不多

但通过 producer搜索 值为 “yagao producer”,可以发现ID为4的数据评分明显最高,因为其匹配程度最高,因为他的

producer字段 能够匹配上搜索条件中的两个词,其他只能匹配到一个

GET product/_search
{
  "query": {
    "match": {
      "name": "yagao"
    }
  }
}


"hits" : [
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.105360515,
        "_source" : {
          "name" : "zhonghua yagao",
          "desc" : "caoben zhiwu",
          "price" : 40,
          "producer" : "zhonghua producer",
          "tags" : [
            "qingxin"
          ]
        }
      },
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.105360515,
        "_source" : {
          "name" : "jiajieshi yagao",
          "desc" : "youxiao fangzhu",
          "price" : 25,
          "producer" : "jiajieshi producer",
          "tags" : [
            "fangzhu"
          ]
        }
      },
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.105360515,
        "_source" : {
          "name" : "dzt yagao",
          "desc" : "dzt fangzhu",
          "price" : 99,
          "producer" : "dzt yagao producer",
          "tags" : [
            "meibai"
          ]
        }
      },
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.105360515,
        "_source" : {
          "name" : "gaolujie yagao",
          "desc" : "gaoxiao meibai",
          "price" : 30,
          "producer" : "gaolujie producer",
          "tags" : [
            "meibai",
            "fangzhu"
          ]
        }
      }
    ]
    
    
    
GET product/_search
{
  "query": {
    "match": {
      "producer": "yagao producer"
    }
  }
}

"hits" : [
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.1522135,
        "_source" : {
          "name" : "dzt yagao",
          "desc" : "dzt fangzhu",
          "price" : 99,
          "producer" : "dzt yagao producer",
          "tags" : [
            "meibai"
          ]
        }
      },
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.110377684,
        "_source" : {
          "name" : "zhonghua yagao",
          "desc" : "caoben zhiwu",
          "price" : 40,
          "producer" : "zhonghua producer",
          "tags" : [
            "qingxin"
          ]
        }
      },
multi_match
GET test_index/_search
{
  "query": {
    "multi_match": {
      "query": "erlv",
      "fields": ["name","hobby"]
    }
  }
}
短语搜索(phrase search)

解释:跟全文检索相反,全文检索会将输入的搜索串拆解开来,去倒排索引里一一匹配,只要匹配上搜索串中任意一个单词,就可以作为结果返回,

而短语搜索要求 输入的搜索串必须完整的存在于结果集的查询字段中,才可以算匹配,可以看到下方只有一个结果匹配上了

GET product/_search
{
  "query": {
    "match_phrase": {
      "producer": "yagao producer"
    }
  }
}

结果:
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.1522135,
    "hits" : [
      {
        "_index" : "product",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.1522135,
        "_source" : {
          "name" : "dzt yagao",
          "desc" : "dzt fangzhu",
          "price" : 99,
          "producer" : "dzt yagao producer",
          "tags" : [
            "meibai"
          ]
        }
      }
    ]
  }
高亮检索
GET product/_search
{
  "query": {
    "match": {
      "producer": "producer"
    }
  },
  "highlight": {
    "fields": {
      "producer": {
        "pre_tags": "<b style='color:red'>",
        "post_tags": "</b>"
      }
    }
  }
}
还可以在高亮之后的结果继续对某个字段的某个值进行高亮
GET product/_search
{
  "query": {
    "match": {
      "producer": "producer"
    }
  },
  "highlight": {
    "fields": {
      "producer": {
        "pre_tags": "<b style='color:red'>",
        "post_tags": "</b>",
        "highlight_query":{
            "xxxx":"xxx"
        }
      }
    }
  }
}
精准检索
terms:多值检索
GET asset_test1/_search
{
  "query": {
    "bool": {
      "filter": {
        "terms": {
          "address": [
            "111.44.212.39",
            "111.8.210.52"
          ]
        }
      }
    }
  }
}

term:单值检索 
GET asset_test1/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "address": "111.11.70.13"
        }
      }
    }
  }
}
检查DSL语句是否合法
GET test_index/_validate/query?explain
{
  "query": {
    "multi_match": {
      "query": "erlv",
      "fields": ["name","hobby"]
    }
  }
}
4.3.1批量查询->mget
不同索引的批量查询:
GET /_mget
{
  "docs": [
    {
      "_index":"test_index",
      "_id" : "7SZwV3cBOZpjf8ZFfV8Q"
    },
    {
      "_index":"test_index",
      "_id" : "XiZwV3cBOZpjf8ZF-mBR"
    }
  ]
}


同索引的批量查询:
GET /test_index/_mget
{
    "ids": ["7SZwV3cBOZpjf8ZFfV8Q","XiZwV3cBOZpjf8ZF-mBR"]
}


结果:
{
  "docs" : [
    {
      "_index" : "test_index",
      "_type" : "_doc",
      "_id" : "7SZwV3cBOZpjf8ZFfV8Q",
      "_version" : 1,
      "_seq_no" : 0,
      "_primary_term" : 1,
      "found" : true,
      "_source" : {
        "name" : "zhangsan"
      }
    },
    {
      "_index" : "test_index",
      "_type" : "_doc",
      "_id" : "XiZwV3cBOZpjf8ZF-mBR",
      "_version" : 4,
      "_seq_no" : 3,
      "_primary_term" : 1,
      "found" : true,
      "_source" : {
        "name" : "erlv"
      }
    }
  ]
}

3.3.2批量操作->bulk

POST /_bulk
{"delete":{"_index":"test_index","_id":"7SZwV3cBOZpjf8ZFfV8Q"}}
{"create":{"_index":"test_index","_id":"12"}}
{"name":"qqq","price":99}
{"index":{"_index":"test_index","_id":"2"}}
{"test_field":"replaced test2"}
{"update":{"_index":"test_index","_id":"9"}}
{"doc":{"test_field2":"bulk test1"}}

发送请求时,每个json整体必须在同一行
bulk操作中,任意一个操作失败是不会影响其他操作的,响应体中会返回错误响应

bulk size 最佳大小
如果太大的话,性能反而会下降,因此需要反复测试一个最佳的bulk size,一般从1000-5000条数据开始,尝试逐步添加,
另外大小的话,最好是在5-15mb
fuzzy查询
GET /test1/_search
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "welcomm",
        "fuzziness": 1   #表示对查询的值做几次调整,值不能大于2
      }
    }
  }
}
推荐搜索
#默认情况下,如果搜索的内容在es中是存在的那么es就不会推荐内容出来, suggest_mode=missing
#建议模式设置为always,代表即便你输入的内容已经在es中存在,还是会把他的相应推荐给推荐出来
#suggest_mode=popular  推荐和我们搜索内容更像的比较常见的

GET test1/_search
{
  "suggest": {
    "title_suggest": {
      "text": "welco",
      "term": {
        "field": "name",
        "suggest_mode":"always"   
      }
    }
  }
}
自动补全
自动补全的功能对性能的要求比较高,用户每发送输入一个字符就要发送一个请求去查找匹配项,ES采取了不同的数据结构来实现,并不是通过倒排索引来实现的,需要将对应的数据类型设置为   "completion",
所以在将数据索引引进ES之前需要先定义mapping信息

get xxx/_search
{
    "suggest":{
        "xxxx_suggest":{
            "prefix": "小",
            "completion":{
                "field":"title",
                 "skip_duplicates": true   #有时es返回的补全数据可能会有重复的,此配置设置为true,去重
            }
        }
    }
}
搜索多个字段,且必须有一个满足查询条件才被检索出来
(bool复合查询,must里面套should)

GET /infomation/_search
{
  "query": {
   "bool": {
     "must": [
       {
         "bool": {
           "should": [
             {
               "match_phrase": {
                 "content": "奥特曼"
               }
             },
             {
               "match_phrase": {
                 "label": "奥特曼"
               }
             },
             {
               "match_phrase": {
                 "title": "奥特曼"
               }
             }
           ]
         }
       }
     ],
     "filter": {
       "term": {
         "status": 0
       }
     }
   }
    
  }
}

4.4聚合

terms
#tags为数组,那么需要该字段的filedata=true才可以通过该字段进行聚合分析
GET product/_search
{
  "size": 0, 
  "aggs": {
    "tag_proCount": {
      "terms": {
        "field": "tags"
      }
    }
  }
}

结果:
 "aggregations" : {
    "tag_proCount" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "fangzhu",
          "doc_count" : 2
        },
        {
          "key" : "meibai",
          "doc_count" : 2
        },
        {
          "key" : "qingxin",
          "doc_count" : 1
        }
      ]
    }
  }
term后计算每组的avg价格 降序排序
GET product/_search
{
  "size": 0,
  "aggs": {
    "tag_proCount": {
      "terms": {
        "field": "tags",
        "order": {
          "avg_price": "desc"
        }
      },
      "aggs": {
        "avg_price": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

结果:
  "aggregations" : {
    "tag_proCount" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "meibai",
          "doc_count" : 2,
          "avg_price" : {
            "value" : 64.5
          }
        },
        {
          "key" : "qingxin",
          "doc_count" : 1,
          "avg_price" : {
            "value" : 40.0
          }
        },
        {
          "key" : "fangzhu",
          "doc_count" : 2,
          "avg_price" : {
            "value" : 27.5
          }
        }
      ]
    }
  }
按照指定的价格区间进行分组,然后在每组内再按照tag进行分组,再求平均价格
GET product/_search
{
  "size": 0,
  "aggs": {
    "range_price": {
      "range": {
        "field": "price",
        "ranges": [
          {
            "from": 0,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          },
          {
            "from": 40,
            "to": 100
          }
        ]
      },
      "aggs": {
        "groupby_tags": {
          "terms": {
            "field": "tags"
          },
          "aggs": {
            "avg_price": {
              "avg": {
                "field": "price"
              }
            }
          }
        }
      }
    }
  }
}
通过搜索条件聚合并在聚合内再次根据条件聚合(聚合内filter过滤)
##################大屏态势感知########################
GET asset_test1/_search
{
  "size": 0
}

#大屏资产安全监测
GET asset_test1/_search
GET asset_test1/_search
{
  "size": 0, 
  "query": {
    "match_all": {}
  },
  "aggs": {
    "level_normal": {
      "filter": {
        "term": {
          "cntLoophole": 0
        }
      }
    },
    "level_high":{
      "filter": {
        "nested": {
          "path": "cveEsModelList",
          "query": {
            "term": {
              "cveEsModelList.serverity": {
                "value": "高"
              }
            }
          }
        }
      }
    },
    "level_medium":{
      "filter": {
        "nested": {
          "path": "cveEsModelList",
          "query": {
            "bool": {
              "must_not": [
                {
                  "term": {
                    "cveEsModelList.serverity": {
                      "value": "高"
                    }
                  }
                }
              ],
              "should": [
                {
                  "term": {
                    "cveEsModelList.serverity": {
                      "value": "中"
                    }
                  }
                },
                {
                  "term": {
                    "cveEsModelList.serverity": {
                      "value": "低"
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
  }
}


#上报资产/稽核资产/总资产数 统计
GET asset_test1/_search
{
  "size": 0,
  "query": {
    "match": {
      "status": 1
    }
  },
  "aggs": {
    "assetByReported": {
      "filter": {
        "term": {
          "source": 3 
        }
      }
    },
    "assetNum": {
      "cardinality": {
        "field": "id"
      }
    },
    "assetByAudit":{
      "filter": {
        "term": {
          "source": 1
        }
      }
    }
  }
}
#上报/稽核资产近一年折线图

GET /asset_test1/_search
{
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "reportDate": {
              "gte": "2020-01-01",
              "lte": "2020-12-31"
            }
          }
        }
      ]
    }
  },
  "aggs": {
    "all_report": {
      "filter": {
        "term": {
          "source": 3
        }
      },
      "aggs": {
        "reportAmountList": {
          "date_histogram": {
            "field": "reportDate",
            "calendar_interval": "month",
            "format": "yyyy-MM-dd",
            "min_doc_count": 0,
            "extended_bounds": {
              "min": "2020-01-01",
              "max": "2020-12-31"
            }
          }
        }
      }
    },
    "all_audit":{
      "filter": {
        "term": {
          "source": 1
        }
      },
      "aggs":{
        "auditAmuountList": {
          "date_histogram": {
            "field": "reportDate",
            "calendar_interval": "month",
            "format": "yyyy-MM-dd",
            "min_doc_count": 0,
            "extended_bounds": {
              "min": "2020-01-01",
              "max": "2020-12-31"
            }
          }
        }
      }
    }
  }
}
聚合查询(top_hits,range,histogram,min_bucket)
#查询年龄最大的两位员工的信息
GET employee/_search
{
    "size": 0,
    "aggs":{
        "order_agg":{
            "top_hits":{
                "size": 2,
                "sort":[
                    {
                        "age":{
                            "order":"desc"
                        }
                    }
                ]
            }
        }
    }
}

#查询不同工资区间的员工工资的统计信息 
GET /test1/_search
{
  "size": 0,
  "aggs": {
    "range_sal_agg": {
      "range": {
        "field": "sal",
        "ranges": [
          {
            "key": "0 <= sal <10001",
            "to": 10001
          },
          {
            "key": "10001 <= sal 20001",
            "from": 10001, 
            "to": 20001
          }
        ]
      }
    }
  }
}

#以直方图的方式以每5000元为一个区间查询员工工资信息
GET /test1/_search
{
  "size": 0,
  "aggs": {
    "range_sal_agg": {
      "histogram": {
        "field": "price",
        "interval": 5000,
        "extended_bounds": {   #设置区间的最大最小值
          "min": 0,
          "max": 50000
        }
      }
    }
  }
}

#查询平均工资最低的工种
GET /test1/_search
{
  "size": 0,
  "aggs": {
    "range_sal_agg": {
      "terms": {
        "field": "gongzhong"
      },
      "aggs": {
        "avg_agg": {
          "avg": {
            "field": "sal"
          }
        }
      }
    },
    "min_avg_sal":{
      "min_bucket": {
        "buckets_path": "range_sal_agg>avg_agg"   #得出range_sal_agg>avg_agg聚合结果汇总值最小的桶
      }
    }
  }
}

5资产检索实现深度分页

#################资产检索实现深度分页##########################################


GET asset_test1/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "reportDate": "desc",
      "id":"desc"
    }
  ]
}

GET asset_test1/_search
{
  "query": {
    "match_all": {}
  },
  "size": 2, 
  "search_after":[1611100800000,"*001755D30AC84BC449753AA9FBCC0A93E73285A8"],
  "sort": [
    {
      "reportDate": "desc",
      "id":"desc"
    }
  ]
}

6.es集群(7.4.2)安装(docker)

启动命令:

242
docker run -d --name es01 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node"  -e ES_JAVA_OPTS="-Xms64m -Xmx128m" -v /opt/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /opt/es/data:/usr/share/elasticsearch/data -v /opt/es/plugins:/usr/share/elasticsearch/plugins --restart=always elasticsearch:7.4.2
243 231

docker run -d --name es01 -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms4g -Xmx4g" -v /opt/nssa/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /opt/nssa/es/data:/usr/share/elasticsearch/data -v /opt/nssa/es/plugins:/usr/share/elasticsearch/plugins --restart=always elasticsearch:7.4.2

报错:

bound or publishing to a non-loopback or non-link-local address, enforcing bootstrap checks ERROR: [2] bootstrap checks failed**

切换到root用户修改配置sysctl.conf

vi /etc/sysctl.conf 
添加配置:
vm.max_map_count=655360

执行命令:
sysctl -p

yml文件说明:

参数

说明

cluster.name

集群名称,相同名称为一个集群

node.name

节点名称,集群模式下每个节点名称唯一

node.master

当前节点是否可以被选举为master节点,是:true、否:false

node.data

当前节点是否用于存储数据,是:true、否:false

path.data

索引数据存放的位置

path.logs

日志文件存放的位置

bootstrap.memory_lock

需求锁住物理内存,是:true、否:false

bootstrap.system_call_filter

SecComp检测,是:true、否:false

network.host

监听地址,用于访问该es

network.publish_host

可设置成内网ip,用于集群内各机器间通信

http.port

es对外提供的http端口,默认 9200

discovery.seed_hosts

es7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点

cluster.initial_master_nodes

es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举master

http.cors.enabled

是否支持跨域,是:true,在使用head插件时需要此配置

http.cors.allow-origin

“*” 表示支持所有域名

配置文件:

cluster.name: nssa_elasticsearch
node.name: es243
network.bind_host: 0.0.0.0
network.publish_host: 192.168.182.243
http.port: 9200
transport.tcp.port: 9300
http.cors.enabled: true
http.cors.allow-origin: "*"
node.master: false
node.data: true
discovery.seed_hosts: ["192.168.182.242:9300","192.168.182.243:9300","192.168.182.231:9300"]
cluster.initial_master_nodes: ["192.168.182.242:9300"]

安装kibana

docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.124.15:9200 -p 5601:5601 -d kibana:7.4.2

安装logstash

1.配置文件 (新建文件 /xxx/logstash.conf )

input {
	tcp {
		mode => "server"
		host => "0.0.0.0"
		# 接收服务发送过来的日志端口,随意改,别重复就好
		port => 5000
		codec => json_lines
	}
}
output {
	elasticsearch {
		# 自己es装的地方
		hosts => ["192.168.182.243:9200"]
		action => "index"
		# 索引 kibana创建索引时使用,根据自己心情来,最好有意义,我是我的网站服务名log+时间节点
		index => "dscnlog-%{+YYYY.MM.dd}"
	}
	stdout {
		codec => rubydebug
	}
}

启动命令

docker run --name logstash -p 5000:5000 \
-v /data/logstash/logstash.conf:/etc/logstash.conf \
--link es01:elasticsearch \
-d logstash:7.4.2 \
logstash -f /etc/logstash.conf

微服务中

<!-- 日志集中管理 -->
        <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
            <version>5.2</version>
        </dependency>
        
    创建logback.xml
    <?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="1 seconds">
	<!-- 作用域就是spring的上下文环境中,后面是服务名,defaultValue不填就可以了,之后就是打印对应的服务名 -->
    <springProperty scope="context" name="applicationName" source="spring.application.name" defaultValue=""/>
    <include resource="org/springframework/boot/logging/logback/base.xml" />
    <appender name="stash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
    	<!-- logstash远程主机 -->
        <destination>192.168.182.243:5000</destination>
        <!-- encoder必须配置,有多种可选 -->
        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" />
    </appender>
	<!-- 日志输出级别 -->
    <root level="info">
        <appender-ref ref="stash" />
    </root>
</configuration>

在kibana中创建index patterns(索引模式)

初步检索

1._cat

GET /_cat/nodes; 查看所有节点

GET /_cat/health; 查看es健康状况

GET /_cat/master;查看主节点

GET /_cat/indlices; 查看所有索引  ==== show databases;
PUT infomation
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "status":{
        "type":"integer"
      },
      "label":{
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "publish": {
        "type": "date",
        "format": [
          "yyyy-MM-dd"
        ]
      }
    }
  }
}

#研报
PUT report
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "status":{
        "type":"integer"
      },
      "label":{
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "publish": {
        "type": "date",
        "format": [
          "yyyy-MM-dd"
        ]
      }
    }
  }
}

#视频
PUT media
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "mediaStatus":{
        "type":"integer"
      },
      "label":{
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "publish": {
        "type": "date",
        "format": [
          "yyyy-MM-dd HH:mm:ss"
        ]
      },
      "image":{
        "type":"keyword"
      },
      "category":{
        "type": "integer"
      },
      "startTime":{
        "type": "date",
        "format": [
          "yyyy-MM-dd HH:mm:ss"
        ]
      },
      "vid":{
        "type": "keyword"
      }
    }
  }
}

temp

GET _search
{
  "query": {
    "match_all": {}
  }
}


PUT demo1
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      }
    }
  }
  
}

PUT demo1/_doc/1
{
  "name":"zhangsan"
}


GET demo1/_search

PUT /test
{
  "mappings": {
    "properties": {
      "title":{"type": "text"},
      "name":{"type": "text"},
      "age":{"type": "integer"},
      "created":{
        "type": "date",
        "format": "strict_date_optional_time||epoch_millis"
      }
    }
  },
  "settings": {
    "index":{
      "number_of_shards":1,
      "number_of_replicas":0
    }
  }
}


PUT /test/_doc/5
{
  "name":"zw",
  "title":"张五",
  "age":28,
  "created":"2020-11-01"
}


GET test/_search




PUT infomation
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "status":{
        "type":"integer"
      },
      "label":{
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "publish": {
        "type": "date",
        "format": [
          "yyyy-MM-dd"
        ]
      }
    }
  }
}

#研报
PUT report
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "status":{
        "type":"integer"
      },
      "label":{
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "publish": {
        "type": "date",
        "format": [
          "yyyy-MM-dd"
        ]
      }
    }
  }
}

#视频
PUT media
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "title": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "mediaStatus":{
        "type":"integer"
      },
      "label":{
        "type": "text",
        "analyzer": "ik_max_word", 
        "search_analyzer": "ik_smart"
      },
      "publish": {
        "type": "date",
        "format": [
          "yyyy-MM-dd HH:mm:ss"
        ]
      },
      "image":{
        "type":"keyword"
      },
      "category":{
        "type": "integer"
      },
      "startTime":{
        "type": "date",
        "format": [
          "yyyy-MM-dd HH:mm:ss"
        ]
      },
      "vid":{
        "type": "keyword"
      }
    }
  }
}

POST /infomation/_doc/888
{
  "id": "888",
  "title":"疫情反弹持续引发担忧 成品油价23日下跌,来了",
  "content": "奥特曼",
  "status": 0,
  "label":"sad",
  "publish":"2020-06-24"
}

POST /infomation/_doc/77711
{
  "id": "77711",
  "title":"新冠疫情反弹持续引发担忧 国际油价23日下跌",
  "status": 0,
  "label":"奥特曼",
  "content": "天成集团",
  "publish":"2020-06-24"
}


GET /infomation/_search
{
  "query": {
    "multi_match": {
      "query": "奥特曼",
      "fields": ["title","content","label"]
    }
  },
  "track_total_hits": true
}

#研报
POST /report/_doc/gdfterte
{
  "id": "gdfterte",
  "title":"研报天然气下跌亏损 国际油价23日下跌",
  "status": 0,
  "label":"aaaa",
  "content": "奥特曼",
  "publish":"2020-06-24"
}

GET /report/_search
{
  "query": {
    "multi_match": {
      "query": "奥特曼",
      "fields": ["title","content","label"]
    }
  },
  "track_total_hits": true
}

##视频
POST /media/_doc/56756875
{
  "id": "56756875",
  "title":"视频天然气下跌亏损 国际油价23日下跌奥特曼",
  "status": 1,
  "label":"dsfs",
  "content": "aaa",
  "publish":"2020-06-24 18:17:17",
  "image":"dsadasdasdasdad",
  "category":2,
  "startTime": "2021-01-01 19:19:19",
  "vid": "342423",
  "mediaStatus": 1
}

GET /report/_search
{
  "query": {
    "multi_match": {
      "query": "奥特曼",
      "fields": ["title","content","label"]
    }
  },
  "track_total_hits": true
}

GET /infomation/_search

GET /report/_search

GET /media/_search


DELETE /infomation

DELETE /report

DELETE /media



PUT _cluster/settings
{
  "persistent": {
    "indices": {
      "breaker": {
        "fielddata.limit": "60%"
      }
    }
  }
}