# esStudy
**Repository Path**: zhayan/es-study
## Basic Information
- **Project Name**: esStudy
- **Description**: elasticSearch学习笔记
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-03-22
- **Last Updated**: 2022-05-25
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# ES
[运行模拟.rar](doc/es作业.rar)
## Centos7环境
### java环境安装
```
vim /etc/profile
export JAVA_HOME=/opt/jdk1.8.0_311
export CLASSPATH=.:${JAVA_HOME}/jre/lib/rt.jar:${JAVA_HOME}/lib/dt.jar:${JAVA_HOME}/lib/tools.jar
export PATH=$PATH:${JAVA_HOME}/bin
source /etc/profile
```
### Elasticsearch
```
cd /opt/elasticsearch-7.3.0
vim /opt/elasticsearch-7.3.0/config/application.yml
node.name: node-1
network.host:192.168.174.139
http.port:9200
cluster.initial_master_nodes: ["node-1"]
```
```
cd /opt/elasticsearch-7.3.0
vim /opt/elasticsearch-7.3.0/config/jvm.options
-Xms1g
-Xmx1g
```
```
# 添加es用户,es默认root无法启动,需要额外用户
useradd estest
passwd estest
123456
# es目录拥有者
chown -R estest /opt/
```
修改/etc/sysctl.conf
```
vim /etc/sysctl.conf
vm.max_map_count=655360
# 修改生效
sysctl -p
```
修改
```
vim /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536
* soft nproc 4096
* hard nproc 4096
```
启动
```
# 切换自定义的用户
su estest
# 启动(后台)
/opt/elasticsearch-7.3.0/bin/elasticsearch -d
# 启动过程中可能需要的权限
chmod -R destiny elasticsearch.keystore
chmod -R 777 /opt/
```
验证

```
192.168.137.139:9200
```
### Kibana
```
# 下载地址
https://www.elastic.co/cn/downloads/kibana
https://www.elastic.co/cn/downloads/past-releases/kibana-7-3-0
cd /opt
tar -zcvf kibana
```
```
# 设置权限
chown -R estest /opt/
chown -R estest /opt/kibana-7.3.0
# 修改配置
vim /opt/kibana-7.3.0/config/kibana.yml
server.port:5601
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://192.168.174.139:9200"]
# (后台)启动
cd /opt/
kibana-7.3.0/bin/kibana &
```
验证
```
http://192.168.174.139:5601
http://192.168.174.139:5601/app/kibana#/dev_tools/console?_g=()
```


### IK分词器
```
# 下载插件
su root
/opt/elasticsearch-7.3.0/bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysisik/releases/download/v7.3.0/elasticsearch-analysis-ik-7.3.0.zip
```
```
# 手动安装
cd /opt/elasticsearch-7.3.0/plugins/
mkdir analysis-ik
cd analysis-ik
#上传资料中的 elasticsearch-analysis-ik-7.3.0.zip
#解压
unzip elasticsearch-analysis-ik-7.3.3.zip
#解压完成后删除zip
rm -rf elasticsearch-analysis-ik-7.3.0.zip
# 重启es、kibana
```
验证ik分词
```
POST _analyze
{
"analyzer": "ik_max_word",
"text": "启动ik分词"
}
{
"tokens" : [
{
"token" : "启动",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "ik",
"start_offset" : 2,
"end_offset" : 4,
"type" : "ENGLISH",
"position" : 1
},
{
"token" : "分词",
"start_offset" : 4,
"end_offset" : 6,
"type" : "CN_WORD",
"position" : 2
}
]
}
```

### 自定义IK分词的特殊词
1. 排除分词
2. 补充同义词
## 基本操作
### 索引维护
```
# 创建索引
PUT /[indexName]
# 验证索引
HEAD /[indexName]
GET /[indexName1],[indexName2],[indexName3]
```
```
# 所有索引
GET /_cat/indices?v
POST /[indexName]/_close
POST /[indexName]/_open
DELETE /[indexName1],[indexName2],[indexName3]
```
### 字段映射
```
# 新增索引字段
PUT /[indexName]/_mapping/
{
"settings": {
},
"mappings": {
"properties": {
"aa": {
"type": [type],
"index": [index],
"store": [store],
"analyzer": [znalyzer]
}
}
}
}
# 查看
GET /_mapping
GET /[indexName]/_mapping
```
- 可新增字段
- 可补充字段
- 不可修改字段:重新建立
- 不可删除字段:重新建立
**字段类型Type:**
1. String
- text:可分词,不参与聚合
- keyword:不可分词,数据作为完整字段进行匹配,可以参与聚合
2. Numercial
- 基本数据类型:byte,short,interger,long,float,half_float
- 浮点数的高精度类型:scaled_fload
3. Date:可以怼日期格式化为字符串存储,但建议存储为毫秒值,long节省空间
4. Array
- 匹配时:任意一个元素满足,都认为满足
- 排序时:如果升序则用数组中的最小值来排序,如果降序则用数组中的最大值来排序
5. Object
```
{
name: "111",
age: 11,
aaa: {
bb: "111"
}
}
```
**索引Index:**
1. true:字段会被索引,可以用来进行搜索,默认true
2. false:字段不会被索引
**Store:**
- 是否将数据独立存储。
- 原始的文本会存储在_source里,默认其他提取出来的字段都不是独立存储的。设置store:true,解析更快,但空间占更多。默认false。
**analyzer分词器:**
- 中文一般选择ik分词器。ik_max_word,ik_smart
### 文档操作
```
#新增-指定id
POST /[indexName]/_doc/{id}
{
"key1": "value1",
"key2": "value2",
}
#新增-自动id
POST /[indexName]/_doc
{
"key1": "value1",
"key2": "value2",
}
# 查看&指定filed
GET /[indexName]/_doc/{id}?_source=key1,key2
# 查看所有
POST /[indexName]/_search
{
"query": {
"match_all": {}
}
}
# 更新文档-全部更新,不存在则新增
PUT /[indexName]/_doc/[id]
{
"key1": "value1",
"key2": "value2"
}
# 更新文档-局部更新
POST /[indexName]/_update/[id]
{
"doc": {
"key1": "value1",
"key2": "value2"
}
}
#删除
DELETE /[indexName]/_doc/[id]
#查询删除
POST /[indexName]/_delete_by_query
{
"query": {
"filed": "value"
}
}
```
**元数据项:**
| | |
| ------------- | ------------------------------------------------------------ |
| _index | 文档所属index |
| _type | 文档所属type,7.x默认为**_doc** |
| _id | 代表document的唯一标识,与index和type一起,可以唯一标识和定位一个 document |
| _version | document的版本号,Elasticsearch利用_version (版本号)的方式来确保应用 中相互冲突的变更不会导致数据丢失。需要修改数据时,需要指定想要修改文 档的version号,如果该版本不是当前版本号,请求将会失败 |
| _seq_no | 严格递增的顺序号,每个文档一个,Shard级别严格递增,保证后写入的Doc seq_no大于先写入的Doc的seq_no |
| _primary_term | 任何类型的写操作,包括index、create、update和Delete,都会生成一个 _seq_no。 |
| found | true/false,是否查找到文档 |
| _source | 存储原始文档 |
## 高级应用
### 高级映射
#### 地理坐标
```
# 字符串形式
PUT /company-locations/_doc/1
{
"name":"NetEase",
"location":"40.715,74.011"
}
# 对象形式
PUT /company-locations/_doc/2
{
"name":"Sina",
"location":{
"lat":40.722,
"lon":73.989
}
}
# 数组形式
PUT /company-locations/_doc/3
{
"name":"Baidu",
"location":[73.983,40.719]
}
```
| 过滤器 | |
| ------------------ | ------------------------------------------------------------ |
| geo_bounding_box | 矩形:找出落在指定矩形框中的点 |
| geo_distance | 圆:找出与指定位置在给定距离内的点 |
| geo_distance_range | 环:找出与指定点距离在给定最小距离和最大距离之间的点 |
| geo_polygon | 多边形:找出落在多边形中的点。 这个过滤器使用代价很大 。当你觉得自己 需要使用它,最好先看看 geo-shapes 。 |
```
GET /company-locations/_search
{
"query": {
"bool" : {
"must" : {
"match_all" : {}
},
"filter" : {
"geo_bounding_box" : {
"location" : {
"top_left" : {
"lat" : 40.73,
"lon" : 71.12
},
"bottom_right" : {
"lat" : 40.01,
"lon" : 74.1
}
}
}
}
}
}
}
GET /company-locations/_search
{
"query": {
"bool" : {
"must" : {
"match_all" : {}
},
"filter" : {
"geo_distance" : {
"distance" : "200km",
"location" : {
"lat" : 40,
"lon" : 70
}
}
}
}
}
}
```
#### 动态映射
是否可以自由向文档中添加新的字段。
mappings.dynamic
- true:遇到陌生字段就执行dynamic mapping处理机制
- false:遇到陌生字段就忽略
- strict:遇到陌生字段就报错,最好使用该参数,规范开发。
#### 自定义动态映射
如果你想在运行时增加新的字段,你可能会启用动态映射。
1. 日期检测:遇到新的字符串字段时,会检测是否包含一个可识别的日期。如果包含该字段会被当做date类型添加,后续的非日期的string类型更新/新增会异常;否则当做string类型。
2. dynamic_templates:控制新生成字段的映射。同一个字段可以生成多个不同的映射,设置不同的分词等。
### Query DSL
基于JSON的完整查询DSL-Domain Specific Language特定域的语言,来定义查询。
```
POST /[indexName]/_search
{
"query": {
"查询类型": {
"查询条件": "查询条件值",
"operator": "and/or"
}
}
}
```
**查询类型:**
- match_all
- match:分词查询
- match_phrase:短语查询
- multi_match:
```
GET /[indexName]/_search
{
"query": {
"multi_match" : {
"query":"2699",
"fields": [ "title","price"]
}
}
}
```
- query_string:
- term:词条查询
```
GET /book/_search
{
"query": {
"term" : { "name" : "solr"}
}
}
```
- terms:查询
```
GET /book/_search
{
"query": {
"terms" : { "name" : ["solr", "elasticsearch"]}
}
}
```
- range:范围查询
- get
- gt
- lte
- lt
- boost权重查询
- exists不为空查询:相当于sql中的 column is not null
```
GET /book/_search
{
"query": {
"exists" : { "field" : "price" }
}
}
```
- prefix词项前缀搜索
```
GET /book/_search
{
"query": {
"prefix" : { "name" : "so" }
}
}
```
- 通配符查询wildcard
```
GET /book/_search
{
"query": {
"wildcard" : { "name" : "so*r" }
}
}
```
- 正则regexp:**注意性能问题**
```
GET /book/_search
{
"query": {
"regexp":{
"name": "s.*"
}
}
}
```
- fuzzy模糊搜索
```
GET /book/_search
{
"query": {
"fuzzy" : { "name" : "so" }
}
}
```
- ids搜索:id集合查询
```
GET /book/_search
{
"query": {
"ids" : {
"type" : "_doc",
"values" : ["1", "3"]
}
}
}
```
- 复合查询-constant_score_query:评分设为一个常值
```
GET /book/_search
{
"query": {
"constant_score" : {
"filter" : {
"term" : { "description" : "solr"}
},
"boost" : 1.2
}
}
}
```
- 复合查询-bool:
- must:必须满足,参与、影响评分
- filter:必须满足,执行的是filter上下文,不参与、不影响评分
- should:或
- must_not:必须不满足,执行的是filter上下文,不参与、不影响评分
- 额外的参数控制:minimum_should_match代表最小匹配精度,should语句至少需要满足几个条件。
- 排序:
```
POST /book/_search
{
"query": {
"match": {"description":"solr"}
},
"sort": [
{
"_score": {"order": "asc/desc"},
"filed": {"order": "asc/desc"},
}
]
}
```
- 相关性评分排序:最相关的score最大,排列最靠前
- 字段值排序
- 多级排序
- 分页查询:size/from
```
POST /book/_search
{
"query": {
"match_all": {}
},
"sort": [
{"price": {"order": "desc"}}
],
"size": 2,
"from": 2
}
```
- 高亮:
```
POST /book/_search
{
"query": {
"query_string" : {
"query" : "elasticsearch"
}
},
"highlight": {
"pre_tags": "",
"post_tags": "",
"fields": [{"name":{}},{"description":{}}]
}
}
```
- 文档批量操作:bulk、mget
bulk需要根据不同机器压测出最大的可执行数量。bulk会将要处理的数据载入内存中,数量有限。一般建议1000-5000个文档,大小建议5-15MB,默认不能超过100MB,elasticsearch.yml中配置http.max_content_length:10mb
```
GET /_mget
{
"docs" : [
{
"_index" : "book",
"_id" : 1
},
{
"_index" : "book",
"_id" : 2
}
]
}
POST /_bulk
{ "delete": { "_index": "book", "_id": "1" }}
{ "create": { "_index": "book", "_id": "5" }}
{ "name": "test14","price":100.99 }
{ "update": { "_index": "book", "_id": "2"} }
{ "doc" : {"name" : "test"} }
```
### Filter DSL
- 过滤器不会计算相关度的得分,计算更快
- 过滤器可以被缓存到内存中,重复查询更快
#### 定位非法搜索
- _validate
- explain
```
GET /book/_validate/query?explain
{
"query": {
"match1": {
"name": "test"
}
}
}
```
### 聚合分析
完成对一个查询的数据集中数据的聚合计算。
对一个数据集求最大、最小、和、平均值等指标的聚合,在ES中称为**指标聚合** metric 而关系型数据库中除了有聚合函数外,还可以对查询出的数据进行分组group by,再在组上进行指标聚合。**在 ES 中group by 称为分桶,桶聚合 bucketing**
```
"aggregations" : {
"" : {
"" : {
}
[,"meta" : { [] } ]?
[,"aggregations" : { []+ } ]?
}
```
#### 指标聚合
#### 桶聚合
### 零停机索引重建
1. 外部数据导入
2. 基于scroll+bulk+索引别名方案
3. Reindex API方案
### 智能搜索建议
1. Term suggester
2. Phrase suggester
3. Completion suggester
4. Context sugester
### java client
#### 索引创建
#### 新增
#### 修改
#### 删除
#### 查询
1. term
2. bool
3. page+sorted
## 集群与高级实战
### 基本概念
1. 集群Cluster
一个Elasticsearch集群由多个节点组成,每个集群都有一个共同的集群名称作为标识
2. 节点Node
- 一个es实例为一个Node,一台机器可以有多个实例
- node.master:标识节点是否具有成为节点的资格
- node.data:标识节点是否存储数据
3. Node节点组合
- 默认主节点+数据节点:node.master:true,node.data:true
- 数据节点:node.master:false,node.data:true
- 客户端节点:针对海量请求进行负载均衡,node.master:false,node.data:false
4. 分片:每个索引有一个或多个分片,每个分片存储不同的数据。主分片primary shard、复制分片replica shard;复制分片是主分片的拷贝,默认每个主分片有一个复制分片,每个索引的复制分片数量可以动态调整,也不与它的主分片在同一个节点。
5. 副本:主分片的副本分片。
- 提高恢复能力。主分片挂掉,成为主分片
- 提高性能:get、search请求可以由主分片又可以由复制分片处理
### 分布式架构
1. 高扩展性:节点添加、集群发现简单
2. 高可用性:分布式的,节点备份,
3. 实时性:使用倒排索引来建立存储结构,搜索时长在百毫秒内
**分层:**
1. Gateway
2. Lucene
3. es数据的加工处理
4. es发现机制、脚本
5. es的交互方式:thrift、memcached、http
6. es的api支持模式:restful style api。
**分布式架构:**
1. 集群发现机制:单播、多播
2. shard负载均衡:分片
3. 扩容机制:垂直-机器增强、水平-节点数
4. rebalance:节点动态平衡
**主节点:**
主节点的主要职则是和集群操作的相关内容,如**创建或删除索引**,跟踪哪些节点是集群的一部分,并决定哪些分片分配给相关的节点。稳定的主节点对集群的健康是非常重要的。
**节点对等:**
每个节点都能接受请求,每个节点接受到请求后都能把该请求路由到有相关数据的其它节点上,接受原 始请求的节点负责采集数据并返回给客户端。
### 集群规划
**考虑点:**
1. 当前数据量、增长情况
2. 机器配置
**节点角色:**
1. master
2. data node
3. corrdinate node协调节点:接收请求、转发请求到其他节点、汇总各个节点返回数据等
**避免脑裂:**
节点心跳、选举的配置:
- cluster.initial_master_nodes
- discovery.request_peers_timeout
- discovery.zen.ping_timeout
**分片与副本设置:**
1. jvm的最大堆
2. 按照节点的1.5-3倍的原则创建分片。
3. 副本数,提高并发查询能力
```
PUT /my_temp_index/_settings
{
"number_of_replicas": 1
}
```
### 集群调优策略
**index写调优:**
1. 副本数设置为0:大批量数据的添加,添加后再重新调整
2. 自动生成doc id:如果指定外部id,会先尝试读取原来的doc版本号,判断是否需要更新。涉及一次磁盘读取
3. 合理设置mappings:keyword、no_analyzed、字段长度控制、分析器有差异
4. 调整_source字段:是否存储原始数据,一般不禁用
5. 对analyzed的字段禁用norms:不需要评分,则禁用
6. 调整索引刷新间隔:缺省1s,强制es每秒创建一个新segment来保证新写入的数据近实时可见。降低刷新间隔可以释放系统刷新的资源。
7. 批处理:压测单个node、单个shard获取最优参数
8. document路由处理:是否指定 /index/doc/id?routing=***,默认routing=id
**index读调优:**
1. 数据分组,分片,索引
2. Filter代替query:现在可评分的查询,不需要评分使用filter
3. ID字段定义为keyword,如果字段不会被range类型搜索,定义为keyword,性能提升30%
4. 限制用户的查询入参:or,*等
## 数据建模
### mapping设置
1. [mappings参数](https://www.elastic.co/guide/en/elasticsearch/reference/7.3/mapping-params.html)
2. mapping设置

### es关联关系
1. application-side joins:代码中进行关联
2. data denormalization数据的非规范化:字段进行冗余
3. nested objects嵌套文档:牺牲建立索引性能(文档内任一属性变化都需要重新索引该文档)来换取查询性能。需要特殊查询语句。
4. parent、child relationships父子文档:档牺牲了一定的查询性能来换取索引性能,适用于写多读少的场景
## 应用原理
### 写入与近实时搜索
### 段合并
### 并发冲突处理
### Query文档搜索机制
### 文档增删改查和搜索请求过程
### 相关性评分算法BM25
### DocValues机制
### Filter过滤
### 控制搜索精度-基于boost的细粒度&权重
### 控制搜索精度-dis_max实现best fields策略
### 控制搜索精度-function_score自定义相关度分数算法
### bulk操作与底层性能优化
### 深度分页与解决