first commit

This commit is contained in:
iProbe 2022-10-18 16:59:37 +08:00
commit ba848e218d
1001 changed files with 152333 additions and 0 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

21
ELK/ELK创建索引.md Normal file
View file

@ -0,0 +1,21 @@
如果logstash(filebeat)收集到的数据es的默认映射不能满足比如说需要把数据中的数字解析成数字类型嵌套json问题等需要定义映射mapping但是索引一般是按照日期创建的如果对每个索引创建映射非常麻烦这时可以使用索引模板。
```
PUT /_template/my_logs ## 创建一个名为 my_logs 的模板。
{
"template": "logstash-*", ## 将这个模板应用于所有以 logstash- 为起始的索引
"order": 1, ## 这个模板将会覆盖默认的 logstash 模板,因为默认模板的 order 更低
"settings": {
"number_of_shards": 1 ## 限制主分片数量为 1
},
"mappings": {
"_default_": {
"_all": {
"enabled": false ## 为所有类型禁用 _all 域
}
}
},
"aliases": {
"last_3_months": {} ## 添加这个索引至 last_3_months 别名中
}
}
```

49
ELK/ELK安全.md Normal file
View file

@ -0,0 +1,49 @@
es由x-pack提供安全。配置elasticsearch.yaml
```
xpack.security.enabled: true
```
#### 为内置用户设置密码
```
./bin/elasticsearch-setup-passwords interactive
```
### 配置kibana
可以在kibana.yml中配置es的密码
```
elasticsearch.username: "kibana"
elasticsearch.password: "your_password"
```
或者使用密钥库存储
```
./bin/kibana-keystore create
./bin/kibana-keystore add elasticsearch.username
./bin/kibana-keystore add elasticsearch.password
```
还可以在启动时,加上参数
```
./bin/kibana --elasticsearch.hosts="http://localhost:9200" --elasticsearch.username=kibana --elasticsearch.password=password
```
### 配置logstash
使用logstash-keystore 存储敏感数据
```
bin/logstash-keystore create
bin/logstash-keystore add ES_HOST
bin/logstash-keystore add LS_USER
bin/logstash-keystore add LS_PWD
```
查看存储的数据
```
./bin/logstash-keystore list
```
logstash配置输出
```
output {
elasticsearch {
hosts => ["${ES_HOST}"]
user => "${LS_USER}"
password => "${LS_PWD}"
}
```

View file

@ -0,0 +1,11 @@
## 删除索引
```
# kibana
# 删除2022年9月份的索引
DELETE /logstash-2022-09-*
```
## 回收磁盘空间
```
curl -XPOST 'http://xxxxxx:9200/_forcemerge?only_expunge_deletes=true'
```

Binary file not shown.

View file

@ -0,0 +1,13 @@
##### 用于错误等多行日志输出为同一事件
https://www.elastic.co/guide/en/logstash/current/plugins-codecs-multiline.html
```
input {
...
codec => mutiline {
pattern => "" ## 正则匹配,哪些数据为一行
negate => "true" or "false"
what => "previous" or "next"
}
...
}
```

18
ELK/es 读写过程.md Normal file
View file

@ -0,0 +1,18 @@
# es 写数据过程
客户端选择一个 node 发送请求过去,这个 node 就是 coordinating node协调节点
coordinating node 对 document 进行路由,将请求转发给对应的 node有 primary shard
实际的 node 上的 primary shard 处理请求,然后将数据同步到 replica node。
coordinating node 如果发现 primary node 和所有 replica node 都搞定之后,就返回响应结果给客户端。
# es 读数据过程
可以通过 doc id 来查询,会根据 doc id 进行 hash判断出来当时把 doc id 分配到了哪个 shard 上面去,从那个 shard 去查询。
客户端发送请求到任意一个 node成为 coordinate node。
coordinate node 对 doc id 进行哈希路由,将请求转发到对应的 node此时会使用 round-robin 随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。
接收请求的 node 返回 document 给 coordinate node。
coordinate node 返回 document 给客户端。
# es搜索过程
客户端发送请求到一个 coordinate node。
协调节点将搜索请求转发到所有的 shard 对应的 primary shard 或 replica shard都可以。
query phase每个 shard 将自己的搜索结果(其实就是一些 doc id返回给协调节点由协调节点进行数据的合并、排序、分页等操作产出最终结果。
fetch phase接着由协调节点根据 doc id 去各个节点上拉取实际的 document 数据,最终返回给客户端。

19
ELK/es修改文档.md Normal file
View file

@ -0,0 +1,19 @@
### 覆盖式修改,指定id
```
put /index/book/1
{
"name": "test",
"version": "v1"
}
```
### 指定字段修改
```
post /index/book/1/_update
{
"doc":
{
"version": "v2"
}
}
```

View file

@ -0,0 +1,5 @@
```
bin/elasticsearch -E node.name=node1 -E cluster.name=ihi.im -E path.data=node1_data -d
bin/elasticsearch -E node.name=node2 -E cluster.name=ihi.im -E path.data=node1_data -d
bin/elasticsearch -E node.name=node3 -E cluster.name=ihi.im -E path.data=node1_data -d
```

135
ELK/es基础.md Normal file
View file

@ -0,0 +1,135 @@
#### es配置建议
1、jvm中的xmx不要超过机器内存的一半
2、不要超过30G
#### 查看es安装的插件
```
bin/elasticsearch-plugin list
```
#### 安装插件
```
## 安装分析器(analysis-icu国际化分析插件)
bin/elasticsearch-plugin install analysis-icu
```
#### 查看集群运行了哪些节点
```
# 浏览器访问
http://localhost:9200/_cat/nodes
```
#### _all字段表示所有数据7.0+已废除
#### Phrase查询需要使用引号
```
GET /movies/_search?q=title:"Beautiful Mind"
{
"profile":"true"
}
```
#### AND OR NOT等
```
# AND,OR,NOR必须大写
## title中包含 Beautiful和Mind
GET /movies/_search?q=title:(Beautiful AND Mind)
{
"profile":"true"
}
## title中包含 Beautiful不包含Mind
GET /movies/_search?q=title:(Beautiful NOT Mind)
{
"profile":"true"
}
## title中包含 Beautiful必须包含Mind%2B为=
GET /movies/_search?q=title:(Beautiful %2BMind)
{
"profile":"true"
}
```
#### 近似查询
```
## beautiful输入错误
GET /movies/_search?q=title:beautilfl~1
{
"profile":"true"
}
```
#### 模糊查询
```
## 搜索Lord of The Rings
GET /movies/_search?q=title:"Lord Rings"~2
{
"profile":"true"
}
```
#### 设置mappings
```
PUT movies
{
"mappings": {
"_doc": {
"dynamic": "false" ## 新文档的新增字段无法索引文档可以索引mappings不更新
}
}
}
PUT movies
{
"mappings": {
"_doc": {
"dynamic": "true" ## 新文档的新增字段可以索引文档可以索引mappings更新
}
}
}
PUT movies
{
"mappings": {
"_doc": {
"dynamic": "stict" ## 新文档的新增字段不可以索引文档不可以索引mappings不更新数据写入直接拒绝报错
}
}
}
PUT users
{
"mappings": {
"mobile": {
"type": "text"
"index": "false" ## 该字段不索引true表示需要索引
}
}
}
PUT users
{
"mappings": {
"mobile": {
"type": "keyword"
"null_value": "NULL" ## 可以直接查询"mobile": "NULL"
}
}
}
## 把firstName和lastName复制到fullName中即使新文档没有fullName字段也可以查询fullName结果展示中不存在fullName
PUT users
{
"mappings": {
"properties": {
"firstName": {
"type": "text"
"copy_to": "fullName"
},
"lastName": {
"type": "text"
"copy_to": "fullName"
}
}
}
}
```

View file

@ -0,0 +1,34 @@
Elasticsearch 不仅仅是 Lucene并且也不仅仅只是一个全文搜索引擎。 它可以被下面这样准确的形容:
一个分布式的实时文档存储,每个字段 可以被索引与搜索
一个分布式实时分析搜索引擎
能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据
es特性
分配文档到不同的容器 或 分片 中,文档可以储存在一个或多个节点中
按集群节点来均衡分配这些分片,从而对索引和搜索过程进行负载均衡
复制每个分片以支持数据冗余,从而防止硬件故障导致的数据丢失
将集群中任一节点的请求路由到存有相关数据的节点
集群扩容时无缝整合新节点,重新分配分片以便从离群节点恢复
集群是由一个或者多个拥有相同 cluster.name 配置的节点组成, 它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。当一个节点被选举成为 主 节点时, 它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。 而主节点并不需要涉及到文档级别的变更和搜索等操作,所以当集群只拥有一个主节点的情况下,即使流量的增加它也不会成为瓶颈。
一个运行中的 Elasticsearch 实例称为一个节点,而集群是由一个或者多个拥有相同 cluster.name 配置的节点组成, 它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。
当一个节点被选举成为 主 节点时, 它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。 而主节点并不需要涉及到文档级别的变更和搜索等操作,所以当集群只拥有一个主节点的情况下,即使流量的增加它也不会成为瓶颈。 任何节点都可以成为主节点。
一个分片是一个 Lucene 的实例,它本身就是一个完整的搜索引擎。 我们的文档被存储和索引到分片内,但是应用程序是直接与索引而不是与分片进行交互。
Elasticsearch 是利用分片将数据分发到集群内各处的。分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。 当你的集群规模扩大或者缩小时, Elasticsearch 会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。
一个分片可以是 主 分片或者 副本 分片。 索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。
在索引建立的时候就已经确定了主分片数但是副本分片数可以随时修改。索引在默认情况下会被分配5个主分片
一个文档的 _index 、 _type 和 _id 唯一标识一个文档
类型 在 Elasticsearch 中表示一类相似的文档。 类型由 名称 —比如 user 或 blogpost —和 映射 组成。
映射, 就像数据库中的 schema ,描述了文档可能具有的字段或 属性 、每个字段的数据类型—比如 string, integer 或 date —以及Lucene是如何索引和存储这些字段的。

View file

@ -0,0 +1,20 @@
### 启动失败,报
```
[1] bootstrap checks failed
[1]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be configured
```
修改配置文件elasticsearch.yml文件至少一项配置放开即可discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes这里修改cluster.initial_master_nodes: : ["node-1"]
### 往es中写数据,报
```
curl -XPUT 127.0.0.1:9200/item/es/1?pretty -d '{"name": "wang", "age": 25}'
{
"error" : "Content-Type header [application/x-www-form-urlencoded] is not supported",
"status" : 406
}
```
写入数据时,加上-H 'content-Type:application/json' 即可,如下
```
curl -XPUT 127.0.0.1:9200/item/es/1?pretty -H 'content-Type:application/json' -d '{"name": "wang", "age": 25}'
```

View file

@ -0,0 +1,62 @@
#### 写入数据:
举例说明在索引名称未item中添加一个类型名称为es编号为3的数据
```
curl -XPUT 127.0.0.1:9200/item/es/3?pretty -H 'content-Type:application/json' -d '{"name": "bi", "age": 21}'
```
```
curl -XPOST 127.0.0.1:9200/item/es/3?pretty -H 'content-Type:application/json' -d '{"name": "bi", "age": 21}'
```
结果如下
```
{
"_index" : "item", ## 索引
"_type" : "es", ## 类型名称
"_id" : "3", ## 编号
"_version" : 1, ## 对该数据的第几次操作
"result" : "created", ## 因为之前没有,即创建
"_shards" : {
"total" : 2, ## 分片数
"successful" : 1, ## 分片成功次数
"failed" : 0 ## 分片失败数
},
"_seq_no" : 4, ## 序列编号
"_primary_term" : 1 ##
}
```
### get数据
```
curl -XGET 127.0.0.1:9200/item/es/3?pretty
```
结果为
```
{
"_index" : "item",
"_type" : "es",
"_id" : "3",
"_version" : 1,
"_seq_no" : 4,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "bi",
"age" : 21
}
}
```
### 搜索数据
```
curl -XGET 127.0.0.1:9200/item/es/_search?pretty
```
返回的结果方在hints数组中默认展示匹配到的前10条数据
### 精确搜索
```
curl -XGET 127.0.0.1:9200/item/es/_search?q=name:wang?pretty
```
```
curl -XGET 127.0.0.1:9200/item/es/_search?q=name:bi
```

View file

@ -0,0 +1,62 @@
```
# 说明: 在索引为megacorp类型为employee的文档中查找last_name为smith年龄大于30岁的人
GET /megacorp/employee/_search
{
"query" : {
"bool": {
"must": {
"match" : {
"last_name" : "smith"
}
},
"filter": {
"range" : {
"age" : { "gt" : 30 }
}
}
}
}
```
```
# 说明:全文搜索,相关性搜索。所有有"rock“或”climbing"的文档都被查找出来根据_score大小排序
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"about" : "rock climbing"
}
}
}
```
```
说明找出一个属性中的独立单词是没有问题的但有时候想要精确匹配一系列单词或者_短语_ 。 比如, 我们想执行这样一个查询,仅匹配同时包含 “rock” 和 “climbing” ,并且 二者以短语 “rock climbing” 的形式紧挨着的雇员记录。
为此对 match 查询稍作调整,使用一个叫做 match_phrase 的查询
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}
```
```
说明:新增一个查询参数--highlight--高亮。当执行该查询时,返回结果与之前一样,与此同时结果中还多了一个叫做 highlight 的部分。这个部分包含了 about 属性匹配的文本片段,并以 HTML 标签 <em></em> 封装
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
},
"highlight": {
"fields" : {
"about" : {}
}
}
}
```

View file

@ -0,0 +1,16 @@
### 创建新文档
_index 、 _type 和 _id 的组合可以唯一标识一个文档。所以,确保创建一个新文档的最简单办法是,使用索引请求的 POST 形式让 Elasticsearch 自动生成唯一 _id
如果已经有自己的 _id ,那么我们必须告诉 Elasticsearch ,只有在相同的 _index 、 _type 和 _id 不存在时才接受我们的索引请求。这里有两种方式,他们做的实际是相同的事情。使用哪种,取决于哪种使用起来更方便。
第一种使用op_type查询-字符串参数
```
PUT /website/blog/123?op_type=create
{ ... }
```
第二种,在 URL 末端使用 /_create :
```
PUT /website/blog/123/_create
{ ... }
```
如果具有相同的 _index 、 _type 和 _id 的文档已经存在Elasticsearch 将会返回 409 Conflict 响应码

View file

@ -0,0 +1,42 @@
### 路由一份文档到分片
一份文档在哪个分片,由以下公式决定
```
shard = hash(routing) % number_of_primary_shards
```
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。 routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到 余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置
所以规定:创建索引的时候,主分片的数量不能变,不然之前路由的值都会无效,文档再也找不到了
所有的文档 API get 、 index 、 delete 、 bulk 、 update 以及 mget )都接受一个叫做 routing 的路由参数 ,通过这个参数我们可以自定义文档到分片的映射。一个自定义的路由参数可以用来确保所有相关的文档——例如所有属于同一个用户的文档——都被存储到同一个分片中。
### 写操作过程(创建文档,索引,删除等)
```
1、客户端向 某个节点node [协调节点]发送新建、索引或者删除请求。
2、节点[协调节点]使用文档的 _id 确定文档属于哪个分片 。请求会被转发到该分片的主分片所在的节点node 上。
3、该节点node在主分片上面执行请求。如果成功了它将请求并行转发到 该主分片的其他副本分片上。一旦所有的副本分片都报告成功, 该节点将向协调节点报告成功,协调节点向客户端报告成功。
```
### 其他可能以数据安全为代价提升性能的参数
#### consistency
```
consistency即一致性。在默认设置下即使仅仅是在试图执行一个_写_操作之前主分片都会要求 必须要有 规定数量(quorum)或者换种说法也即必须要有大多数的分片副本处于活跃可用状态才会去执行_写_操作(其中分片副本可以是主分片或者副本分片)。这是为了避免在发生网络分区故障network partition的时候进行_写_操作进而导致数据不一致。_规定数量_即
int( (primary + number_of_replicas) / 2 ) + 1
consistency 参数的值可以设为 one (只要主分片状态 ok 就允许执行_写_操作,all必须要主分片和所有副本分片的状态没问题才允许执行_写_操作, 或 quorum 。默认值为 quorum , 即大多数的分片副本状态没问题就允许执行_写_操作。
注意,规定数量 的计算公式中 number_of_replicas 指的是在索引设置中的设定副本分片数,而不是指当前处理活动状态的副本分片数。如果你的索引设置中指定了当前索引拥有三个副本分片,那规定数量的计算结果即:
int( (primary + 3 replicas) / 2 ) + 1 = 3
如果此时你只启动两个节点,那么处于活跃状态的分片副本数量就达不到规定数量,也因此您将无法索引和删除任何文档。
```
#### timeout
```
如果没有足够的副本分片会发生什么? Elasticsearch会等待希望更多的分片出现。默认情况下它最多等待1分钟。 如果你需要,你可以使用 timeout 参数 使它更早终止: 100 100毫秒30s 是30秒。
```
### 局部更新
```
1、客户端向某个节点[协调节点]发送更新请求。
2、该节点[协调节点]将请求转发到该文档的主分片所在节点。
3、该节点从主分片检索文档修改 _source 字段中的 JSON ,并且尝试重新索引主分片的文档。 如果文档已经被另一个进程修改,它会重试步骤 3 ,超过 retry_on_conflict 次后放弃。
4、如果 主分片所在节点成功地更新文档,它将新版本的文档并行转发到副本分片,重新建立索引。 一旦所有副本分片都返回成功, 主分片所在的节点向协调节点也返回成功,协调节点向客户端返回成功。
```

View file

@ -0,0 +1,8 @@
### 检索文档
```
1、客户端向 任意节点node 发送获取请求。
2、该节点使用文档的 _id 来确定文档属于哪个分片 。使用随机轮询算法,在所有包含该分片(主副分片)的节点上,随机选择一个,响应请求
3、响应请求的节点将结果返回给 请求的节点,请求的节点将文档返回给客户端。
```

View file

@ -0,0 +1,64 @@
### 主分片与副本分片
number_of_shards
每个索引的主分片数,默认值是 5 。这个配置在索引创建后不能修改。
number_of_replicas
每个主分片的副本数,默认值是 1 。对于活动的索引库,这个配置可以随时修改。
#### 创建一个有1个主分片无副本分片的索引
```
PUT /my_temp_index
{
"settings": {
"number_of_shards" : 1,
"number_of_replicas" : 0
}
}
```
#### 修改索引副本分片数量
```
PUT /my_temp_index/_settings
{
"number_of_replicas": 2
}
```
### 分析器
standard 分析器是用于全文字段的默认分析器,对于大部分西方语系来说是一个不错的选择。 它包括了以下几点:
standard 分词器,通过单词边界分割输入的文本。
standard 语汇单元过滤器,目的是整理分词器触发的语汇单元(但是目前什么都没做)。
lowercase 语汇单元过滤器,转换所有的语汇单元为小写。
stop 语汇单元过滤器,删除停用词—​对搜索相关性影响不大的常用词,如 a the and is 。
默认情况下,停用词过滤器是被禁用的。如需启用它,你可以通过创建一个基于 standard 分析器的自定义分析器并设置 stopwords 参数。 可以给分析器提供一个停用词列表,或者告知使用一个基于特定语言的预定义停用词列表。
在下面的例子中,我们创建了一个新的分析器,叫做 es_std 并使用预定义的西班牙语停用词列表:
```
PUT /spanish_docs
{
"settings": {
"analysis": {
"analyzer": {
"es_std": {
"type": "standard",
"stopwords": "_spanish_"
}
}
}
}
}
```
es_std 分析器不是全局的—​它仅仅存在于我们定义的 spanish_docs 索引中。 为了使用 analyze API来对它进行测试我们必须使用特定的索引名
```
GET /spanish_docs/_analyze?analyzer=es_std
El veloz zorro marrón
```
简化的结果显示西班牙语停用词 El 已被正确的移除:
```
{
"tokens" : [
{ "token" : "veloz", "position" : 2 },
{ "token" : "zorro", "position" : 3 },
{ "token" : "marrón", "position" : 4 }
]
}
```

View file

@ -0,0 +1,146 @@
es是使用json存储文档json会把文档处理成扁平化式的键值对结构。
这时,搜索时,可能会因为字段一样,把数据张冠李戴。举例如下:
```
PUT /my_index/blogpost/1
{
"title": "Nest eggs",
"body": "Making your money work...",
"tags": [ "cash", "shares" ],
"comments": [
{
"name": "John Smith",
"comment": "Great article",
"age": 28,
"stars": 4,
"date": "2014-09-01"
},
{
"name": "Alice White",
"comment": "More like this please",
"age": 31,
"stars": 5,
"date": "2014-10-22"
}
]
}
```
es存储的结构如下
```
{
"title": [ eggs, nest ],
"body": [ making, money, work, your ],
"tags": [ cash, shares ],
"comments.name": [ alice, john, smith, white ],
"comments.comment": [ article, great, like, more, please, this ],
"comments.age": [ 28, 31 ],
"comments.stars": [ 4, 5 ],
"comments.date": [ 2014-09-01, 2014-10-22 ]
}
```
但是搜索的时候,就可能出现错误的数据
```
GET /_search
{
"query": {
"bool": {
"must": [
{ "match": { "name": "Alice" }},
{ "match": { "age": 28 }}
]
}
}
}
```
数据的相关性完全消失。
嵌套对象 就是来解决这个问题的。将 comments 字段类型设置为 nested 而不是 object 后,每一个嵌套对象都会被索引为一个 隐藏的独立文档 ,举例如下:
```
{
"comments.name": [ john, smith ],
"comments.comment": [ article, great ],
"comments.age": [ 28 ],
"comments.stars": [ 4 ],
"comments.date": [ 2014-09-01 ]
}
{
"comments.name": [ alice, white ],
"comments.comment": [ like, more, please, this ],
"comments.age": [ 31 ],
"comments.stars": [ 5 ],
"comments.date": [ 2014-10-22 ]
}
{
"title": [ eggs, nest ],
"body": [ making, money, work, your ],
"tags": [ cash, shares ]
}
```
在独立索引每一个嵌套对象后,对象中每个字段的相关性得以保留。我们查询时,也仅仅返回那些真正符合条件的文档。
不仅如此,由于嵌套文档直接存储在文档内部,查询时嵌套文档和根文档联合成本很低,速度和单独存储几乎一样。
嵌套文档是隐藏存储的,我们不能直接获取。如果要增删改一个嵌套对象,我们必须把整个文档重新索引才可以。值得注意的是,查询的时候返回的是整个文档,而不是嵌套文档本身。
设置一个字段为 nested 很简单 —  你只需要将字段类型 object 替换为 nested 即可
```
PUT /my_index
{
"mappings": {
"blogpost": {
"properties": {
"comments": {
"type": "nested",
"properties": {
"name": { "type": "string" },
"comment": { "type": "string" },
"age": { "type": "short" },
"stars": { "type": "short" },
"date": { "type": "date" }
}
}
}
}
}
}
```
由于嵌套对象 被索引在独立隐藏的文档中,我们无法直接查询它们,必须使用 nested 查询 去获取它们:
```
GET /my_index/blogpost/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "eggs"
}
},
{
"nested": {
"path": "comments",
"query": {
"bool": {
"must": [
{
"match": {
"comments.name": "john"
}
},
{
"match": {
"comments.age": 28
}
}
]
}
}
}
}
]
}}}
```
nested 字段可以包含其他的 nested 字段。同样地nested 查询也可以包含其他的 nested 查询。而嵌套的层次会按照你所期待的被应用。
nested 查询肯定可以匹配到多个嵌套的文档。每一个匹配的嵌套文档都有自己的相关度得分,但是这众多的分数最终需要汇聚为可供根文档使用的一个分数。
默认情况下,根文档的分数是这些嵌套文档分数的平均值。可以通过设置 score_mode 参数来控制这个得分策略,相关策略有 avg (平均值), max (最大值), sum (加和) 和 none (直接返回 1.0 常数值分数)。

View file

@ -0,0 +1,64 @@
索引 别名 就像一个快捷方式或软连接可以指向一个或多个索引也可以给任何一个需要索引名的API来使用。别名 带给我们极大的灵活性,允许我们做下面这些:
在运行的集群中可以无缝的从一个索引切换到另一个索引
给多个索引分组 (例如, last_three_months)
给索引的一个子集创建 视图
有两种方式管理别名: _alias 用于单个操作, _aliases 用于执行多个原子级操作。
在本章中,我们假设你的应用有一个叫 my_index 的索引。事实上, my_index 是一个指向当前真实索引的别名。真实索引包含一个版本号: my_index_v1 my_index_v2 等等。
首先,创建索引 my_index_v1 ,然后将别名 my_index 指向它:
```
PUT /my_index_v1 ## 创建索引 my_index_v1
PUT /my_index_v1/_alias/my_index ## 设置别名 my_index 指向 my_index_v1
```
你可以检测这个别名指向哪一个索引
```
GET /*/_alias/my_index
```
或哪些别名指向这个索引:
```
GET /my_index_v1/_alias/*
```
两者都会返回下面的结果
```
{
"my_index_v1" : {
"aliases" : {
"my_index" : { }
}
}
}
```
然后,我们决定修改索引中一个字段的映射。当然,我们不能修改现存的映射,所以我们必须重新索引数据。 首先, 我们用新映射创建索引 my_index_v2
```
PUT /my_index_v2
{
"mappings": {
"my_type": {
"properties": {
"tags": {
"type": "string",
"index": "not_analyzed"
}
}
}
}
}
```
然后我们将数据从 my_index_v1 索引到 my_index_v2 ,下面的过程在 重新索引你的数据 中已经描述过。一旦我们确定文档已经被正确地重索引了,我们就将别名指向新的索引。
一个别名可以指向多个索引,所以我们在添加别名到新索引的同时必须从旧的索引中删除它。这个操作需要原子化,这意味着我们需要使用 _aliases 操作
```
POST /_aliases
{
"actions": [
{ "remove": { "index": "my_index_v1", "alias": "my_index" }},
{ "add": { "index": "my_index_v2", "alias": "my_index" }}
]
}
```
你的应用已经在零停机的情况下从旧索引迁移到新索引了。

View file

@ -0,0 +1,30 @@
需要在不停服务的情况下增加容量时,下面有一些有用的建议。相较于将数据迁移到更大的索引中,你可以仅仅做下面这些操作:
创建一个新的索引来存储新的数据。
同时搜索两个索引来获取新数据和旧数据。
实际上,通过一点预先计划,添加一个新索引可以通过一种完全透明的方式完成,你的应用程序根本不会察觉到任何的改变。
使用索引别名来指向当前版本的索引。 举例来说,给你的索引命名为 tweets_v1 而不是 tweets 。你的应用程序会与 tweets 进行交互,但事实上它是一个指向 tweets_v1 的别名。 这允许你将别名切换至一个更新版本的索引而保持服务运转。
可以使用一个类似的技术通过增加一个新索引来扩展容量。这需要一点点规划,因为你需要两个别名:一个用于搜索另一个用于索引数据:
```
PUT /tweets_1/_alias/tweets_search
PUT /tweets_1/_alias/tweets_index
```
新文档应当索引至 tweets_index ,同时,搜索请求应当对别名 tweets_search 发出。目前,这两个别名指向同一个索引。
当我们需要额外容量时,我们可以创建一个名为 tweets_2 的索引,并且像这样更新别名
```
POST /_aliases
{
"actions": [
{ "add": { "index": "tweets_2", "alias": "tweets_search" }}, # 添加索引 tweets_2 到别名 tweets_search
{ "remove": { "index": "tweets_1", "alias": "tweets_index" }}, # 移除tweets的别名tweets_index
{ "add": { "index": "tweets_2", "alias": "tweets_index" }} # 将别名 tweets_index 由 tweets_1 切换至 tweets_2
]
}
```
一个搜索请求可以以多个索引为目标,所以将搜索别名指向 tweets_1 以及 tweets_2 是完全有效的。 然而,索引写入请求只能以单个索引为目标。因此,我们必须将索引写入的别名只指向新的索引

View file

@ -0,0 +1,26 @@
想要控制一些新建索引的设置settings和映射mappings。也许我们想要限制分片数为 1 ,并且禁用 _all 域。 索引模板可以用于控制何种设置settings应当被应用于新创建的索引
```
PUT /_template/my_logs # 创建一个名为 my_logs 的模板
{
"template": "logstash-*", # 将这个模板应用于所有以 logstash- 为起始的索引
"order": 1, # 这个模板将会覆盖默认的 logstash 模板,因为默认模板的 order 更低
"settings": {
"number_of_shards": 1 # 限制主分片数量为 1
},
"mappings": {
"_default_": { # 为所有类型禁用 _all 域
"_all": {
"enabled": false
}
}
},
"aliases": {
"last_3_months": {} # 添加这个索引至 last_3_months 别名中
}
}
```
这个模板指定了所有名字以 logstash- 为起始的索引的默认设置,不论它是手动还是自动创建的。 如果我们认为明天的索引需要比今天更大的容量,我们可以更新这个索引以使用更多的分片。
这个模板还将新建索引添加至了 last_3_months 别名中,然而从那个别名中删除旧的索引则需要手动执行。

View file

@ -0,0 +1,60 @@
按时间建立索引的一个好处是可以方便处理旧索引,只需要删除那些变得不重要的索引就可以了。
删除整个索引比删除单个文档要更加高效Elasticsearch 只需要删除整个文件夹。
但是删除索引是 终极手段 。在我们决定完全删除它之前还有一些事情可以做来帮助数据更加优雅地过期。
### 索引迁移
随着数据被记录,很有可能存在一个 热点 索引——今日的索引。 所有新文档都会被加到那个索引,几乎所有查询都以它为目标。那个索引应当使用你最好的硬件。
Elasticsearch 是如何得知哪台是你最好的服务器呢?你可以通过给每台服务器指定任意的标签来告诉它。 例如,你可以像这样启动一个节点:
```
./bin/elasticsearch --node.box_type strong
```
box_type 参数是完全随意的——你可以将它随意命名只要你喜欢——但你可以用这些任意的值来告诉 Elasticsearch 将一个索引分配至何处。
我们可以通过按以下配置创建今日的索引来确保它被分配到我们最好的服务器上:
```
PUT /logs_2014-10-01
{
"settings": {
"index.routing.allocation.include.box_type" : "strong"
}
}
```
昨日的索引不再需要我们最好的服务器了,我们可以通过更新索引设置将它移动到标记为 medium 的节点上:
```
POST /logs_2014-09-30/_settings
{
"index.routing.allocation.include.box_type" : "medium"
}
```
### 索引优化
昨日的索引不大可能会改变。 日志事件是静态的已经发生的过往不会再改变了。如果我们将每个分片合并至一个段Segment它会占用更少的资源更快地响应查询。 我们可以通过optimize API来做到。
对还分配在 strong 主机上的索引进行优化Optimize操作将会是一个糟糕的想法 因为优化操作将消耗节点上大量 I/O 并对索引今日日志造成冲击。但是 medium 的节点没有做太多类似的工作,我们可以安全地在上面进行优化。
昨日的索引有可能拥有副本分片。如果我们下发一个优化Optimize请求 它会优化主分片和副本分片,这有些浪费。然而,我们可以临时移除副本分片,进行优化,然后再恢复副本分片
```
POST /logs_2014-09-30/_settings
{ "number_of_replicas": 0 }
POST /logs_2014-09-30/_optimize?max_num_segments=1
POST /logs_2014-09-30/_settings
{ "number_of_replicas": 1 }
```
### 关闭旧索引
当索引变得更“老”,它们到达一个几乎不会再被访问的时间点。 我们可以在这个阶段删除它们,但也许你想将它们留在这里以防万一有人在半年后还想要访问它们。
这些索引可以被关闭。它们还会存在于集群中,但它们不会消耗磁盘空间以外的资源。重新打开一个索引要比从备份中恢复快得多。
在关闭之前,值得我们去刷写索引来确保没有事务残留在事务日志中。一个空白的事务日志会使得索引在重新打开时恢复得更快:
```
POST /logs_2014-01-*/_flush # 刷写Flush所有一月的索引来清空事务日志
POST /logs_2014-01-*/_close # 关闭所有一月的索引
POST /logs_2014-01-*/_open # 当你需要再次访问它们时,使用 open API 来重新打开它们
```

13
ELK/es打分算法.md Normal file
View file

@ -0,0 +1,13 @@
**TF/IDF模型**
* TFTF(Term Frequency),即**词频**表示词条在文本中出现的频率。考虑一篇文档得分的首要方式是查看一个词条在当前文档注意IDF统计的范围是所有文档中出现的次数比如某篇文章围绕ES的打分展开的那么文章中肯定会多次出现相关字眼当查询时我们认为该篇文档更符合所以这篇文档的得分会更高。TF的值通常会被归一化一般是词频除以文章总词数以防止它偏向长的文件同一个词语在长文件里可能会比短文件有更高的词频而不管该词语重要与否
* IDFIDF(Inverse Document Frequency),即**逆文档频率**反应了一个词在所有文档中出现的频率如果一个词在很多的文本中出现那么它的IDF值应该低。而反过来如果一个词在比较少的文本中出现那么它的IDF值应该高。
TF/IDF算法简单来说就是一个词语在某一篇文档中出现次数越多同时在所有文档中出现次数越少那么该文档越能与其它文章区分开来评分就会越高。
字段的长度是多少?字段越短,字段的权重越高。检索词出现在一个内容短的 title 要比同样的词出现在一个内容长的 content 字段权重更大
**BM25模型**
传统的tf计算公式中词频越高tf值就越大没有上限。但BM中的tf随着词频的增长tf值会无限逼近(k+1),相当于是有上限的。这就是二者的区别。一般 k取 1.2Lucene中也使用1.2作为 k 的默认值。

View file

@ -0,0 +1,4 @@
keyword不分词整个存入es中。默认时256个字符
text内容会进行分词。先分词再存入es中当使用多个单词精心查询时查不到已经分词的内容
举例说明存储小说时小说名及作者名可以不分词存入es中

View file

@ -0,0 +1,10 @@
当es节点启动后利用多播muticast寻找集群给中其他节点并与之建立连接
在集群中,一个节点被选举成主节点(master node)。这个节点负责管理集群的状态,当群集的拓扑结构改变时把索引分片分派到相应的节点上。
在必要的情况下,任何节点都可以并发地把查询子句分发到其它的节点,然后合并各个节点返回的查询结果。最后返回给用户一个完整的数据集。所有的这些工作都不需要经过主节点转发(节点之间通过P2P的方式通信)。
主节点会去读取集群状态信息;在必要的时候,会进行恢复工作。在这个阶段,主节点会去检查哪些分片可用,决定哪些分片作为主分片。处理完成后,集群就会转入到黄色状态。
这意味着集群已经可以处理搜索请求了,但是还没有火力全开(这主要是由于所有的主索引分片(primary shard)都已经分配好了,但是索引副本还没有)。接下来需要做的事情就是找到复制好的分片,并设置成索引副本。当一个分片的副本数量少了,主节点会决定将缺少的分片放置到哪个节点中,并且依照主分片创建副本。所有工作完成后,集群就会变成绿色的状态(表示所有的主分片的索引副本都已经分配完成)。

View file

@ -0,0 +1,15 @@
```
## 搜索索引bank中的addree字段包含mill或lane的数据
GET /bank/_search
{
"query": { "match": { "address": "mill lane" } }
}
```
```
## 搜索索引bank中的addree字段包含“mill lane”的数据
GET /bank/_search
{
"query": { "match_phrase": { "address": "mill lane" } }
}
```

View file

@ -0,0 +1,59 @@
```
## 第一个参数是访问方式get/put/delete/post等第二个参数是文件或者uri字符串如/item/es/_search
## 文件中第一行为uri字符串
## 其他行合并组成一个访问的data数据
## 测试失败不识别query暂时未找到解决方法
#!/usr/bin/env python
#_*_Coding:UTF-8_*_
import requests
import sys
import json
import os
class Esdata(object):
def __init__(self, refers, header):
self.refers = refers
self.header = header
## 通过脚本参数传入,决定调用的函数
def operator(self, func):
return getattr(requests, func)
## 得到response
def getdata(self, func, uri, data):
url = self.refers + uri
if self.operator(func) in ["put", "post"]:
response = self.operator(func)(url, data=data, headers=header)
else:
response = self.operator(func)(url, params=data, headers=header)
return response
if __name__ == '__main__':
refers = 'http://127.0.0.1:9200'
header = {"content-Type": "application/json"}
# 传递参数get/put/post/delete等
methods = sys.argv[1]
d = sys.argv[2]
# 判断第二个参数是否文件
if d and os.path.isfile(d):
with open(d, 'rb') as f:
# readline函数一次读取一行这是第一行uri
uri = f.readline()
data = ''
# 其他行组成data用于传入访问链接
for line in f.readlins()[0:]:
data = data + line.strip()
else:
uri = d
data = None
# 读出的data中会把双引号转换成单引号但转换成json格式就会异常需要替换一下
data = data.replace("\'","\"")
es = Esdata(refers, header)
res = es.getdata(methods, uri, json.loads(data))
print(json.dumps(res.text, sort_keys=True, indent=4, separators=(', ', ': '), ensure_ascii=False))
```