很详细,大家可以花点时间看看
目录
0 概念扫盲
-
elasticsearch
- – 一个开源的分布式搜索引擎,可以用来实现搜索、日志统计、分析、系统监控等功能
-
elastic stack(ELK)
- –是以elasticsearch为核心的技术栈,包括beats、Logstash(数据抓取)、kibana(数据可视化)、elasticsearch(存储、计算、搜索数据)
-
Lucene
- –是Apache的开源搜索引擎类库,提供了搜索引擎的核心API
-
正向索引和倒排索引
-
正向索引
- – 即根据id查文档再在文档中扫描关键字记录位置信息(全表扫描
-
倒排索引
- – 根据关键字找文档,创建一个词条表记录每个词条所在文档的id记录下来
- – 搜索流程
- :
1. es概念
-
文档和字段:
- 文档(Document)相当于数据库表中的一条记录,字段(Field)相当于列
-
索引和映射:
- 索引(index)是所有文档的集合相当于数据库中的表,数据库中的表有表结构,字段名,类型等约束信息,那么映射(mapping)就是索引中文档的约束信息。
-
DSL:相当于mysql中的sql语句
2. es操作
2.1 mapping映射属性
-
type:字段的数据类型,常见的简单类型有
- 字符串:text(可分词的文本)、keyword(精确值,如ip地址
- 数值:long, integer, short , byte, double , float
- 布尔:boolean
- 日期:date
- 对象:object
-
index: 是否创建索引(是否参与搜索),默认为true
-
analyzer: 使用哪种分词器
-
properties: 字段,可以在字段中嵌套字段
2.2 索引库的CRUD
- 创建索引库映射关系: PUT /{索引库名} 请求参数:js
- 查询索引库: GET /{索引库名}
- 修改索引库:
- 倒排索引一旦数据结构发生改变需要重新创建倒排索引,因此索引库一旦创建无法修改mapping 但可以在mapping中添加新字段
- 基本语法:
- 请求方式:PUT
- 请求路径:/索引库名/_mapping
- 请求参数:js
- 删除索引库:DELETE /{索引库名}
2.3 文档操作
- 新增文档:POST /{索引库名}/_doc/{文档ID}
- 查询文档:GET /{索引库名}/_doc/{文档ID}
- 删除文档:DELETE /{索引库名}/_doc/{文档ID}
- 修改文档:
- 全量修改(根据id先删除再新增相同id的文档 :
- 语法:PUT /{索引库名}/_doc/{文档id} 参数:js
- 增量修改:(只修改指定id匹配的文档中的部分字段 :
- 语法:POST /{索引库名}/_update/{文档id} 参数:js
- 全量修改(根据id先删除再新增相同id的文档 :
2.4 DSL条件查询分类
查询通用语法 :
GET /indexName/_search
{
"query": {
"查询类型": {
"查询条件": "条件值"
}
}
}
查询所有 :
- 全文检索(full text)查询:
- 使用场景:输入框搜索
- match:单字段查询(语法如下) :
-
GET /indexName/_search { "query": { "match": { "FIELD": "TEXT" } } }
- multi_match : 多字段查询,任意一个字段符合条件即可(参与查询字段越多,查询性能越差 ) :
GET /indexName/_search { "query": { "multi_match": { "query": "TEXT", "fields": ["FIELD1", " FIELD12"] } } }
- 精确查询
- 精确查询一般是查找keyword、数值、日期、boolean等类型字段。不会对搜索条件分词
- term: 根据词条精确值查询,输入的内容跟自动值完全匹配时才认为符合条件。
// term查询 GET /indexName/_search { "query": { "term": { "FIELD": { "value": "VALUE" } } } }
- range: 一般应用在对数值类型做范围过滤的时候。比如做价格范围过滤。
// range查询 GET /indexName/_search { "query": { "range": { "FIELD": { "gte": 10, // 这里的gte代表大于等于,gt则代表大于 "lte": 20 // lte代表小于等于,lt则代表小于 } } } }
- 地理(geo)查询
- 根据经纬度查询,一般用于搜索附近酒店附近人等
- geo_bounding_box:
- :
- 矩形范围查询,查询坐标落在某个矩形范围的所有文档,需要指定矩形的左上、右下两个点的坐标,然后画出一个矩形,落在该矩形内的都是符合条件的点。
// geo_bounding_box查询 GET /indexName/_search { "query": { "geo_bounding_box": { "FIELD": { "top_left": { // 左上点 "lat": 31.1, "lon": 121.5 }, "bottom_right": { // 右下点 "lat": 30.9, "lon": 121.7 } } } } }
- 矩形范围查询,查询坐标落在某个矩形范围的所有文档,需要指定矩形的左上、右下两个点的坐标,然后画出一个矩形,落在该矩形内的都是符合条件的点。
- geo_distance: :
- 查询到指定中心点小于某个距离值的所有文档。
// geo_distance 查询 GET /indexName/_search { "query": { "geo_distance": { "distance": "15km", // 半径 "FIELD": "31.21,121.5" // 圆心 } } }
- 查询到指定中心点小于某个距离值的所有文档。
- 复合(compound)查询
- 复合查询可以将其它简单查询组合起来,实现更复杂的搜索逻辑
- fuction score:算分函数查询,可以控制文档相关性算分,控制文档排名
- 相关性算分:当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排列
- 算法有TF- IDF和BM25算法,es5.1版本后采用BM25
- 控制相关性算分
- 语法 :
- 组成:
- 原始查询条件:query部分,基于这个条件搜索文档,并且基于BM25算法给文档打分,原始算分(query score)
- 过滤条件:filter部分,符合该条件的文档才会重新算分(决定哪些文档的算分被修改
- 算分函数:符合filter条件的文档要根据这个函数做运算,得到的函数算分(function score),有四种函数
- weight:函数结果是常量
- field_value_factor:以文档中的某个字段值作为函数结果
- random_score:以随机数作为函数结果=
- script_score:自定义算分函数算法
- 运算模式:算分函数的结果、原始查询的相关性算分,两者之间的运算方式(决定最终算分结果),包括:
- multiply:相乘
- replace:用function score替换query score
- 其它,例如:sum、avg、max、min
- 运行流程:
- 1)根据原始条件查询搜索文档,并且计算相关性算分,称为原始算分(query score)
- 2)根据过滤条件,过滤文档
- 3)符合过滤条件的文档,基于算分函数运算,得到函数算分(function score)
- 4)将原始算分(query score)和函数算分(function score)基于运算模式做运算,得到最终结果,作为相关性算分。
- 相关性算分:当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排列
- bool query:布尔查询,利用逻辑关系组合多个其它的查询,实现复杂搜索。布尔查询是一个或多个查询子句的组合,每一个子句就是一个子查询,子查询的组合方式有
- must: 必须匹配每个子查询,类似“与”
- should:选择性匹配子查询,类似“或”
- must_not:必须不匹配,不参与算分,类似“非”
- filter:必须匹配,不参与算分
-
GET /hotel/_search { "query": { "bool": { "must": [ {"term": {"city": "上海" }} ], "should": [ {"term": {"brand": "皇冠假日" }}, {"term": {"brand": "华美达" }} ], "must_not": [ { "range": { "price": { "lte": 500 } }} ], "filter": [ { "range": {"score": { "gte": 45 } }} ] } } }
2.5 搜索结果处理
2.5.1 排序
elasticsearch默认是根据相关度算分(_score)来排序,但是也支持自定义方式对搜索结果排序。
普通字段排序: :
GET /indexName/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"FIELD": "desc" // 排序字段、排序方式ASC、DESC
}
]
}
地理坐标排序: :
GET /indexName/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance" : {
"FIELD" : "纬度,经度", // 文档中geo_point类型的字段名、目标坐标点
"order" : "asc", // 排序方式
"unit" : "km" // 排序的距离单位
}
}
]
}
2.5.2 分页
elasticsearch 默认情况下只返回top10的数据。而如果要查询更多数据就需要修改分页参数了。elasticsearch中通过修改from、size参数来控制要返回的分页结果
from从第几个文档开始,size总共查询几个文档。类似于mysql中的 limit ? , ?
基本分页语法: :
GET /hotel/_search
{
"query": {
"match_all": {}
},
"from": 0, // 分页开始的位置,默认为0
"size": 10, // 期望获取的文档总数
"sort": [
{"price": "asc"}
深度分页语法:官方文档
常见分页实现方案:
from + size:
优点:支持随机翻页
缺点:深度分页问题,默认查询上限(from + size)是10000
场景:百度、京东、谷歌、淘宝这样的随机翻页搜索
after search:
优点:没有查询上限(单次查询的size不超过10000)
缺点:只能向后逐页查询,不支持随机翻页
场景:没有随机翻页需求的搜索,例如手机向下滚动翻页
scroll:
优点:没有查询上限(单次查询的size不超过10000)
缺点:会有额外内存消耗,并且搜索结果是非实时的
场景:海量数据的获取和迁移。从ES7.1开始不推荐,建议用 after search方案。
2.5.3 高亮:
实现 :
GET /hotel/_search
{
"query": {
"match": {
"FIELD": "TEXT" // 查询条件,高亮一定要使用全文检索查询
}
},
"highlight": {
"fields": { // 指定要高亮的字段
"FIELD": {
"pre_tags": "<em>", // 用来标记高亮字段的前置标签
"post_tags": "</em>" // 用来标记高亮字段的后置标签
}
}
}
}
流程:
- 给文档中的所有关键字都添加一个标签,例如<em>标签
- 页面给<em>标签编写CSS样式
注意事项
- 高亮是对关键字高亮,因此搜索条件必须带有关键字,而不能是范围这样的查询。
- 默认情况下,高亮的字段,必须与搜索指定的字段一致,否则无法高亮
- 如果要对非搜索字段高亮,则需要添加一个属性:required_field_match=false
全部查询条件示例总结![](https://i-blog.csdnimg.cn/blog_migrate/4222340b9da64a0fba2b037cd8542202.png)
2.6 数据的聚合
2.6.1 种类
桶(Bucket)聚合:用来对文档做分组
– TermAggregation:按照文档字段值分组,例如按照品牌值分组、按照国家分组
– Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组
度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等
– Avg:求平均值
– Max:求最大值
– Min:求最小值
– Stats:同时求max、min、avg、sum等
管道(pipeline)聚合:其它聚合的结果为基础做聚合
2.7 自动补全 (后续
2.8 数据同步(后续
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
总结很长时间,麻烦给个点赞吧!