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