ElasticSearch 完整教程
ElasticSearch 完整教程
by@chenshaojun - 2025.02.18
1.简介
1.1 发展历程
-
1998.9.4日,Google在美国硅谷成立,是做搜索的公司;
-
同时期,Doug Cutting的美国工程师,也迷上了搜索引擎,他做了一个文本搜索的函数库Lucene,java写的。
-
2001Lucene成为Apache软件基金会的子项目.(好爹)
-
Doug Cutting 2006 加盟了Yahoo, 对Lucene,NDFS,MapReduce升级改造为Hadoop
-
Doug Cutting同年改造:Hadoop+bigTable 为HBase
-
ElasticSearch是对Lucene的封装和增强,也是java写的
-
ElasticSearch是基于json格式的开源的分布式全文检索引擎.用于全文搜索,结构化搜索,分析.
-
2016.1 ElasticSearch已超过Solr,成为排名第一的搜索引擎应用.
-
Lucene,Solr,ElasticSearch都是Apache软件基金会的项目。
-
总结:ES VS Solr
1、ES基本是开箱即用,非常简单。Solr安装略微复杂
2、Solr 利用Zookeeper进行分布式管理,而Elasticsearch 自身带有分布式协调管理功能。
3、Solr 支持更多格式的数据,比如JSON、XML、 CSV ,而Elasticsearch仅支持JSON文件格式。
4、Solr 官方提供的功能更多,而Elasticsearch本身更注重于核心功能,高级功能多有第三方插件提供,例如图形化界面需要kibana友好支撑
5、Solr 查询快,但更新索引时慢(即插入删除慢) ,用于电商等查询多的应用;
● ES建立索引快(即查询慢) ,即实时性查询快,用于facebook新浪等搜索。
● Solr是传统搜索应用的有力解决方案,但Elasticsearch 更适用于新兴的实时搜索应用。
6、Solr比较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而Elasticsearch相对开发维护者较少,更新太快,学习使用成本较高 -
ES 特点
-
Elasticsearch是面向文档的一种数据库,这意味着其不再需要行列式的表格字段约束
-
ES会存储整个构造好的数据或文档,然而不仅仅是储存数据,这使得文档中每个数据可以被标识,进而可以被检索。在ES中,执行index,search,sort或过滤文档等操作都不是传统意义上的行列式的数据
-
ES从根本上对数据的不同思考方式也正是他能应对复杂数据结构的全文检索的原因之一
Relational DB Elasticsearch 数据库(database) 索引(index) 表(tables) 类型(types,新版本中逐步弃用) 行(rows) 文档(documents) 字段(columns) 字段(file)
-
2.基本概念
2.0 索引index,分片shard,副本replica
主分片和副本分片数量的调整
put /my-index/_settings
{
"number_of_shards":3,
"number_of_replicas":2
}
2.新建索引时设置分片
put /my-index
{
"settings":{
"number_of_shrads":3,
"number_of_replicas":2
}
}
2.1 分词器
-
是基于Json的开源的高扩展的分布式全文检索引擎
-
Lucene,ES,Solr的关系
-
倒排索引:将每个文档拆分成独立的词,然后创建不重复词的排序列表,记录每个词出现在那个文档
-
标准分词器:standard
-
IK分词:需安装插件,ik_smart/ik_max_word
https://github.com/infinilabs/analysis-ik -
切词器,词项过滤器:停用词,同义词
分词器各有特点,适用于不同的场景。选择合适的分词器可以提高搜索和索引的效率和准确性。
2.2 过滤器
"analyze":"standard" /ik_smart/ik_max_word
"filter":["upercase"] /["stop"]
"char_filter":{
"type":"html_strip" //html过滤器
-
字符过滤器:
html过滤器,
字符映射过滤器
正则过滤器把手机号码隐藏,把特殊字符脏字*号显示过滤器filter
返回指定字段
英文停用词/中日韩停用词:a,an,and
es-ik/7.17.3/config/stopword.dic
es-ik/7.17.3/config/main.dic
2.3 词项
分词后的每一项词条
3.数据类型
3.1 字符类型
text: 存储时会对字符进行分词然后存储
keyword: 存储时作为整体,不进行分词
3.2 数字
long,integer,short,byte,double,float
3.3 日期类型
date
3.4 布尔
boolean
3.5 二进制类型
binary
4.分词器介绍
分词器:对输入的文本进行切词的方法,适应多种业务场景
4.1 Standard 分词器
适用于自然语言文本,能够识别单词、数字、电子邮件地址和 URL。常用于英文语种分词
特点:
识别单词:能够识别常见的单词边界。
处理标点符号:会忽略大多数标点符号,但保留电子邮件地址和 URL。
处理数字:能够识别并保留数字。
处理特殊字符:能够处理一些特殊字符,如连字符和撇号。
4.2 Simple 分词器
简单地按非字母字符分割文本,并将所有字母转换为小写。
特点:
简单分割:只按非字母字符分割。小写转换:将所有字母转换为小写。
不处理数字:数字被视为非字母字符,会被分割掉。
4.3 WhiteSpace 分词器
仅按空格分割文本,保留所有字符。
特点:
按空格分割:只按空格分割文本。
保留所有字符:不忽略任何字符,包括标点符号和数字。
4.4 中文IK分词器
将整个输入文本作为一个单一的词元处理,不分词。适应与中文分词
特点:
不分词:将整个输入文本作为一个词元处理。
保留原样:不进行任何转换或修改。
- ik_smart:将文本最大程度地切分成独立的词汇,最少切分
ik_max_word:这种模式结合了理解歧义和未知词的算法,对文本进行词典分词的同时,也会智能识别词汇的边界,从而提高分词的准确性。最细粒度划分。
这些分词器各有特点,适用于不同的场景。选择合适的分词器可以提高搜索和索引的效率和准确性。
下载:https://github.com/medcl/elasticsearch-analysis-ik
安装:解压后放入es的安装目录的插件目录plugins下即可
4.5 ES搜索结果中字段介绍(took,hits)
- hits:
- total: 查询配到的文档总数
- took: 查询用时,毫秒
- shard:查询中参入分片的总数
- timeout: 查询是否超时
"took": 4,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 7, //符合条件的总文档数
"relation": "eq"
},
"max_score": 18.563643,
"hits": [ //结果集,默认返回前10个文档
{
"_index": "sensitive_brand", //索引名称
"_type": "_doc",
"_id": "025a8a620bb80ca6092b9c321bf467df", //文档id
"_score": 18.563643, //相关度评分
"_source": {
"Brand": "futu..",
5. 倒排索引
5.1 简介
将每个文档拆分成独立的词,然后创建不重复词的排序列表,记录每个词出现在那个文档。
elasticsearch使用的是一种称为倒排索引的结构 ,采用Lucene倒排索引作为底层。这种结构适用于快速的全文搜索,一个索引由文档中所有不重复的列表构成,对于每一个词,都有一个包含它的文档列表
5.2 数据结构
为了创建倒排索引,我们首先要将每个文档拆分成独立的词(或称为词条或者tokens) ,然后创建一个包含所有不重复的词条的排序列表,然后列出每个词条出现在哪个文档:(大小写要区分,重复单词也要加入)
term doc_1 doc_2
Study 〇 X
To X 〇
forever 〇 〇
every 〇 〇
study X 〇
day 〇 〇
good 〇 〇
up 〇 〇
to 〇 X
every 〇 〇
5. RestFull API
5.1 基本命令
method url地址 描述
PUT localhost:9200/索引名称/类型名称/文档id 创建文档(指定文档id )
POST localhost:9200/索弓|名称/类型名称 创建文档(随机文档id )
POST localhost:9200/索引名称/update/文档id update 修改文档
DELETE localhost:9200/索引名称/类型名称/文档id 删除文档
GET localhost:9200/索引名称/类型名称/文档id 查询文档(通过文档id)
GET localhost:9200/索弓|名称/类型名称/_ search 查询所有数据
5.2 DDL 命令(CRUD)
5.2.1 创建索引结构:put
put:http://10.158.*.*:9201/indexname
json 参数:
{
"mappings": {
"properties": {
"AddTime": {
"type": "date"
},
"Country": {
"type": "text",
"analyzer": "standard"
},
"FormatBrand": {
"type": "keyword",
"normalizer": "lowercase_analyzer"
},
"Id": {
"type": "keyword"
}
}
},
"settings": {
"index": {
"number_of_shards": "6",
"analysis": {
"normalizer": {
"lowercase_analyzer": {
"filter": [
"lowercase"
],
"type": "custom",
"char_filter": []
}
},
"analyzer": {
"digit_analyzer": {
"filter": [
"lowercase"
],
"type": "custom",
"tokenizer": "comma_tokenizer"
}
},
"tokenizer": {
"comma_tokenizer": {
"type": "char_group",
"tokenize_on_chars": [
"whitespace",
","
]
}
}
},
"number_of_replicas": "1"
}
}
}
5.2.2 查询单个索引结构:get
5.2.3 插入数据到索引:post
post: http://usl/test_19/_doc/1
post: 10.158.*.*:9201/test_19/_doc/1
{
"Country":"US",
"FormatBrand":"div2",
"Id":"01",
"AddTime":"2025-02-19"
}
5.2.4 修改索引字段和数据:post
-
post://url/indexname/_doc/1 如果文档存在,现有文档会被删除,新的文档会被索引
-
使用_update部分更新,不会删除原来的文档,而是实现真正的数据更新:格式: POST /索引名称/_update/id ,格式: POST /索引名称/_update/id
post: 10.158.*.*:9201/test_19/_doc/1
{
"Country2":"US2",
"FormatBrand2":"div22",
"Id":"01",
"AddTime":"2025-02-19"
}
post: 10.158.*.*:9201/test_19/_update/1
{
"Country2":"US2",
"FormatBrand2":"div22",
"Id":"01",
"AddTime":"2025-02-19"
}
5.2.5 删除索引:delete
删除索引:delete: http://indexname
删除文档:DELETE /es_db/_doc/1
delete: 10.158.*.*:9201/sensitive_wipo_distinctbrand_test
5.2.6 修改索引别名:_aliases
post: 10.158.*.*:9201/_aliases
{
"actions": [
// {
// "remove": {
// "index": "sensitive_wipo_distinctbrand_v16", 若别名已使用先删
// "alias": "sensitive_wipo_distinctbrand"
// }
// },
{
"add": {
"index": "test_19",
"alias": "test_test"
}
}
]
}
5.2.7 重建索引 :_reindex
一般使用于:经常更新的索引,时间常了有碎片导致查询性能下降需要重建索引。(创建索引结构,还原备份数据,重建索引)
post: 10.158.*.*:9201/_reindex
{
"source": {
"index": "test_19"
},
"dest": {
"index": "test_20"
}
}
5.2.7 分词_analyze
post:http://10.158.*.*:9201/_analyze
{
"analyzer":"standard", //Simple,WhiteSpace,ik_smart(最粗粒度的拆分),ik_max_word(最细粒度的拆分) 需安装插件ik
"text":"İÇDAŞ DIŞ TİCARET A.Ş."
}
5.2.8 indices 查询所有索引,大小
get: http://10.158.*.*:9201/_cat/indices
5.2.8 detailed 查询所有请求及响应时间
get: http://10.158.*.*:9201/_cat/tasks?v&detailed=true
5.2.9 plugins 查询所有安装的插件
get: http://10.158.*.*:9201/_cat/plugins
注意: 创建的索引名要小写
6.高级查询
6.1 match_all查询所有文档,全量分页查
6.1.1 返回源数据_sourc
6.1.2 返回指定条数size
6.1.3 分页查询from&size
6.1.4 指定字段排序sort
案例:
{
"query": {
"match_all": {} //match_all:无参输入,查询索引中的所有文档,不能写查询条件,默认返回10条记录
},
"_source": [
"Country",
"Id",
"AddTime"
], //返回的字段 _source": "obj.*" 只返回以obj开头的字段
"from": 0, //开始
"size": 2, //返回条数
"sort": {
"AddTime": {
"order": "asc" //desc 降序
}
}
}
6.2 术语级别查询(term,terms,exists,ids,range,prefix,wildcard)
-
术语级别查询(Term-Level Queries)指的是搜索内容不经过文本分析直接用于文本匹配;
-
术语级别查询示例包括 term、terms 和 range 查询, 查询类型为keyword的文本字段;
-
注意:最好不要在term查询的字段中使用text字段,因为text字段会被分词,这样做既没有意义,还很
有可能什么也查不到.
6.2.1 term 查询:单字段与单字符串的查询
-
对bool,日期,数字,结构化的文本可以利用term做精确匹配
-
采用term精确查询, 查询字段映射类型为keyword
get: 10.158.*.*:9201/shopee_listing/_search { "query": { "term": { //term 查找只能查找keyword类型的文本数据 "Sku": { //AddTime.keyword "value": "13346844" } } } }
6.2.2 terms 查询:是单字段与多字符串查询
get: 10.158.*.*:9201/shopee_listing/_search
{
"query": {
"terms": { //term 查找只能查找keyword类型的文本数据
"Sku": [
"13346844",
"13169954"
]
}
}
}
6.2.3 exists 判断是否存在对应的字段,有查询出数据
get: 10.158.*.*:9201/shopee_listing/_search
{
"query": {
"exists": { //term 查找只能查找keyword类型的文本数据
"field":"remark"
}
}
}
备注:如果remark的value值为null或着[],那么是不会被匹配到的
6.2.4 ids (ids values) id包含查询
where id in(values)
get: 10.158.*.*:9201/shopee_listing/_search
{
"query": {
"ids": { //返回id为输入值的文档
"values": [
"31303534342d32333533323439393635312d3133333436383434",
"31303534342d32333933323530323330322d3133313734323331"
]
}
}
}
6.2.5 range 范围查询: 数字,时间,bool
-
gt 大于
-
gte大于等于
-
lt小于
-
lte小于等于
get /_search { "query": { "range": { "OrderSourceId": { "gt": 10543, "lt": 10545 } } } }
6.2.6 wildcard 通配符查询
-
匹配一个或多个占位符,如Sku字段 匹配以133开头的sku文档被匹配出来
- *匹配多个字符
- ?匹配任何单个字符
get: /_search { "query": { "wildcard": { "Sku": "133*" //匹配以sku 以133开头的文档 } } } { "query": { "wildcard": { "name": "陈*" //匹配name以陈开头的文档 } } }
6.2.7 prefix query 前缀查询
-
将查询关键字作为一个前缀匹配查询,字符区分大小写的默认false, "case_insensitive":"true"
{ "query": { "prefix": { "Sku": { //查询以133开头的sku文档 "value": "133" } } } } { "query": { "prefix": { "Sku": "133" } } }
6.2.8 regexp query 正则匹配
- k.*y 可以匹配以k开头以y结尾的单词,ky,kay,kimy都可以匹配到
- 1344.*9可以匹配sku以13344开头,9结尾的文档
{
"query": {
"regexp": {
"Sku": {
"value":"1344.*9" //匹配sku以13344开头,9结尾的文档
// "case_insensitive":"true"
}
}
}
}
6.2.9 fuzzy query 模糊查询
- 编辑距离模糊查询
- 改变其中一个字母,比如box -> fox
- 删除其中一个字符,比如black -> lack
- 插入一个新的字母,比如sic -> sick
- 调整两个相邻字母的位置,比如cat -> act
GET: 10.158.*.*:9201/sensitive_v11/_search
{
"query": {
"fuzzy": {
"Brand": {
"value":"FUTURISTU",
"fuzziness":2 //最大编辑距离
}
}
}
}
6.3 全文检索(match)
- match查询特点:分词然后按分词匹配查找,查询的词项与倒排索引中的词项
- 分词:首先,输入的查询文本会被分词器进行分词。分词器会将文本拆分成一个个词项(terms),如单词、短
语或特定字符。分词器通常根据特定的语言规则和配置进行操作。
- 倒排索引:ES使用倒排索引来加速搜索过程。倒排索引是一种数据结构,它将词项映射到包含这些词项的文档。
每个词项都有一个对应的倒排列表,其中包含了包含该词项的所有文档的引用。
- 匹配计算:一旦查询被分词,ES将根据查询的类型和参数计算文档与查询的匹配度。对于match查询,ES将比较
查询的词项与倒排索引中的词项,并计算文档的相关性得分。相关性得分衡量了文档与查询的匹配程度。
- 结果返回:根据相关性得分,ES将返回最匹配的文档作为搜索结果。搜索结果通常按照相关性得分进行排序,以
便最相关的文档排在前面。
match_all 没有入参,查询所有文档,_search 默认返回10条
6.3.1 match 查询
- match在匹配时会对所查找的关键词进行分词,然后按分词匹配查找
#match 分词后 and的效果
{
"query": {
"match": {
"SearchBrand": {
"query": "广州白云山公园", //匹配分词包含FUTU值的文档(前后都可以,查询字段类型为text类型的
"operator":"and" //条件分词后都要匹配; 默认 or 条件分词后有一个匹配即可,即条件在倒排索引中最低的匹配度
}
}
}
}
#match 分词后or的效果
{
"query": {
"match": {
"SearchBrand": {
"query": "广州白云山公园", //匹配分词包含FUTU值的文档(前后都可以,查询字段类型为text类型的
}
}
}
}
6.3.2 multi_match 多字段查询
-
可以根据字段类型,决定是否使用分词查询,得分最高的在前面
get:10.158.*.*:9201/sensitive_v11/_search { "query": { "multi_match": { "query": "US", "fields": [ "SearchBrand", //可以根据字段类型,决定是否使用分词查询,得分最高的在前面 "Country" ] } } } { "query":{ "multi_match":{ "query":"libai", "fields":["address","name"] } } }
6. 3.3 match_phrase 短语查询
-
match_phrase 会将检索关键词分词
-
匹配的是相邻的词条
-
可以通过调整slop参数设置分词出现的最大间隔距离
get: 10.158.*.*:9201/sensitive_v11/_search { "query": { "match_phrase": { "SearchBrand": "eco" } }, "size": 10000 }
6.3.4 query_string 查询所有字段
get: 10.158.*.*:9201/sensitive_v11/_search
{
"query": {
"query_string": {
"query": "US" //所有字段查询
}
}
}
{
"query": {
"query_string": {
"query": "US",
"default_field":"Brand" //单字段查询
}
}
}
{
"query": {
"query_string": {
"query": "US",
"fields":["Brand","Country"] //多字段查询
}
}
}
6.3.5 simple_query_string
支持部分逻辑:不常用
+ 替代AND
| 替代OR
- 替代NOT
GET: 10.158.*.*:9201/sensitive_v11/_search
{
"query": {
"simple_query_string": {
"query": "US + A",
"fields":["Brand","Country"] //多字段查询
}
}
}
6.4 布尔查询(bool query)
6.4.1 must
-
布尔查询可以按照布尔逻辑条件组织多条查询语句,只有符合整个布尔条件的文档才会被搜索出来
-
在布尔条件中,可以包含两种不同的上下文。
- 搜索上下文(query context):使用搜索上下文时,Elasticsearch需要计算每个文档与搜索条件的相关度得分,
这个得分的计算需使用一套复杂的计算公式,有一定的性能开销,带文本分析的全文检索的查询语句很适合放在
搜索上下文中。
- 过滤上下文(filter context):使用过滤上下文时,Elasticsearch只需要判断搜索条件跟文档数据是否匹配,例如
使用Term query判断一个值是否跟搜索内容一致,使用Range query判断某数据是否位于某个区间等.
- 布尔查询一共支持4种组合类型:
- must 可包含多个查询条件,每个条件均满足的文档才能被搜索到,
- should可包含多个查询条件,满足多条件中的一个能被查询到
- filter可包含多个过滤条件,每个条件均满足的文档才能被搜索到
- must_not可包含多个过滤条件,每个条件均不满足的文档才能被搜索到
must
get:10.158.*.*:9201/sensitive_v11/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"Brand": "US"
}
},
{
"match": {
"Country": "US"
}
}
]
}
}
}
6.4.2 should
{
"query": {
"bool": {
"should": [
{
"match": {
"Brand": "US"
}
},
{
"match": {
"Country": "US"
}
}
]
}
}
}
6.4.3 filter
Filter:
{
"query": {
"bool": {
"filter": [
{
"term": {
"Country": "US"
}
},
{
"range": {
"UpdateTime": {
"gte": "2024-10-16T14"
}
}
}
]
}
}
}
6.5 hightlight高亮查询
-
highlight 关键字: 可以让符合条件的文档中的关键词高亮。
highlight相关属性:
pre_tags 前缀标签
post_tags 后缀标签
tags_schema 设置为styled可以使用内置高亮样式
require_field_match 多字段高亮需要设置为false
6.5.1 自定义高亮html标签
get: 10.158.*.*:9201/sensitive_v11/_search
{
"query": {
"term": {
"Brand": "US"
}
},
"highlight":{
"post_tags":["</span>"],
"pre_tags":["<span style='color:red'>"], //自定义高亮html标签
"fields":{
"Brand":{} ,
"Country":{} //多字段高亮
}
}
}
6.5 深度分页
-
from + size: 越往后翻译越慢
-
scroll 数据是非实时的,如果遍历过程中插海量数据的导出,需要查询海量结果集的数据入新的数据,是查询不到的
-
实现复杂,需要有一个全局唯一的字段连续分页的实现会比较复杂,因为每一次查询都需要上次查询的结果,它不适用于大幅度跳页查询
6.5.1 什么是深度分页
-
协调节点汇总各个分片返回的数据,再次排序,最终返回前N条数据给客户端,致一个深度分页的问题,也就是翻页越多,性能越差,甚至导致ES出现OOM
-
说当你单次查询的数量越大,那么堆内存中汇总的数据也就越多,对内存的压力也就越大
-
max_result_window,其默认值为10000,其作用是为了保护堆内存不被错误操作导致溢出
-
解决深度分页问题最好的办法就是避免使用深度分页
-
scroll滚动搜索是先搜索一批数据,然后下次再搜索下一批数据,以此类推,直到搜索出全部的数据来
-
scroll搜索会在第一次搜索的时候,保存一个当时的视图快照,之后只会基于该视图快照搜索数据,如果在搜索期间数据发生了变更,用户是看不到变更的数据的。因此,滚动查询不适合实时性要求高的搜索场景
6.5.2 scroll 及from size
注意事项
scroll滚动查询不适合实时性要求高的查询场景,比较适合数据迁移的场景。
scroll查询完毕后,要手动清理掉 scroll_id 。虽然ES有自动清理机制,但是 srcoll_id 的存在会耗费大量的资源
来保存一份当前查询结果集映像,并且会占用文件描述符。
官方建议:ES7之后,不再建议使用scroll API进行深度分页。如果要分页检索超过 Top 10,000+ 结果
时,推荐使用:PIT + search_after
get: 10.158.*.*:9201/sensitive_v11/_search?scroll=1m
{
"query": {
"match_all": {} //match_all:无参输入,查询索引中的所有文档,不写查询条件,默认返回10条记录
},
"from": 0, //开始
"size": 2 //返回条数
}
6.5.3 search_after
-
使用 search_after 需要具有相同查询和排序值的多个搜索请求,以保留搜索中的当前索引状态
-
是 Elasticsearch 7.10 版本之后才有的新特性
-
使用步骤:
-
Post:10.158..:9201/sensitive_v11/_pit?keep_alive=1m
1# 创建一个时间点(PIT)来保存搜索期间的当前索引状态 POST /sensitive_v11/_pit?keep_alive=1m 3 #返回结果,会返回一个PID的值 { "id" : "39K1AwEFZXNfZGIWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAWdkhjbE9YNVRTMUNDcWNQQVR2ZXYzdwAAAAAAAA A9jhZvaGpLSDlzVVMxbW5idG5DZ0xEUHFRAAEWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAA" } 2. 根据pit首次查询:查询入参带pit GET 10.158.*.*:9201/sensitive_v11/_search { "query": { "match_all": {} }, "pit": { "id": "39K1AwEFZXNfZGIWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAWdkhjbE9YNVRTMUNDcWNQQVR2ZXYzdwAAAAAAAAA9jhZvaGpLSDlzVVMxbW5idG5DZ0xEUHFRAAEWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAA", "keep_alive": "1m" }, "size": 2, "sort": [ { "_id": "asc" } ] } 查询结果: "hits" : { "total" : { "value" : 5, //做为下次查询分页的search_after值 3.根据search_after和pit进行翻页查询 GET 10.158.*.*:9201/sensitive_v11/_search { "query": { "match_all": {} }, "pit": { "id": "39K1AwEFZXNfZGIWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAWdkhjbE9YNVRTMUNDcWNQQVR2ZXYzdwAAAAAAAAA9jhZvaGpLSDlzVVMxbW5idG5DZ0xEUHFRAAEWZTN2N2Nrdk5RRjY3QjBma1h5aFRodwAA", "keep_alive": "1m" }, "size": 2, "sort": [ { "_id": "asc" } ], "search_after":[5] //hits做为下次查询分页的search_after值 }
-
6.5.2 常见解决方案:避免深度分页
- ES7之后,官方建议使用search_after分页,不建议使用scroll, es_db/_pit?keep_alive=1m
6.6 聚合查询
- 指定要执行的聚合操作,如 sum、avg、min、max、terms、date_histogram 等等。每个聚合命令都会生成一个聚合结果
GET <index_name>/_search
{
"aggs": {
"<aggs_name>": { // 聚合名称需要自己定义
"<agg_type>": {
"field": "<field_name>"
}
}
}
}
aggs_name:聚合函数的名称
agg_type:聚合种类,比如是桶聚合(terms)或者是指标聚合(avg、sum、min、max等)
field_name:字段名称或者叫域名。
Demo:SELECT avg(price) FROM products // min(), max(), sum() 操作
{
"aggs": {
"<avg_price>": { // 聚合名称需要自己定义
"<avg>": {
"field": "price"
}
}
}
}
- 注意:对 Text 字段进行 terms 聚合查询,会失败抛出异常
- 解决办法:对 Text 字段打开 fielddata,支持terms aggregation
7.ES优化
7.1.减少 Refresh 的次数
默认情况下索引的refresh_interval 为1 秒,每秒创建一个分段,如果我们对搜索的实效性要求不高,可以将 Refresh 周期延长,例如 30 秒,允许更大部分的flush并减少合并压力.
7.2.减少副本的数量
每个副本也会执行分析、索引及可能的合并过程,所以 Replicas 的数量会严重影响写索引的效率,当写索引时,需要把写入的数据都同步到副本节点,副本节点越多,写索引的效率就越慢,当查询较多是,副本节点会提高查询速度.
7.3.合理的分片配置
每个节点的硬件资源(CPU, RAM, I/O)将被节点上的所有分片共享,分片越少每个分片的性能将会得到提升,建议每个节点不超过2000分片,每个分片30G左右(10-50G),反之则不然。分片是一个功能完整的搜索引擎,它拥有使用一个节点上的所有资源的能力.
7.4 问题:
1.ES写的多,查询的少时?如何写优化策略?;2.ES写少,读的多实时,如何写优化策略?
2.如果每一个分片都处于不同的节点还好, 但如果多个分片都需要在同一个节点上竞争使用相同的资源就有些糟糕了,如ES 磁盘高,CPU高?可能是什么原因?
3.ES有3个node; 每个节点分片3份,共有多少分片?3x3+9=18
4.ES有3个node; 每个节点分片3份,共有多少分片?10x3+30=60 ;
5.条件查询必须判断条件是否“ ”,或查询不存在的条件值,避免导致全索引扫描,占用大量资源,或打死了整个ES.