前言
Elasticsearch学习笔记
概念
文档(document):每条数据就是一个文档
词条(term):文档中按照语意分开后的词语
索引(index):相同类型文档的集合
映射(mapping):索引对文档字段的约束,类似于数据表的结构约束
Elasticsearch中的概念
MySQL与Elasticsearch的概念对比
Index
索引,相同类型文档的集合。类似于MySQL的数据表
Table
Document
文档,每条数据就是一个文档,文档都是JSON格式字符串。类似于与MySQL的行
Row
Field
字段,JSON文档中的各个key。类似于MySQL的列
Column
Mapping
映射,JSON文档中各个value的约束。类似于MySQL的表结构
Schema
DSL
JSON风格的请求语句,用来操作Elasticsearch实现CRUD的语句。类似于MySQL的SQL语句
SQL
ik分词器
The IK Analysis plugin integrates Lucene IK analyzer (/302.html?target=http://code.google.com/p/ik-analyzer/) into elasticsearch, support customized dictionary.(Github )
添加扩展词
添加停止词
分词操作
"analyzer": ""
:指定分词的方式 > standard
:标准方式。逐字分词 > chinese
:内置的中文分词。逐字分词 > ik_smart
:ik分词器最少词 > ik_max_word
:ik分词器最多词
"text": ""
:指定分词的内容
request 1 2 3 4 5 6 7 POST http://127.0.0.1:9200/_analyze Content-Type : application/json{ "analyzer": "standard", "text": "" }
在指定索引库中进行分词操作
request 1 2 3 4 5 6 7 POST http://127.0.0.1:9200/索引库名/_analyze Content-Type : application/json{ "analyzer": "standard", "text": "" }
对索引库的操作
新增索引库
在Elasticsearch中id通常定义为keyword
类型
type: ""
:字段数据类型 > 字符串 > > text
:可分词的文本 > > keyword
:精确值,不能被拆开的词 > > 数值 > > long
> > integer
> > short
> > byte
> > double
> > float
> > 布尔 > > boolean
> > 日期 > > date
> > 数组 > > elasticsearch中没有数组类型,但是任何数据类型都可以指定多个值 > > 地理坐标 > > geo_point: "3.1415926, 3.1415926"
:地理上的一个点 > > geo_shape: "LINESTARING(第一个点经度 第一个点纬度, 第二个点经度 第二个点纬度)"
:地理上由多个点组成的一个范围 > > 自动补全 > > completion
:允许通过前缀关键字模糊搜索
index: ""
:是否创建倒排索引。如果字段参与搜索,才需要创建倒排索引;如果不需要搜索,就不用创建倒排索引 > true
:缺省值,创建倒排索引 > false
:不创建倒排索引
analyzer: ""
:指定使用哪种分词器 > standard
:标准方式。逐字分词 > chinese
:内置的中文分词。逐字分词 > ik_smart
:ik分词器最少词 > ik_max_word
:ik分词器最多词
properties: {"": "", "": ""}
:字段的子字段 copy_to: "其他字段名"
:将当前字段的值拷贝到其他字段(底层只是创建了一个索引,并不是真的拷贝了一份),这样当搜索其他字段时,当前字段的值也会被搜索到
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 PUT http://127.0.0.1:9200/索引库名 Content-Type : application/json{ "mappings": { "properties": { "字段名": { "type": "字段类型" }, "id": { "type": "keyword", "index": false }, "name": { "type": "text", "analyzer": "ik_smart" }, "engilshname": { "type": "text", "copy_to": "name" }, "father": { "properties": { "son": { "type": "keyword" } } } } } }
指定自定义分词器
将pinyin分词器重新配置后,作为过滤器,与ik分词器组合成新的自定义分词器
创建索引库时,指定新增文档时使用的分词器为自定义分词器,指定查询文档时使用的分词器为ik分词器
character filter:在分词之间对原文档做处理 tokenizer
:将文本按照指定的规则或分词器切成词条term,如果不分词就指定为keyword
filter
:将tokenizer输出的词条交给指定过滤器或分词器作进一步处理
"analyzer": ""
:指定创建时使用的分词器 "search_analyzer": ""
:指定搜索时使用的分词器
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 PUT http://127.0.0.1:9200/索引库名 Content-Type : application/json{ "settings": { "analysis": { "analyzer": { "自定义分词器名": { "tokenizer": "ik_max_word", "filter": "过滤器名" } }, "filter": { "过滤器名": { "type": "pinyin", "keep_full_pinyin": false, "keep_joined_full_pinyin": true, "keep_original": true, "limit_first_letter_length": 16, "remove_duplicated_term": true, "none_chinese_pinyin_tokenize": false } }, "mappings": { "properties": { "字段名": { "type": "字段类型", "analyzer": "自定义分词器名", "search_analyzer": "ik_smart" } } } } } }
查询索引库
request 1 GET http://127.0.0.1:9200/索引库名
删除索引库
request 1 DELETE http://127.0.0.1:9200/索引库名
修改索引库
request 1 2 3 4 5 6 7 8 9 10 PUT http://127.0.0.1:9200/索引库名/_mapping Content-Type : application/json{ "properties": { "新字段名": { "type": "字段类型" } } }
对文档操作
新增文档
文档id
:如果不指定文档id,则索引库会自动随机生成一个id
request 1 2 3 4 5 6 7 8 9 POST http://127.0.0.1:9200/索引库名/_doc/文档id Content-Type : application/json{ "key": "value", "key": { "key": "value" } }
结果中result
如果为created
表示新增成功
每次写操作都会导致version
自增
删除文档
request 1 DELETE http://127.0.0.1:9200/索引库名/_doc/文档id
结果中result
如果为deleted
表示删除成功
删除所有文档
request 1 2 3 4 5 6 7 8 POST http://127.0.0.1:9200/索引库名/_delete_by_query Content-Type : application/json{ "query": { "match_all": {} } }
修改文档
全量修改
先通过文档id查询旧文档
如果查询到了旧文档,就删除旧文档,新增新文档
如果没有查询到旧文档,就直接新增文档
request 1 2 3 4 5 6 7 8 9 PUT http://127.0.0.1:9200/索引库名/_doc/文档id Content-Type : application/json{ "key": "value" "key": { "key": "value" } }
结果中result
如果为updated
表示全量修改成功
结果中result
如果为created
表示新增成功
局部修改
request 1 2 3 4 5 6 7 8 POST http://127.0.0.1:9200/索引库名/_update/文档id Content-Type : application/json{ "doc": { "字段名": "字段值" } }
结果中result
如果为updated
表示局部修改成功
查询文档
request 1 GET http://127.0.0.1:9200/索引库名/_doc/文档id
结果中found
如果为true
表示查询成功,如果为false
表示查询失败
如果查询成功,数据会存在_source
中
搜索文档的操作
request 1 2 3 4 5 6 7 8 9 10 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "查询类型": { "查询条件": "查询值" } } }
简单查询
查询所有
查询所有默认返回的结果并不是全部结果,只会返回部分结果
request 1 2 3 4 5 6 7 8 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "match_all": {} } }
查看分片信息
"explain": true
:列出信息存储的节点位置
request 1 2 3 4 5 6 7 8 9 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "explain": true, "query": { "match_all": {} } }
全文检索
根据指定的单个字段全文检索
只要指定字段的关键字中,任意子关键字满足条件,即可查询出
request 1 2 3 4 5 6 7 8 9 10 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "match": { "字段名": "关键字" } } }
根据指定的多个字段全文检索
只要多个字段的关键字中,任意子关键字满足条件,即可查询出
多个字段全文检索比单个字段全文检索效率更低,推荐将字段的集合复制为一个单独字段all
进行单字段检索
"query": ""
:指定关键字 "fields": ["", ""]
:指定字段名
request 1 2 3 4 5 6 7 8 9 10 11 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "multi_match": { "query": "关键字", "fields": ["字段名", "字段名"] } } }
精确查询
完全匹配
request 1 2 3 4 5 6 7 8 9 10 11 12 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "term": { "字段名": { "value": "关键字" } } } }
匹配数值范围
gt
:大于 gte
:大于等于 lt
:小于 lte
:小于等于
request 1 2 3 4 5 6 7 8 9 10 11 12 13 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "range": { "字段名": { "gte": "最小值", "lte": "最大值" } } } }
地理查询
矩形范围
指定矩形左上角和右下角的坐标,查询矩形范围内的所有文档
top_left
:矩形左上角的坐标 > lat
:经度 > lon
:纬度
bottom_right
:矩形右下角的坐标 > lat
:经度 > lon
:纬度
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "geo_bounding_box": { "字段名": { "top_left": { "lat": 1.1, "lon": 1.1 }, "bottom_rignt": { "lat": 1.1, "lon": 1.1 } } } } }
圆形范围
"distance": ""
:指定半径距离 "中心点坐标": "经度,纬度"
:指定中心点坐标
request 1 2 3 4 5 6 7 8 9 10 11 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "geo_distance": { "distance": "15km", "中心点坐标": "经度,纬度" } } }
复合查询
布尔查询
布尔查询是把多个简单查询语句进行组合,形成复合查询语句
must
:(与)必须匹配所有子查询 should
:(或)选择性匹配子查询 must_not
:(非)必须不匹配所有子查询,不参与算分 filter
:必须匹配,不参与算分
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "bool": { "must": [ {} ], "should": [ {} ], "must_not": [ {} ], "filter": [ {} ] } } }
算分函数查询
Elasticsearch 5.0
之前默认采用TF-IDF
算法,会随着词频增加而无限增加
Elasticsearch 5.0
之后默认采用BM25
算法,会随着词频增加而趋于水平
有加分规则
为了能人工干预算法默认的分数,可以采用Function Score Query
通过query
获取查询的文档
通过filter
过滤,得到需要加分的文档
通过运算函数,将运算函数的结果与原始的分进行组合运算
通过boost_mode
指定运算的方式
function_score
:通过算分函数重新算分 > "query": {}
:初始条件,通过简单查询添加条件,得到原始得分
"filter": {}
:过滤条件,通过简单查询添加条件 运算函数
> weight
:给定一个常量值作为函数结果 > field_value_factor
:用文档的某个字段作为函数结果 > random_score
:用一个随机数作为函数结果 > script_score
:自定义一个公式,公式结果作为函数结果
boost_mode
:指定算分方式 > multiply
:缺省值,将原始得分和额外分相乘 > add
:将原始得分和额外分相加 > avg
:将原始得分和额外分取平均值 > max
:将原始得分和额外分取最大值 > min
:将原始得分和额外分取最小值 > replace
:将额外分数替换原始分数
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "function_score": { "query": {}, "functions": [ "filter": {} "weight": 10 ], "boost_mode": "multiply" } } }
返回的数据中,_score
表示最终分数,分数越高排名越靠前
没有加分规则
request 1 2 3 4 5 6 7 8 9 10 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": { "function_score": { "query": {} } } }
搜索结果处理
排序
order
:指定排序规则 > asc
:升序 > desc
:降序
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": {}, "sort": [ "字段名": { "order": "asc" }, "字段名": { "order": "desc" } ] }
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": {}, "sort": [ { "字段名": "asc" }, { "字段名": "desc" } ] }
地理类型排序
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": {}, "sort": [ { "_geo_distance": { "地理字段名": { "lat": 纬度, "lon":经度 }, "order": "asc", "unit": "km" } } ] }
简化写法
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": {}, "sort": [ { "_geo_distance": { "地理字段名": "纬度, 经度", "order": "asc", "unit": "km" } } ] }
分页
from
:分页起始下标位置,默认为0 size
:每页的数据数,默认为10
request 1 2 3 4 5 6 7 8 9 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": {}, "sort": [], "from": 0, "size": 10 }
高亮
原理:后端得到数据后,先将关键字添加标签,再返回给前端;前端添加指定标签的样式,实现高亮
require_field_match
:是否开启搜索字段与高亮字段匹配 > true
:缺省值,开启搜索字段与高亮字段匹配。如果匹配才会实现高亮,如果不匹配就无法实现高亮 > false
:关闭搜索字段与高亮字段匹配。即便是不匹配也能实现高亮
pre_tags
:添加标签前缀,如果没有指定,缺省值是<em>
post_tags
:添加标签后缀,如果没有指定,缺省值是</em>
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": {}, "highlight": { "fields": { "字段名": { "require_field_match": "true", "pre_tags": "<em>", "post_tags": "</em>" } } } }
聚合查询
官方文档
聚合可以实现对文档数据的统计、分析、运算
聚合可以嵌套,在一个聚合的结果上继续做聚合
query
:限定聚合条件,可以不指定聚合条件 size
:展示的原数文档的个数,0表示不展示原文档 aggs
:定义聚合,可以指定多个聚合
request 1 2 3 4 5 6 7 8 9 10 11 12 13 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": {}, "size": 0, "aggs": { "聚合名": { "聚合类型": {}, "聚合类型": {} } } }
返回的数据中,aggregations.聚合名
表示聚合的结果
桶聚合(Bucket)
Term Aggregation
方式桶聚合:按照文档字段值分组,统计指定字段相同的文档的数量。类似于MySQL中的分组(Group By)
terms
:Term方式的桶聚合 field
:指定参与聚合的字段名 size
:指定聚合结果数量,默认值为10 _count
:返回数据按照文档数量的排序规则 > desc
:缺省值,按照文档数量的降序排序 > asc
:按照文档数量的降序升序
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": {}, "size": 0, "aggs": { "聚合名": { "terms": { "field": "字段名", "size": 10, "order": { "_count": "asc" } } } } }
aggregations.聚合名.buckets.key
:文档的字段名 aggregations.聚合名.buckets.doc_count
:文档的个数
度量聚合(Metric)
在桶聚合的基础上,用于计算数据的值,包括文档个数、文档评分最小值、文档评分最大值、文档评分平均值、文档评分总和
如果没有在桶聚合的基础上,则将所有数据参与分值计算
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 POST http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "query": {}, "size": 0, "aggs": { "聚合名": { "terms": { "field": "桶聚合字段名", "size": 10, "order": { "_count": "asc" } } "aggs": { "度量聚合名": { "stats": { "field": "度量聚合字段名" } } } } } }
aggregations.聚合名.buckets.度量聚合名.count
:文档的个数 aggregations.聚合名.buckets.度量聚合名.min
:文档评分最小值 aggregations.聚合名.buckets.度量聚合名.max
:文档评分最大值 aggregations.聚合名.buckets.度量聚合名.avg
:文档评分平均值 aggregations.聚合名.buckets.度量聚合名.sum
:文档评分总和
自动补全搜索
自动补全类型 > completion
:通过前缀关键字模糊搜索
field
:指定需要补全查询的字段名 skip_duplicates
:跳过重复项 size
:查询结果的个数
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 GET http://127.0.0.1:9200/索引库名/_search Content-Type : application/json{ "suggest": { "查询名称": { "text": "前缀关键字", "completion": { "field": "字段名", "skip_duplicates": true, "size": 10 } } } }
Elasticsearch集群
集群中节点的职责
master eligible
node.master
true
备选主节点:主节点可以管理和记录集群状态、决定分片在哪个节点、处理创建和删除索引库的请求
data
node.data
true
数据节点:存储数据、搜索、聚合、CRUD
ingest
node.ingest
true
数据预处理节点:数据存储之前的预处理
coordinating
以上节点如果都为false,则coordinating为true
无
协调节点:路由请求到其他节点,合并其他节点处理的结果,返回给用户
脑裂现象
主节点由于网络原因导致与其他节点失联,此时其他节点会重新选举出新的主节点,当旧的主节点恢复连接时,集群中会出现多个主节点,这种现象就是脑裂现象
当选举票数 > (所有节点个数 + 1) / 2
时,可以避免脑裂现象
Elasticsearch7.x版本以上,选举算法直接作为了配置的缺省值,所以不需要任何配置即可解决脑裂现象
分布式新增
将得到的数据交给主节点,主节点通过计算hash(文档id) % 所有节点个数
的值,可以得到将数据存储到哪个分片
将数据交给指定节点进行存储
将数据交给其他节点进行备份
分布式查询
分散阶段(scatter phase):coordinating节点会把请求分发给集群中的每一个节点
聚集阶段(gather phase):coordinating节点会将从所有data节点中搜索到的结果进行汇总后返回给用户
故障转移
主节点会监控集群中所有节点的健康状态,当集群中其中一个节点宕机,会立即将宕机节点的数据重新备份给其他健康的节点,这就是故障转移
如果是数据节点宕机,直接进行转移数据
如果是主节点宕机,先进行主节点选举,再进行转移数据
如果宕机的节点恢复健康,则新的主节点会将备份数据重新从其他节点转移给恢复健康的节点
完成
参考文献
哔哩哔哩——黑马程序员 博客园——只会玩辅助 CSDN——qq_47452239