DSL查询
DSL查询分类
查询所有:查询出所有数据(match_all)
全文检索:利用分词器对用户输入内容分词,然后去倒排索引库中匹配
- match_query
- multi_match_query
精确查询:根据精确词条值查找数据,一般是查找keyword,数值,boolean等字段
- ids
- range
- Term
地理查询:根据经纬度查询
- Geo_distance
- Get_bounding_box
复合查询:复合查询可以将上述各种查询条件组合起来,合并查询条件
- boool
- function_score
DSL Query基本语法
代码语言:javascript复制GET /indexName/_search
{
"query": {
"查询类型": {
"查询条件": "条件值"
}
}
}
全文检索查询
match查询:全文检索的一种,会对用户输入的内容分词,然后去倒排索引库检索
代码语言:javascript复制GET /indexName/_search
{
"query": {
"match": {
"FIELD": "TEXT"
}
}
}
multi_match:与match查询类似,只不过允许同时查询多个字段
代码语言:javascript复制GET /indexName/_search
{
"query": {
"multi_match": {
"query": "TEXT",
"fields": ["FIELD1", " FIELD12"]
}
}
}
match与multi_match的区别
- match根据一个条件查询
- Multi_match根据多个字段查询,参与查询字段越多,查询性能越差,多字段建议使用all的方式
精确查询
精确查询一般是查找keyword、数值、日期、boolean等类型字段,所以不会对搜索条件分词,常见的有:
- term:根据词条精确值查询
- range:根据值的范围查询
trem查询语法:
代码语言:javascript复制// term查询
GET /indexName/_search
{
"query": {
"term": {
"FIELD": {
"value": "VALUE"
}
}
}
}
range查询语法:
代码语言:javascript复制// range查询
GET /indexName/_search
{
"query": {
"range": {
"FIELD": {
"gte": 10,
"lte": 20
}
}
}
}
地理查询
根据经纬度查询
- geo_bounding_box:查询geo_point值落在某个矩形范围的所有数据
语法:
代码语言:javascript复制// 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:查询到指定中心点小于某个距离值的所有文档
语法:
代码语言:javascript复制// geo_distance 查询
GET /indexName/_search
{
"query": {
"geo_distance": {
"distance": "距离",
"FIELD": "经纬度坐标"
}
}
}
复合查询
复合查询:可以将其他简单查询组合起来,实现更复杂的搜索逻辑
相关性算分
当我们利用match查询文档时文档结果会根据于搜索词条的关联度打分,返回结果时按照分值进行排列
使用function score query,可以修改文档的相关性算分,根据新的到的算分排序
语法:
代码语言:javascript复制#相关性算分
GET /hotel/_search
{
"query": {
"function_score": {
//原始查询条件
"query": {
"match": {
"name": "外滩"
}
},
"functions": [
{
//过滤条件
"filter": {
"term": {
"city": "如家"
}
},
//算分函数
"weight": 10
}
],
//加权模式
"boost_mode": "multiply"
}
}
}
语法解释:
- query:原始查询条件,搜索文档并根据相关性打分
functions:
- filter:过滤条件,复合条件的文档才会被重新算分
- 算分函数:将来会与query score运算,符合条件的文档才会被重新算分
- weight:给一个常量值,作为函数结果
- field_value_factor:用文档中的某个字段值作为函数结果
- random_scope:随机生成一个值,作为函数结果
- script_scope:自定义计算公式,公式结果作为函数结果
- 加权模式:
- multiply:两者相乘(默认)
- replace:用function score替换query score
- 其他:sum、avg、max、min
布尔查询
布尔查询是一个或者多个查询子句的组合
- must:必须匹配每个子查询,类似“与”,
- should:选择性匹配子查询,类似“或”,
- must_not:必须不匹配,类似“非”不参与算分
- fiter:必须不匹配,不参与算分
需求:搜索名字包含如家,价格不高于400在坐标31.21,121.5周围10km范围的酒店文档
语法:
代码语言:javascript复制#布尔查询
GET /hotel/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "如家"
}
}
],
"must_not": [
{
"range": {
"price": {
"gt": 400
}
}
}
],
"filter": [
{
"geo_distance": {
"distance": "10km",
"location": "31.21,121.51"
}
}
]
}
}
}
搜索结果处理
排序
es支持对搜索结果排序,默认是根据相关度算分来排序,可以排序的字段有:keyword类型、数值类型、地理坐标、日期类型等
通过评分和价格排序:
代码语言:javascript复制#通过评分和价格排序
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"score": {
"order": "desc"
},
"price": {
"order": "asc"
}
}
]
}
当有多个排序条件时会优先执行前面的条件
通过距离排序
代码语言:javascript复制#通过距离排序
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance": {
"location": "31.226215,121.495706",
"order": "asc",
"unit": "km"
}
}
]
}
注意这里的经纬度是纬度在前
分页
es中默认只返回top10的数据,而如果要查询更多数据就需要修改分页参数了
es中通过修改from、size参数来控制返回的分页结果
代码语言:javascript复制#分页
GET /hotel/_search
{
"query": {
"match_all": {}
},
//起始记录数
"from": 0,
//获取文档总数
"size": 20
}
语法解释:
from:获取文档的起始位置默认是0(from = size*(page-1))
size:一次获取的文档总数
注意:es能获取到的最大数据为10000
深度分页问题
es的分页原理是先查询出分页所需的所有文档(例如from=100,size=10,就会查询出110条数据再返回101-110的数据)当然这在单机状态是没有问题的,在分布式系统中就会出现问题
集群es中的数据是分片存储在不同的es机器上的,假如集群中有100台机器查询数据为from=990,size=10,es就会从不同的es机器上分别查找1000条数据,然后聚合重排序后返回991-1000的数据,这次查询就会查询出100*(990 10)=100000,这10万条数据放进内存重排序时非常消耗cpu和内存甚至造成服务器宕机,所以在业务中应尽量避免使用深度分页(es设定结果集的上限为10000)
深度分页问题解决方案
针对深度分页,es提供了两种解决方案
search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据(官方推荐方式)
scroll:原理将排序数据形成快照,保存在内存(不推荐使用)
搜索结果高亮
es支持给搜索出来的关键字加标签,前端在给相应标签写样式就实现了搜索功能高亮
语法:
代码语言:javascript复制#高亮显示
GET /hotel/_search
{
"query": {
"match": {
"all": "如家"
}
},
"highlight": {
//开始标签
"pre_tags": "<em>",
//结束标签
"post_tags": "</em>",
//是否字段匹配,默认情况下搜索字段需要与高亮字段匹配
"require_field_match": "false",
//高亮字段
"fields": {
"name": {},
"brand": {}
}
}
}