ElaticSearch:分布式开源搜索和分析引擎

ES简介:

近实时存储、检索数据,集群可达百台,可处理PB级的数据,使用java并使用lucene做为基础,使用restAPI的形式来简化lucene的复杂.

功能:

分布式搜索引擎;全文检索;数据分析引擎(分组聚合);对海量数据进行实时更新;

特点:

安装方便;JSON格式;RestAPI操作;分布式,加入节点自动均衡;多租户,不同用户可建立不同索引;实时处理PB级数据;

使用场景:

搜索类:大网站搜索;
日志分析:ELK组合,ES、logstash、Kibana,日志存储分析;
数据预警平台和数据分析场景:电商类网站的价格机制、热点数据的嗅探
商业BI系统:大型销售系统的数据的分析与展示.

案例:

各种百科,全文检索
stack overflow:全文检索
git hub:管理那么多代码
ELK日志分析系统:很成熟的日志框架

与主流搜索进行对比:

lucene:一个jar包型得框架
solr也是基于lucene开发的http接口的查询服务器,用zookeeper做分布式的管理;官方提供的功能完整;
ES更专注于核心的功能-搜索,其他一些功能都由第三方提供,而且ES自带分布式管理功能,无需zookeeper等注册中心.
在传统搜索中Solr更合适,实时搜索的话ES更胜一筹;
在选型方面,ES还是更被推荐.

ES版本介绍:

主流版本为5、6、7;
7.x版本的变化:TransportClinet被弃用,使用新的restClient,实现为high-level rest Client数据存储结构变化:简化了Type,索引不再有类型之分,6中规定索引只能有一个类型,7中将类型统一边成了_doc型,8可能会彻底删除索引的type,随之带来的API请求将会受到影响:get index/_doc/id,这其中的_doc原来是索引类型,现在就是固定了7之后默认打包了JDK,不用单独安装JDK了.默认节点为主机名,默认分片数为1底层的lucene升级为lucene,在查询品种算法上进行了优化, top N的查询间隔查询,对intervals query允许在查询时进行精确控制查询词在文档中出现的先后关系,实现了对terms顺序、terms之间的距离以及他们之间的包含关系灵活控制;引入了新的集群协调子系统,删除minimum_master_nodes参数,ES可以选择仲裁的节点不再会有OOM的情况,JVM有了新的熔断机制,查询或聚合的数据量超出单机处理最大内存限制会被熔断,indices.breaker.fielddata.limit默认从60%降低到40%分片搜索空闲时间挑过refresh刷新,原来是每秒都要refresh

单节点部署流程:

7.3不支持CentOS 8,7是兼容性比较好的;
官方下载ES,解压安装;
https://www.elastic.co/cn/elasticsearch/ ES官网
ES不使用root启动,所以服务器如果自带了JDK,那么环境变量是针对root用户的,所以要注意一下,手动安装一下就可避免这个问题;
安装JDK后配置环境变量;
配置ES中的config的elasticsearch.ymlnode.name: node1network.hosthttp.port: 9200cluster.initial_master_nodes: [node1]
配置config的jvm.options的jvm参数,服务器不行,改小点 512MB 不能再小了;
添加es专用账户;
给es目录授权给新建账户;
修改linux系统配置 /etc/sysctl.conf,添加 vm.max.map_count=655360,sysctl -p生效;
修改/etc/security/limit.conf,添加soft nofile 65536hard nofile 65536soft nproc  4096hard nproc 4096
切换到新建账户
运行bin下的执行文件;

ES入门:

索引:一个索引代表一个库
类型type:类似于表的概念,7.x只有doc后期就会没
映射mapping:类似与表结构的概念,对数据的约束;

API:

REST风格;
客户端API: java high level rest client

图形化插件:

kibana来管理ES,图形化,基于node.js的.
安装流程:
把kibana的权限授权给新建用户
设置权限给kibana目录
修改配置文件:kibana.ymlserver.port:5601server.host:es.host:
启动kibana 可用root 加--allow-root

Kibana和IK分词器的集成

IK3.0 60万/秒处理能力,多子处理器,个人词条优化存储,支持拓展词典,优化查询分析器;
安装流程:下载IK
插件安装流程:在plugins新建ik的目录,然后解压进去,重启es和kibana
分词模式:ik_max_word和smart模式,详细解析和简单模式
拓展词库添加:在es目录/config/analysis-ik/中添加dic字典库配置ik的配置文件ikanalyzer.cfg.xml
停用词库添加:在es目录/config/analysis-ik/中添加停词dic字典库配置ik的配置文件ikanalyzer.cfg.xml
同义词词典:在es目录/config/analysis-ik/中创建同义词词典dic格式为:liuzhiwei,刘治炜  表示这两个词是相同含义;

索引基本操作:

操作都是一次http请求
PUT /indexName 添加
HEAD /indexName  检查
GET /indexName,... 查找  _all全部索引  _cat/indices?v 健康状态
POST /indexName/_close 关闭索引
POST /indexName/_open 开启索引
DELETE /indexName,... 删除索引

映射操作:

添加约束,对字段的类型和其他属性进行设置;
index 是否索引;
store 是否存储;
analyzer 指定分词器;
映射关系查看: GET /indexName/_mapping
查看所有映射: GET _mapping、GET _all/_mapping
添加索引同时添加mappingPUT /indexName{"settings" :{},"mappings":{file约束}}

文档的操作:

POST /index/_doc/{id} id不写就是自动生成
{json数据
}
GET /index/_doc/{id} 查看文档
GET /index/_search
{"query":{查询条件,如:"match_all":{}}
}
GET /index/_doc/{id}?_source 查看并设置返回结果
PUT /index/_doc/{id}
{修改的json数据,全量更新,不写别的值会被干掉;
}
POST /index/_update/{id}
{"doc":{json数据,增量更新不会干掉没更新的字段}
}
DELETE /index/_doc/{id} 删除文档
DELETE /index/_delete_by_query
{"query":{条件"match_all":{=全删}}
}
PUT /index/_doc/{id}/_create {json} 强制创建 如果ID存在,那么报错
PUT /index/?refresh=true 增加文档后立即刷新索引,对新文档进行分词啦

ES高级

地理坐标点

和redis的geohash还有mongo的geo差不多;
表达坐标的三种形式:字符串:"location":"纬度,经度";属性格式:"lat":纬度, "lon":经度数组形式:"location":[经度,纬度]
坐标过滤器:geo_bounding_box:方框中的点geo_distance:指定位置指定距离的圆形内覆盖的点;geo_distance_range两个同心圆的边距距离
过滤器的使用:json在query中添加filter对象

动态映射

针对于mapping初始化未设置的字段处理
mapping的dynamic属性:true:动态处理false:忽略strict:报错

自定义动态映射:

日期检测的问题:mappings中date_detection属性设置为false,表示value不做日期检测,不把它转换为日期类型;
日期格式检测:mappings中dynamic_date_formats:"时间格式",只要符合设置的格式,那么才转为日期格式;

动态模板:

dynamic_templates属性来控制,
根据match规则设置哪些字段,设置分词器、字段属性等mapping属性

DSL:

查询的基础语法:query:{查询的类型:match、match_all}
全文查询的语法:query:{match:{字段:{query:"value"operator:"逻辑关系 and 或者 or,基础查询默认给的是or"}}}
短语查询语法:query:{match_phrase:{字段:{query:"value",slop:"跨度(中间最大间隔多少个单词,至少为1)"}}}
Query_String查询语法:query:{query_string:{ 不指定字段,那就所有字段查询,query:"value" 可逻辑查询和模糊查询,default_field:"设置默认字段,等同于普通查询了",fields:[设置查询的多个字段]}}
multi match查询多字段搜索:与query_String的多字段一样,支持字段模糊匹配

词条级搜索:

精确的搜索

词条搜索基础语法:query:{term:{字段:value}}
词条集合搜索:query:{terms:{字段:[value1,value2,...]}}
范围查询:query:{range:{字段:{"gte" : value, 为>="lte" : value 为<="gt" : 为 >"lt" : 为 <boots: 1.0 查询权重 }}}
不为null的查询:query:{exists:{指定字段是否存在field:"字段名"}}
前缀查询:query:{prefix:{字段:"value"}}
模糊查询:query:{wildcard:{字段:"可使用通配符的value, 区分大小写",也可写成对象型,字段再被设置为一个对象}};query:{fuzzy:{字段:{value:boots:fuzziness: 允许模糊字符的数量,纠错数量,中文可能就是字儿}}}
正则搜索:
 注意使用,正则较为复杂会影响性能query:{regexp:{字段:"正则表达式"}}
ids查询:
 query:{ids:{type:"_doc" 后期取消,可不写values: [value1,value2]}}

复合查询:

评分相同查询:query:{constant_score:{filter:{真正的查询,filter不会产生分数,所以才会有相同评分},boots:"设置的分数"}}
布尔查询:query:{must:{必须满足的条件},filter:{必须满足的条件,无评分},should:{or的条件},minimum_should_match:should最少满足条件的数量must_not:{必须不满足的条件}}
排序:
默认按文档相关性得分进行排序,默认降序排序
设置排序规则:sort:{_score:{order:asc/desc}}
分页:
from:"从哪开始",
size:"每次取多少条"
高亮:
与match的字段绑定,match哪些字段才会高亮哪些字段,可使用query_string的查询就可多个字段高亮
highlight:{pre_tags:开始标签post_tags:结束标签fields:[{字段:{属性},...}]
}

文档批量操作:

_mget 多索引组合查询 _docs :[ 索引1:{字段:value},索引2:{字段:value}]
_bulk 批量增删改 {"动作" :{_index:索引, _id:value}}

Fileter过滤器:

不会计算相关度得分,会缓存的内存中,相同查询再次查时就会非常快;
一种特殊的查询;
查询语法检测:GET /index/_validate/query?explain{可能出现错误的查询}
聚合分析:聚合:metric聚合+group by:分桶 bucketing聚合方法语法:aggs:{聚合命名:{max/min/sum/avg:{field:字段name}}}查询条数:1:GET /index/_count{ 条件 }2:value_count:{field:字段name}去重:cardinality全部聚合展示:count、max、min、avg、sumstats:{field:字段name}高级全部聚合展示:平方差等,比普通全部展示多了四个extended_stats:{field:字段name}百分比统计:字段值在最大值中的位置百分比percentiles:{field:字段name}指定百分比显示:percentiles:{field:字段name,percents:[百分比]}分组+聚合:aggs:{分组的语句,aggs:{分组后的聚合语句}}ES的having效果:aggs:{分组的语句,aggs:{分组后的聚合语句having:{bucket_selector:{buckets_path:{parName:对应的聚合名称},script:{"source":"条件语句,例如params.parName = 1,params必填"}}}}}

ES零停机索引重建:

方案1:外部数据导入
MQ发送消息;
消费者消费消息 重新导入ES索引
从DB获取数据 并发送给MQ
另外消费者从MQ获取信息 存入到ES中
特点:批次可控、并发效率高
缺点:DB压力高、带宽占用较多、重建时间长
方案2:scroll+bulk+索引别名利用ES自带工具功能,利用java客户端做scroll查询、bulk命令封装;不依赖DBjava客户端使用别名来指向索引;新建索引,设置settings使用scroll api 批量查询数据滚动查询 GET /index/_search?scroll=1m 会返回一个scroll ID用 bulk api将scorll的数据插入到新索引中GET /index/_search/scroll{"scroll":1m,"scroll_id":"返回的scroll_id""size":"拿多少条"}就可一直拿取下一页的数据用 bulk api将scorll的数据插入到新索引中特点:不依赖DB,使用java客户端即可;
方案3:reindex API对scroll、bulk进行了封装,不需要java客户端了都POST _reindex{conflicts:"proceed" 忽略已存在文档的报错"source":{index:"index",可添加query:{}可添加sort:{}},"dest":{index:"new index""version_type":"internal"覆盖操作"external":乐观锁更新操作,数据存在更新version,不会覆盖"op_type":create 如果文档ID已存在那么报错}} 记得要对新索引设置settings

智能搜索建议:

智能联想、补全、纠错等功能,也增加一些相同的相同意义的单词
Suggester API将输入的文本分解为token,然后去索引里查找相似的term. 根据使用场景,有四种不同实现:Term Suggester  单词的Phrase Suggester  短语的Completion SuggesterContext Suggester 段落的
单词智能支持 Term Suggester:分词的URL POST _analyzer(使用默认simple分词器){text:[文本]}搜索建议:POST /index/_search{suggest:{selectName:{text:"input的text",term:{suggest_mode:missing错过,只有错误的才会被建议popular流行,将一些同义词或者更高词频的也给建议出来always一直,与流行一样了.原来是一直建议的意思;field:字段}}}}term的相似性是根据两个单词之间字符变动的数量来判断的,但中文相似性就无法使用这样的算法进行比较,中文较为复杂
Phrase Suggest 短语智能搜索:POST /index/_search{suggest:{selectName:{text:"input的text",phrase:{field:字段highlight:{高亮选项pre_tag:开始标签post_tag:结束标签}}}}}
Completion Suggest  实时查询:
应用于auto completion场景,用户每输入一个字符就会进行匹配查询并返回匹配项,用户如果输入过快可能会影响到后端响应速度;
不采用倒排索引的数据结构,将分词后的数据编码成FST和索引一起存放,如果open的索引,FST会被整体装载到内存,这样正排索引速度就会很快,但也仅仅只能正序查询了,智能建议同义词什么的,就木有了;
在创建索引时,就需要设置字段类型为completion:"mappings":{"properties":{"body":{"type":"completion"}}}
查询:
POST /indexname/_search/pretty"suggest":{"查询name":{"prefix":"查询词","completion":{"field":"字段名称"}}}
针对于不同的分词器,会影响到该智能搜索的结果,所以要考虑好分词器的选择;
mappings其他可能影响搜索结果的配置:preserve_separatorspreserve_position_increments 这些模糊查询的配置 都会影响completion搜索的结果
场景选择:开始输入时,使用前缀completion查询,80%做到命中;输入结束,completion查询 无法查询到结果, 那么开始使用短语和单词查询来进行错误词和相似词的建议查询并返回;精准度由粗到精准为:粗Completion->phrase->term精准相关的一些指标:公式解释:查询到的相关文档为A查询到的不相关文档为B没有查询到的相关文档为C没有查询到的不相关文档为D召回率:检索到的相关文件 / 系统相关文件总数   R=A/ (A+C)准确率:检测到的相关文件/ 查询到的系统文件总数  P= A/ (A+B)
Context suggester 相关性查询:根据上下文相关性提供查询建议,但这个是不是得配啊? 有个专门的上下文配置或者在新增文档的时候就需要考虑这个上下文的问题? 类似于"猜你想搜"?

ES的 Java Client:

1:TransportClient ES 为传统客户端 8.0将删除
2:RestClient ,分为low level 和high level
使用流程:导入依赖包 elasticsearch-rest-high-level-client, groupId=org.elasticsearch.clinet排除 elasticserach,该包中ES版本可能较低(5.6.8), 单独再导入ES依赖导入依赖包 elasticsearchyml配置文件的编写:esconfigName:elasticsearch:hostlist: ip:9200配置类:创建bean,返回为RestHighLevelClient,解析hostlist,new RestHighLevelClient时需要使用;CreateIndexRequest("indexName") 创建索引,CreateIndexRequest.mapping(json数据)拼装JSON 可使用alibaba的fastJSON,还有很多Json拼接IndicesClient in = client.indices();CreateIndexResponse cir = indicesClinet.create();

ES索引库管理:

删除索引库:DeleteIndexRequest对象负责删除IndicesClient对象负责实例化客户端AcknowLedgedResponse对象接收客户端执行后的响应
添加文档:IndexRequest对象 初始化请求体JsonIndexRequest.source(json数据);IndexResponse对象负责接收执行后的响应
查询文档:GetRequest对象负责去查询文档;GetRequest.source(json条件);client.get(GetRequest);GetResponse负责接收响应

API高级查询的代码实现:

SearchRequest对象负责query类查询;
SearchSourceBuilder对象添加条件数据
SearchSourceBuilder.query(QueryBuilders.查询类型)
SearchSourceBuilder.fetchSource(包含的数组,排除的数组);
SearchRequest.source(SearchSourceBuilder);
SearchResponse对象获取响应
SearchHits hits = SearchResponse.getHits();获取命中的结果对象

API高级查询的其他代码实现:

termQuery:SearchSourceBuilder.query(QueryBuilders.查询类型)改为termQuery(查询条件添加)
分页Query:SearchSourceBuilder.from(开始获取位置)SearchSourceBuilder.size(获取数量)SearchSourceBuilder.sort(排序语法
)

ES高可用:

node节点配置:node.master 是否可成为主节点node.data: 是否可存储数据
分片:索引可有多个分片,存储不同的数据,可分为主分片和复制分片,复制分片就是主分片的复制版本,不会与主分片在一个分区
副本:主分片的复制,可随时代替主分片;

分布式架构:

高扩展性、高可用性、实时性;
新节点无需过多配置即可被发现

分层结构:

贴图

gateway层:中间缓存类存储,保证故障可用的索引数据
Lucene支持层:lucene的底层支持
中间模组层:索引、查询、mapping、river
决策和脚本层:Zen负责节点的选举、发现、添加与健康检查;执行js、python等脚本第三方插件的集成
转换层:http协议为默认传输层Thrift协议、Memcached协议JMX组件
API层:rest api,基于netty框架
透明隐藏特性:隐藏分片的机制,减少大文件存储和IO;隐藏分片的副本可以快速上主,提供高可用;集群发现机制:自动发现新加入的节点,Zen的作用负载均衡:自动负载节点;扩容机制:垂直扩容:替换服务器水平扩容:新增节点主节点:master,负责创建索引和管理,他的健康程度影响分布式整体效率节点对等:每个节点都能接收请求并路由到相关节点

集群环境搭建:

单机伪集群:一个节点最低要保证1G的内存;
配置文件es.yml:cluster.name集群名称node.name节点名称node.master是否可称为masternode.data是否存储数据path.data索引数据存放路径path.logs日志存放路径bootstrap.memory_lock:是否需要锁住物理内存,就是直接占上,不是不够了再申请network.host:地址http.port:端口默认9200transport.port:节点选举端口 默认9300discovery.seed_hosts:7.x之后的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点cluster.initial_master_nodes:初始化一个新的集群时需要该配置来选举masterhttp.cors.enabled:是否支持跨域,在使用head插件时需要配置http.cors.allow-orgin "*" 表示支持所有域名
集群健康验证:http://host:port/_cat/health?v

集群工具head插件:

图形化集群管理工具,搜索接口可查询原始JSON,提供输入窗口调用Rest API
安装流程:基于node.js的,所以需要先安装node.js;设置软连接来达到环境变量的目的,ln -s /执行目录  /usr/local/bin/安装phantomjs下载后是 bz2的压缩包,我们要yum install -y bzip2tar -jxvf phantomjs配置环境变量:export PATH=$PATH:/phantomjs目录source生效一下npm安装一下grunt的相关工具贴文档git下载head在head目录下指定一下npm源为淘宝的npm源地址;启动:npm run start

集群规划:

考虑方面:数据量规模、机器的配置
ES JVM heap 最大32G
大型服务器可跑多个ES实例
应用场景:业务搜索 几千万-十亿 2-4台节点ELK 需要的就多了
角色分配:协调节点,只负责路由的节点,不选举、不存数据
集群脑裂:旧版本过半机制来防止脑裂discovery.zen.minimum_master_nodes 来设置7.x 后更改了一些配置防止脑裂做法主节点与数据节点分离,设置基数主节点延长心跳检测的等待时间
分片数量考虑:30-32G的JVM限制 分片容量最大限制为 30GB,根据数据规模 /30G +1个分片根据索引类型设置分片;分片是无法动态扩容的,只能重置索引,这就导致该索引暂时不可用
分片副本数量考虑:副本大多为2则可, 如果并发请求大, 那么可以增加副本,可以动态扩容

分布式集群的调优策略:

写调优:首次写入数据 副本设0, 写入完成再调成 正常副本数量 直接拷贝即可;合理设置mappings,分词的字段要设置好,或者不建立索引,针对有些类型分词没有意义浪费效率减少内容长度,有些内容没必要建索引那就没必要写到ES中使用不同的分词器,合适搭配_source字段调整, includes和excludes 过滤评分相关度关闭,有些查询无需计算相关度,可关闭减少性能消耗;调整索引刷新间隔;批处理来新增文档,一次请求处理;文档的路由处理,针对于请求进行路由,使其减少线程的开启,设置一个routing来让put时 变成为一个批处理,减少线程数,但会对于单次请求来讲,请求时间加长了,要注意;
读的调优:对索引进行分组, 业务控制分组去读filter去替代query减少相关度评分计算,filter+bool的查询是可以做到相关度评分的查询效果,业务进行组装;ID优化为keyword,ES可优化并加快搜索速度;限制用户输入无效字符,减少ES的无效查询或慢速查询

ES的数据模型:

现实世界与计算机语言的映射
事物实体:具体的物或人
概念实体:对事物归类的实体,如一个公司,一个队伍
实体属性:实体的特征

数据建模:

概念建模:搞个大概雏形
逻辑建模添加细节、关系、对应;便于各岗位沟通交流,明确需求,不依赖具体的实现,可选型、技术栈选择
物理建模具体落实到数据库产品选择.对逻辑建模进行具体的执行和建立,数据的具体类型,表关系的设计,索引建立等具体的工作;
建模的意义:贴图

ES数据建模的Mapping设置:

es的网址可以具体查看mapping属性,官网:

设置流程

关联关系处理:application-side joins 像表连接一样的关联查询,对独立的索引进行组合的查询查时 将term中设置联查的索引的id 作为value 查询data denormalization非规范化查询,针对少量的关联关系处理添加文档时,将关联的关系进行存储在各个索引中,提供给后期查询用使用match条件查询嵌套关联关系, 将数据进行嵌套组装,查询时对数据进行直接查询即可,但数据添加相对复杂使用 naste参数设置查询条件父子文档关联关系 牺牲查询性能来换取索引性能,查询性能比嵌套查询慢5-10倍,消耗内存和CPU,需要特定的has_parent和has_child过滤器查询语法,不能同时返回父子文档,父子的文档都在一个索引上,父子必须存储在同一分片上,通过routing进行关联存储

ES的搜索实战:

数据在DB中,存储到ES中,再给用户进行查询.通过点击后查询数据库进行查看详细页面;
一些细节:注意将elasticsearch-rest-high-level-client中的es包进行排除,该包中的es版本较低;IndexRequest().source()多态方法中 Object..数组并不能处理实体类.使用成型的插件可以避免一些问题的出现

ES深度应用剖析:

ES基本存储单元为shard,每个shard中存储了若干个segment;
commits:Commit 操作意味着将 Segment 合并,并写入磁盘。保证内存数据尽量不丢。但刷盘是很重的 IO 操作, 所以为了机器性能和近实时搜索, 并不会刷盘那么及时。

Translog:新文档被索引意味着文档会被首先写入内存 buffer 和 translog 文件。每个 shard 都对应一个 translog文件

refresh:在 Elasticsearch 中, _refresh 操作默认每秒执行一次, 意味着将内存 buffer 的数据写入到一个新的 Segment 中,这个时候索引变成了可被检索的。写入新Segment后 会清空内存buffer。

flush:Flush 操作意味着将内存 buffer 的数据全都写入新的 Segments 中, 并将内存中所有的 Segments全部刷盘, 并且清空 translog 日志的过程。

近实时搜索的原理:

不会立即同步,暂时移除刷盘机制,先把新增的文档写入内存中,再提交到文件系统的buffer,立刻提供查询功能;但不会刷盘到磁盘文件.在后期进行定时的异步刷盘操作,写盘为不连续的随机写入,不像rocket的刷盘机制,是顺序写入的;


refresh的API:默认每秒自动刷新一次,可通过API进行手动刷新,对单个索引、单个文档进行刷新;针对那种不是特别多的新增索引,可以把刷新间隔设置长一点;settings:{refresh_interval:30s}如果后期需要可以再设置回1秒一刷新

持久化变更:

与近实时搜索的原理相同,在持久化时提供两个缓存的空间,内存buffer和transLog缓存,当refresh时,清空内存buffer写入文件交换系统buffer,当flush时将translog的数据进行刷盘并清空transLog,这样最大程度保证了数据的持久性,不会因为ES挂机而导致数据丢失;
flush API:默认每30分钟自动flush一次,可手动flush: /_flush可设置同步flush:/_flush?wait_for_ongoin 等待刷盘全部完成返回结果
transLog的安全性:transLog默认是5S刷盘一次,所以因为机器重启可能会丢失几秒内的数据,这是无法避免的,避免频繁IO提高速度就要丢失数据一致性,这是必然的;设置异步刷盘的属性:settings:{"index.translog.durability":"async",默认是同步的 request"index.translog.sync_interval":"5s"}可针对索引单独设置

索引文档的段合并机制:

段合并机制:索引创建和搜索时会自动进行,对一些segment进行合并,方便刷盘,但是这个操作会有IO消耗,所以要控制segment合并的磁盘读取速度,默认情况下归并限速配置是indices.store.throttle.max_bytes_per_sec:20MB,我们可以根据自己服务器的磁盘配置相应调高一些,如ELK这种日志系统就可以调成100MB或者更高.也可以设置归并的线程数来限制IO的数量,index.merge.scheduler.max_thread_count为CPU核心的数的一半.但也要配合硬盘的处理能力来决定.别硬盘5400转的,贼慢,搞8个线程去搞那玩意,浪费;
归并策略:根据一定的规则进行挑选segment进行合并
index.merge.policy.floor_segment 优先合并的segment最小设置,小于该值大小的segment会被优先合并,默认为2MB
index.merge.policy.max_merge_at_once 设置单次合并segment的数量. 默认为10个
index.merge.policy.max_merge_at_once_explicit 强制合并时,单次合并segment的数量,默认为30个
index.merge.policy.max_merged_segment 当一个segment超过该值设定大小后,将不会被合并,但不影响强制合并的功能.默认为5GB
optiomize API 强制合并:通过设置强制合并,将一些固定大小的数据segment进行强制合并,这些数据产能稳定,数据大小固定,通过设置max_num_segments参数来设置强制合并的segment个数,主要是为了提升搜索性能,将数据都扔一堆里肯定查询更快;
API:_optimize?max_num_segments=1
对应JDK API:forceMergeRequest.maxNumSegments(1)

并发处理机制:

并发减库存的问题;ABA的问题;
悲观锁的解决方案:直接锁数据,简单.方便;
乐观锁的解决方案:版本控制来解决并发问题,不会阻塞,自己维护了一个version版本,不用自己搞,同过if_seq_no和if_primary_term参数来进行乐观锁更新,如果不一致将会报错,seq_no会针对整个索引的,version是针对文档修改的,修改时只要原来的version号大就可.新增文档seq_no来更新,单个文档version来搞

ES的分布式一致性:

一致性检测
5.0之前: one、all、quorum;一个主节点活跃即可;全部节点活跃;计算后的节点数量活跃,公式(主的总数 + 每个主的副本数) /2 +1
timeout机制:一段时间内检测节点活跃
5.0之后:wait_for_active_shards 设置需要活跃的节点数量,也是根据quorum公式计算

Query文档搜索机制:

搜索类型:
query nad fetch:向所有分片发出查询请求,但浪费资源,会有重复记录,会多返回数据,为size的n倍
QUERY_THEN_FETCH查询前先将分片的词频率和文档频率收集,提供更精准评分相关度的查询,性能低,也会返回size N倍的数据;
QUERY_THEN_FETCH先向shard发送请求,然后根据返回的数据相关度再拿出size个数据,性能较低、准确度较为不错,详细流程:1.发送查询到每个shard 2.找到所有匹配的文档,并使用本地的Term/Document Frequency信息进行打分 3.对结果构建一个优先队列(排序,标页等) 4.返回关于结果的元数据到请求节点。注意,实际文档还没有发送,只是分数 5.来自所有shard的分数合并起来,并在请求节点上进行排序,文档被按照查询要求进行选择 6.最终,实际文档从他们各自所在的独立的shard上检索出来 7.结果被返回给用户
DFS_QUERY_THEN_FETCH比上面多了个词频率文档频率进行收集和统计;1.预查询每个shard,询问Term和Document frequency2.发送查询到每个shard3.找到所有匹配的文档,并使用全局的Term/Document Frequency信息进行打分4.对结果构建一个优先队列(排序,标页等)5.返回关于结果的元数据到请求节点。注意,实际文档还没有发送,只是分数6.来自所有shard的分数合并起来,并在请求节点上进行排序,文档被按照查询要求进行选择7.最终,实际文档从他们各自所在的独立的shard上检索出来8.结果被返回给用户

文档写入流程:

(1)客户端首先会选择一个节点node发送请求过去,这个节点node可能是协调节点coordinatingnode
(2)协调节点coordinating node会对document数据进行路由,将请求转发给对应的node(含有primary shard)
(3)实际上node的primary shard会处理请求,然后将数据同步到对应的含有replica shard的node
(4)协调节点coordinating node如果发现含有primary shard的node和所有的含有replica shard的node符合要求的数量之后,就会返回响应结果给客户端

文档查询流程:

1、客户端首先会选择一个节点node发送请求过去,这个节点node可能是协调节点coordinating node
2、协调节点将搜索请求转发到所有的shard对应的primary shard 或 replica shard ,都可以。
3、query phase:每个shard将自己的搜索结果的元数据到请求节点(其实就是一些doc id和 打分信息等返回给协调节点),由协调节点进行数据的合并、排序、分页等操作,产出最终结果。
4、fetch phase:接着由协调节点根据doc id去各个节点上拉取实际的document数据,最终返回客户端。

相关性评分算法BM25:

设置BM25的K值和B值:settings:{similarity:{bmname:{type:BM25,b:0.1,k1:0.3}}},mappings:{properties:{title:{type:text,similarity:bmname}}}

DocValues机制:

倒排索引查询很快,但排序没有很好的解决,docValue属性来完善排序的机制,通过设置该值来决定是否排序,设置false后,不可被排序,不可被统计分组;
概念:一个正排索引,文档里有哪些词,占用空间,但提供了排序和统计;
底层:与倒排索引一样,也有segment和刷盘机制,但没有buffer这一步,直接入库;
压缩:根据值进行压缩,利用最大公约数的机制来进行同比压缩;
禁用doc values:text无法使用docvalue排序,因为要分词;

Filter:

 在倒排索引中查找搜索串,获取document listFilter为每个在倒排索引中搜索到的结果,构建一个bitset,[0, 0, 0, 1, 0, 1](非常重要)多个过滤条件时,遍历每个过滤条件对应的bitset,优先从最稀疏的开始搜索,查找满足所有条件的documentcaching bitset,跟踪query,在最近256个query中超过一定次数的过滤条件,缓存其bitset。对于小segment(<1000,或<3%),不缓存bitset如果document有新增或修改,那么cached bitset会被自动更新filter大部分情况下,在query之前执行,先尽量过滤尽可能多的数据

ES控制搜索精度:

自定义函数:自定义一个函数,配合boots权重值来进行自定义的评分计算规则;几个影响评分的函数field_value_factory:分数影响函数,可设置一些公式,然后与设置的source进行一些计算,如field_value_factory:{filed:"需要计算的字段",factor:"因子数",modifier:"sqrt" 计算的公式,这个是平方根}modifier取值列表:

 产生的分值必须为正数,否则会报错.所以在计算分数时要注意写公式不要出现负数;Decay functions:递减函数,类似于范围查询,计算查出的数字与设置的原点的距离,进行返回展示;规则公式:高斯、线性、指数,这三个规则所呈现的递减幅度不同而已.高斯为一个平滑的凸起弧面,指数为了一凹进的弧面,线性则为锋利的切面;公式属性:origin设置原点,与scale进行计算scale:设置衰减距离,范围查询的主要参数,用来计算相关度评分的主要参数,可日期、数字,也可写上单位offset:偏移量,对value进行附加decay:衰减参数,按照设置的比例给文档进行评分,相当于一个影响因素.如果不定义,那么默认就给每个查出的文档+0.5分

bulk操作API:

基本的格式:{"action":{"metadata(_index)"}}{"data"}不需要将JSON转换为标准对象,节省内存占用

深度分页:

基础方式:from+size,请求量大时,ES会对分页进行限制,idnex.max_result_window,如果超出了该数,那么ES会拒绝返回结果,但有的需求确实需要深度分页查询到所有数据;
scroll遍历方式:不适合实时搜索,利用快照机制锁定某一时刻数据,进行分页查询,不会被更新数据影响,适合批处理任务;
search after方式:满足实时获取,根据上一页最后一条数据的位置获取下一页数据,数据将需要唯一的字段value,如_id或者唯一编号等.利用唯一字段value进行排序,然后通过seach_after填入上一页最后一条数据的唯一value;只能点击下一页来操作,不能直接选择页码;
三种方式对比
from 简单、深度分页有问题、数据量小时,简单分页
scroll 解决深度分页,数据不是实时的,快照,需要使用srcoll_id,适合批次处理的海量数据
seach_after 最强性能,分页实时性、速度都可以,但无法通过选择页码进行翻页,适合大量数据的分页;

ElaticSearch学习笔记相关推荐

  1. ElasticSearch基础学习笔记

    在学习ElasticSearch之前,先简单了解一下Lucene: Doug Cutting开发 是apache软件基金会4 jakarta项目组的一个子项目 是一个开放源代码的全文检索引擎工具包 不 ...

  2. 2020-11-24-ElasticSearch7.x学习笔记

    笔记记录 B站狂神说Java的ElasticSearch课程:https://www.bilibili.com/video/BV17a4y1x7zq 在学习ElasticSearch之前,先简单了解一 ...

  3. 【ElasticSearch7.X】学习笔记(一)

    [ElasticSearch7.X]学习笔记 一.介绍 1.1.ElasticSearch 1.2.RESTful 1.3.数据格式 二.下载安装(单机部署) 2.1.解压文件 2.2.修改配置配置 ...

  4. PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call

    您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...

  5. 容器云原生DevOps学习笔记——第三期:从零搭建CI/CD系统标准化交付流程

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  6. 容器云原生DevOps学习笔记——第二期:如何快速高质量的应用容器化迁移

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  7. 2020年Yann Lecun深度学习笔记(下)

    2020年Yann Lecun深度学习笔记(下)

  8. 2020年Yann Lecun深度学习笔记(上)

    2020年Yann Lecun深度学习笔记(上)

  9. 知识图谱学习笔记(1)

    知识图谱学习笔记第一部分,包含RDF介绍,以及Jena RDF API使用 知识图谱的基石:RDF RDF(Resource Description Framework),即资源描述框架,其本质是一个 ...

最新文章

  1. C++/C++11中头文件numeric的使用
  2. java中的关键字static(静态变量)和final定义常量
  3. 帝国cms内部会员组的使用方法以及应用场景
  4. mysql 执行计划 优化_执行计划
  5. 学习多媒体开发的正确姿势?陈功:看书 啃代码 搞插件
  6. Caffe源码解析4: Data_layer
  7. mysql多副本搭建_一个简单的MySQL多实例环境搭建
  8. Codeup——问题 H: 部分A+B (15)
  9. python使用try语句捕获处理异常_Python使用try except处理程序异常的三种常用方法分析...
  10. 外卖行业现状分析_2020年中国外卖行业市场现状与发展前景分析
  11. 7-6 愿天下有情人都是失散多年的兄妹(25 分)
  12. 计算机英语构词法,【计算机专业论文】计算机专业英语的构词方法(共2969字)
  13. java计算机毕业设计校园订餐系统源代码+数据库+系统+lw文档
  14. 百度AI战疫五十天:三场战役与一次胜利
  15. 滴滴一下,小程序专车来了
  16. 真正的IT技术男是什么样的?
  17. matlab 数理统计,概率论和数理统计(matlab应用)1
  18. Python print 输出时刷新当前行内容而不输出新行
  19. 企业数据应用 传统商业智能对比大数据应用
  20. 阻容感原件选择标规范

热门文章

  1. idea安装maven依赖包及配置过程,打开及运行项目
  2. dnf7月7日服务器维护,dnf7月7日早7点/8点半停机更新公告
  3. 料箱输送线程序,有合流和分拣,个人认为精华部分是WCS和PLC的Socket接口和分拣控制程序
  4. 挂件巡检机器人_一“人”分饰多角 京东新一代巡检机器人上岗!
  5. PYTHON实现自动发送邮件
  6. | UML(Jude)
  7. chatgpt可以降重论文吗-chatgpt降重论文软件
  8. java中经纬度使用与相关工具类
  9. 机器学习算法分析汇总
  10. 【Linux】手把手教你搭建自己个人博客(boss版)