DSL查询文档
利用RestClient往ES中导入了很多数据,数据的存储不是目的,最终是从海量的数据中,检索出你所需要的哪些,这就用到了ES的搜索功能了
一、DSL查询分类
1.1.常见的查询类型
Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括:
1).查询所有:查询出所有数据,一般测试用。例如:match_all
2).全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:
- match_query
- multi_match_query
3).精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。例如:
- ids
- range
- term
4).地理(geo)查询:根据经纬度查询。例如:
- geo_distance
- geo_bounding_box
5).复合(compound)查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如:
- bool
- function_score
1.2.DSL Query基本语法
语法如下:
GET /indexName/_search { "query": { "查询类型": { "查询条件": "条件值" } } }
查询所有
# 查询所有 GET /indexname/_search { "query": { "match_all": {} } }
查询所有是不需要查询条件的,以查询文档库hotel为例如下:
# 查询hotel文档库中所有内容 GET /hotel/_search { "query": { "match_all": {} } }
执行后结果如下:

二、全文检索查询
全文检索查询,会对用户输入内容分词,常用于搜索框搜索,例如京东搜索功能

2.1.全文检索查询:match
2.1.1.语法说明
match查询:全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索,语法:
GET /indexName/_search { "query": { "match": { "FIELD": "TEXT" } } }
注意:
match:代表有条件,field:字段根据那个字段查询 text:要搜索的内容
2.1.2.案例
查询条件:全文检索字段all ,含有外滩,all是前面学习表映射时的多个字段的结合字段
# match查询 GET /hotel/_search { "query": { "match": { "all": "外滩" } } }
执行后结果如下:

全文检索all字段:外滩如家,会对外滩如家进行分词,然后倒排索引,
# match查询 GET /hotel/_search { "query": { "match": { "all": "外滩如家" } } }
执行后结果如下:

2.2.全文检索查询:multi_match
2.2.1.语法如下:
multi_match:与match查询类似,只不过允许同时查询多个字段,语法:
GET /indexName/_search { "query": { "multi_match": { "query": "TEXT", "fields": ["FIELD1","FIELD2"] } } }
2.2.2.案例演示
multi_match 多个点字段搜索:在多个字段中查询 含有外滩如家的
# 根据"name", "brand", "business"字段全文检索外滩如家 GET /hotel/_search { "query": { "multi_match": { "query": "外滩如家", "fields": ["name", "brand", "business"] } } }
执行后结果如下:

2.3.通过使用all和多个字段搜索是一样的,那么使用那个呢?
参与搜索的字段越多查询效率越低推荐使用all的方法,不要查询整个字段,而是把字段copy到一个字段中去查,这样效率更高
三、精准查询
3.1.精准查询说明
精确查询一般是查找keyword、数值、日期、boolean等类型字段。所以不会对搜索条件分词。常见的有:
- term:根据词条精确值查询
- range:根据值的范围查询
例如:京东中对于CPU型号、机身内存都属于精准查询,

而这几个字段brand(品牌)、city(城市)、price(价格)、score(评分):都是keyword 或数值类型,在查询的时候不能进行分词

3.2.语法
精确查询常见的有term查询和range查询。
- term查询:根据词条精确匹配,一般搜索keyword类型、数值类型、布尔类型、日期类型字段
- range查询:根据数值范围查询,可以是数值、日期的范围
3.2.1.term查询:
语法如下:term是精确匹配的,不会进行分词了
# term查询 GET /indexName/_search { "query": { "term": { "FIELD": { "value": "VALUE" } } } }
案例说明:term根据词条精确查询:查询city为上海的,如下:
# term查询 GET /hotel/_search { "query": { "term": { "city": { "value": "上海" } } } }
执行后结果如下:

3.2.2.range查询:
range:根据条件范围查询,语法如下:
# range查询 GET /indeXname/_search { "query": { "range": { "FIELD": { "gte": 10, "lte": 20 } } } }
案例说明:搜索price大于等于100,小于等于300的酒店信息,如下:
# range查询 GET /hotel/_search { "query": { "range": { "price": { "gte": 100, "lte": 300 } } } }
执行后结果如下:

四、地理坐标查询
4.1.地理坐标查询说明
根据经纬度查询。常见的使用场景包括:
- 携程:搜索当前位置附近的酒店
- 滴滴:搜索我附近的出租车
- 微信:搜索我附近的人
如下:

4.2.地理查询
根据经纬度查询有两种方式。分别为:geo_bounding_box和geo_distance
4.2.1.地理查询:geo_bounding_box
geo_bounding_box:查询geo_point值落在某个矩形范围的所有文档

语法如下:
# 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 } } } } }
案例根据location字段查询,查询左上点位置(121.5,31.1)、和右下点(121.7,30.9)形成的矩形区域内的所有文档,如下:
# geo_bounding_box查询 GET /hotel/_search { "query": { "geo_bounding_box":{ "location":{ "top_left":{ "lat":31.1, "lon":121.5 }, "bottom_right":{ "lat":30.9, "lon":121.7 } } } } }
执行后结果如下:

4.2.2.地理查询:geo_distance
geo_distance:查询到指定中心点小于某个距离值的所有文档

语法如下:
# geo_distance查询 GET /indexname/_search { "query": { "geo_distance":{ "distance": "20km", "FIELD": "31.21,121.5" } } }
案例如下:查询以经纬度(121.5,32.21)为原点,半径20km范围内的酒店信息,如下:
# geo_distance查询 GET /hotel/_search { "query": { "geo_distance":{ "distance": "20km", "location": "31.21,121.5" } } }
执行后结果如下:

五、复合查询
5.1.复合查询
复合(compound)查询:复合查询可以将其它简单查询组合起来,实现更复杂的搜索逻辑,
例如:fuction score:算分函数查询,可以控制文档相关性算分,控制文档排名。如百度竞价排名:

5.2.相关性算分
当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排,例如,我们搜索“虹桥如家”,结果如下:
[ { "_score":17.850193, "_source":{ "name":"虹桥如家酒店真不错",} }, { "_score":12.259849, "_source":{ "name":"外滩如家酒店真不错",} }, { "_score":12.259849, "_source":{ "name":"迪士尼如家酒店真不错",} }, ]
elasticsearch中的相关性打分算法是什么?
- TF-IDF:在elasticsearch5.0之前,会随着词频增加而越来越大
- BM25:在elasticsearch5.0之后,会随着词频增加而增大,但增长曲线会趋于水平
IDF:上面的操作如家在三个文档中都出现了,权重为0 虹桥只有第一条出现了这条文档的权重较大
BM25:算法的影响不会受词频的影响
算法说明:

曲线图如下:

5.3.DSL查询语法-Function Score Query
使用function score query,可以修改文档的相关性算分(query score),根据新得到的算分排序。

上面执行后结果如下:

案例:给如家 品牌的酒店排名靠前一些,想完成设置如家品牌的排名靠前,function score设置需要注意:
1.哪些文档需要算分加权? 品牌为如家的酒店 2.算分函数是什么? weight就可以 3.加权模式是什么? 求和
DSL语法如下:
GET /hotel/_search { "query": { "function_score": { "query": {"match": {"all": "外滩"}}, "functions": [ //算分函数 { "filter": {"term": { "brand": "如家"}}, //满足的条件,品牌必须是如家 "weight": 10 //算分权重为2 } ], "boost_mode": "sum" // 更改加权模式:sum } } }
加权后如家酒店跑到第一名了,如下:

5.4.DSL查询语法-BooleanQuery
Function Score Query和BooleanQuery的区别:
- Function Score Query:计算相关性算分
- Boolean Query:不是计算相关性算分,而是把多个查询语句组合在一起,形成新的查询,被组合的查询称为子查询
复合查询Boolean 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}}} ], } } }
注意:
- must_not和filter 不参与算分 ,它的返回结果是或否 true和false,如果子查询较多,都参与算分,会非常影响性能
- ES会把filer的查询,放到缓存里面,将来在查询的时候,会近一步提高性能
- 有以上四种组合关系,除了跟算分相关的,一般是关键字,放到must和should里面
- 其他的都应该放到must_not和filter里面,尽可能的减少算分提高查询的效率
下面图片的查询,搜索框的内容关键字的搜索可以放到must里,因为它参与算分,过滤条件:类型也好容量也好,放到must_not或者filter里面,放到这里面不参与算分

案例说明:
利用bool查询实现功能,需求:搜索名字包含"如家”,价格不高于400,在坐标31.21,121.5周围10km范围内的酒店。如下:
GET /hotel/_search { "query": { "bool": { "must": [ {"match": {"name": "如家"}} ], "must_not": [ {"range": {"price": {"gt": 400}} } ], "filter": [ {"geo_distance": { "distance": "10km", "location": {"lat": 31.21,"lon": 121.5} }} ] } } }
注意:上面的must_not是取反的,gt值为400表示,价格大于400,取反则是价格小于400。
执行后结果如下:


浙公网安备 33010602011771号