es是一个开源的基于Lucene基础上,使用java封装,内部使用Lucene做索引与搜索,提供了一套简单的RESTful API。
es的作用:①分布式的实时文档存储,每个字段都可以被索引与搜索;②分布式实时搜索引擎;③胜任上百个服务节点的扩展,支持PB级别的数据
es是基于文档的搜索引擎,使用JSON文档存储数据,相关数据通常存在同一个文档中,而不是分散在多个表中。
es使用Query DSL ,基于JSON,支持全文搜索、复合查询、过滤、聚合等。
1.es为什么快
1.分布式存储:使用分布式存储技术将数据存储在多个节点上,减轻单节点压力,提升性能;
2.索引分片:把每个索引划分成多个分片,这样可以让查询操作并行化,提高查询速度;
3.全文索引:将文档转化成可搜索的结构化数据,使得搜索操作快速高效。
4.倒排索引:支持倒排索引结构,倒排索引将文档中的词与词出现的文档进行映射,并存储这些信息。当搜索请求时,es可以快速查询包含关键词的文档并返回;
5.预存储结果:插入数据时会对数据进行预处理,并将结果存储到索引中,从而在查询中不再需要重新计算;
6.内存存储:使用内存存储,减少磁盘IO,提高存储和查询速度;
2.es字段类型
text
适用于全文检索的文本,会被分词器分词并建立倒排索引,,支持模糊搜索、短语搜索等,默认使用标准分词器,也可以指定
java
"content": {
"analyzer": "ik_max_word",
"type": "text"
}
keyword
用于存储不可分词的、完整的、原始的值,如标签、ID、code等,用于精确匹配等,不进行分词
java
"id": {
"type": "keyword"
},
数值类型:long、integer、short、byte、dobule、float
时间:date
java
"created": {
"format": "yyyy-MM-dd HH:mm:ss",
"type": "date"
},
"pubdate": {
"format": "yyyy-MM-dd",
"type": "date"
},
nested
用来存数组形式的独立对象,每个对象都有自己的文档结构
java
"researchers": {
"type": "nested",
"properties": {
"user_id": {
"type": "long"
},
"name": {
"type": "keyword"
}
}
},
多字段
为一个字段创建多个映射定义,可以使用不同的左印方式查询同一字段的内容,如下title字段,有个text字段,用的是ik_smart的分词模式,然后还可以通过search_key字段使用ik_max_word进行匹配,也可以通过key进行全词匹配或者ngram_key进行模糊匹配
java
"title": {
"analyzer": "ik_smart",
"type": "text",
"fields": {
"search_key": {
"analyzer": "ik_max_word",
"type": "text"
},
"key": {
"type": "keyword"
},
"ngram_key": {
"analyzer": "ngram_analyzer",
"type": "text"
}
}
},
3.优化
3.1集群和硬件优化
服务是个java项目,合理设置服务运行参数可以有效提升服务性能
确保堆内存最大最小值Xmx和Xms想通,防止运行中改变堆大小(通常为机器内存50%但是不超过32G,超过会无法使用压缩指针)
合理的GC模式(G1好了,内存一般超过4G)
根据需要使用高性能服务器或者提升服务器性能,比如增加CPU、内存、使用ssd
负载均衡
3.2合理分片
分片多了可以提升吞吐量,但是查询大量的分片也可能会导致查询性能降低,因为每个分片都要单独处理查询。分片多了也会增加集群管理开销。所以需要根据数据大小、查询复杂性、硬件资源和预期的负载等等因素进行设置分片大小。
es为强制规定分片大小,但是网上有一个经验法则:每个节点上已经配置的每个GB分片不大于20,即某节点又有15GB的堆内存,那最多可以分300片,当然一半而言在此范围内分片数量越少效果越好。
3.3精准的映射和索引设置
为每个字段指定正确的数据类型(text、keyword、long、date等),不同的数据类型有不同的存储和索引方式。
不需要全文检索的指定为keyword避免被分词器分割。
需要分割的text并 指定合适的分词器(ik_smart/ik_max_word)来定义文本如何被分割和索引。
3.4查询优化
1.使用过滤器:filter可以缓存,query不可以,后续相同查询速度会提升
2.避免深度分页:当使用from(跳过的条数)和size(每页条数)进行查询,from=8000,size=10,他会先找到并处理当前页之前的所有数据(8000)就是深度分页,会对性能产生影响,页码越多处理的数据就越多;考虑使用search_after或者scroll API
3.减少返回字段:在查询请求中指定返回的字段(_source filtering),只获取必要的字段,可以减少网络传输的数据量和减轻ES集群的负担
4.使用精确的查询语句,避免使用一些通配符、正则表达式、脚本(script)查询
5.监控:使用kibana和ElasticSearch-head监控状态性能
6.启用慢查询来识别和优化慢查询(可以看这篇文章Elasticsearch慢查询日志配置-CSDN博客)
在elasticsearch.yml中开启慢查询:,不需要就注释后重启就行了,生成的日志记录在以"_index_isearch_slowlog.log" 结尾的文件中
java
index.search.slowlog.threshold.query.warn: 10s #超过10秒的query产生1个warn日志
index.search.slowlog.threshold.query.info: 5s #超过5秒的query产生1个info日志
index.search.slowlog.threshold.query.debug: 2s #超过2秒的query产生1个debug日志
还有索引的慢查询日志
java
index.indexing.slowlog.threshold.index.warn: 10s ##索引数据超过10秒产生一个warn日志
index.indexing.slowlog.threshold.index.info: 5s ##索引数据超过5秒产生一个info日志
index.indexing.slowlog.threshold.index.debug: 2s ##索引数据超过2秒产生一个ddebug日志
4其他
es不支持事务,但是可以通过版本号_version(6.7之前),之后的版本可以通过_seq_no
和_primary_term进行,可以去看以下文档:
Optimistic concurrency control | Elasticsearch Guide [8.16] | Elastic
java
PUT products/_doc/1567?if_seq_no=362&if_primary_term=2
{
"product": "r2d2",
"details": "A resourceful astromech droid",
"tags": [ "droid" ]
}
5.和mongoDB的区别
1.es是java编写,RESTful接口操作数据,mongoDB是C++的。
2.mongodb分片可以通过hash和range,es只能hash
3.es天生分布式,主副分片自动分配和复制,开箱急用,mongodb需要手动配置
4.es是倒排索引,mongodb是B树索引
5.es是最终一致性,mongodb是强一致性的,es适合做搜索日志分析,mongodb适合高吞吐量的读写操作
7.ES文档最大2.2G,mongodb16M
8.存储引擎es是Lucene,mongodb是WiredTiger
9.es不支持事务,mongodb支持事务
10.适用场景,es适合做搜索日志分析,mongodb适合做文档存储、分析
这篇文档里写得到更详细(MongoDB与Elasticsearch特性及知识点对比_elasticsearch mongodb-CSDN博客)