ElasticSearch03——es常用查询类型及其Restclient操作
查询类型查询所有:查询出所有数据,类型是match_all全文检索:利用分词器对用户输入的内容分词,然后去倒排索引中match_query和multi_match_query类型精确查询:根据精确词条查找数据,一般是keyword、数值、日期、boolean类型,有ids、range、term类型地理查询:根据经纬度查询,有geo_distance和geo_bounding_box类型复合查询:复
查询类型
查询所有:查询出所有数据,类型是match_all
全文检索:利用分词器对用户输入的内容分词,然后去倒排索引中match_query和multi_match_query类型
精确查询:根据精确词条查找数据,一般是keyword、数值、日期、boolean类型,有ids、range、term类型
地理查询:根据经纬度查询,有geo_distance和geo_bounding_box类型
复合查询:复合查询是将以上所有条件组合起来,合并查询条件,比如function score查询:算分函数查询,可以控制相关性算分,控制文档排名 还有Boolean query查询,组合条件查询
下面通过DEV_TOOL工具的DSL语句演示几种常用查询
查询所有,match查询
#查询所有 match_all指的是查询类型,表示查询所有
GET /hotel/_search
{
"query": {
"match_all": {
}
}
}
全文检索,match_query查询
#根据条件查询 all是一个字段,后面表示查询内容
GET /hotel/_search
{
"query": {
"match": {
"all": "7天"
}
}
}
全文检索,multi_match_query查询,根据多个条件来查询
#根据多个字段查询 第二个query表示查询条件,fields表示查询的字段,这里是多个字段
GET /hotel/_search
{
"query": {
"multi_match": {
"query": "7天",
"fields": ["brand","name"]
}
}
}
精确查询,term查询
#term查询(精确查询),字段一般是keyword类型,没有分词 city是字段,value表示查询字段的值
GET /hotel/_search
{
"query": {
"term": {
"city": {
"value": "北京"
}
}
}
}
range查询,根据范围查询,通常都是数字一类的
#range查询。根据范围查询,gte是大于等于。lte是小于等于,去掉e则没有等于
GET /hotel/_search
{
"query": {
"range": {
"price": {
"gte":300,
"lte":700
}
}
}
}
地理查询 geo_distance查询,指定一个坐标点,根据范围来查询,需在索引库设置一个经纬度字段,这里设置的是location
#地理坐标查询 "geo_distance"是根据指定位置查询,给一个坐标点,然后设置在查询多少km之内的条件
GET /hotel/_search
{
"query": {
"geo_distance":{
"distance":"2km",
"location":"31.21,121.5"
}
}
}
地理查询 geo_bounding_box查询,根据两个点组成一个矩形范围来查询,lat是纬度,lon是经度
#地理坐标查询 geo_bounding_box 是分别根据左上和右下两个点组成的矩形范围进行查找
GET /hotel/_search
{
"query":{
"geo_bounding_box":{
"location":{
"top_left":{"lat":"31.21",
"lon":"121.5"},
"bottom_right":{"lat":"30.21",
"lon":"122.5"
}
}
}
}
}
复合查询:function score类型,通过相关性算分,分数越高排名越靠前,在es5.0之前用的是TF-IDF算法,es5.0之后用的是BM25算法,这里引用黑马视频截图说明
可以对比一下两种算法的区别,BM25算法会随着词频增大而增大,但增长曲线会趋于水平 而function score就是在原始的算分方法之上,通过修改算分函数,来修改分数,分高者排名靠前
具体语法如下
根据上述模式写一个dsl语句
#function score查询 这里表示搜索外滩字段时可能会有多个酒店品牌,通过修改将字段brand为“如家”的酒店的权重增加10分,使其排名靠前
GET /hotel/_search
{
"query":{
"function_score":{
"query":{
"match":{
"all":"外滩"
}
},
"functions": [
{"filter": {
"term": {
"brand": "如家"
}
},
"weight": 10
}
],
"boost_mode": "sum"
}
}
}
复合查询:Boolean query查询。布尔查询是一个或多个查询子句的组合,组合方式有:
- must:必须匹配每个子查询,类似与“与”
- should:选择性匹配子查询,类似于“或”
- must_not:必须不匹配,不参与算分,类似于“非”
- filter:必须匹配,不参与算分,不参与算分可以提高性能
下面写一个dsl语句,要求查询"如家"或者是"君悦"品牌,价格不高于1000,距离自定义坐标点不超过10km。 根据分析可知,搜索的是两个品牌中的一个都可以,所以是"或"关系,并且品牌参与算分 ,所以用should,价格不高于1000,而且价格不参与算分,可以用must_not,距离也不参与算分,用filter,如果用must_not则是10km之外的酒店,所以不可取
GET hotel/_search
{
"query":{
"bool": {
"should": [
{"match": {
"brand": "如家"
}},
{"match": {
"brand": "君悦"
}}
],
"must_not": [
{"range": {
"price": {
"gt": 1000
}
}}
],
"filter": [
{"geo_distance": {
"distance": "10km",
"location": "31.220706, 121.498769"
} }
]
}
}
}
搜索结果排序处理——将查询出的结果排序
排序结果默认是相关性算分排序,排序的字段类型有keyword类型、数值类型、地理坐标类型、日期类型,除了地理坐标外,其他语法基本相同,语法如下
#搜索结果排序处理 sort和query同级,里面添加可排序的字段,选择升序或降序
GET /hotel/_search
{
"query":{
"function_score":{
"query":{
"match":{
"all":"外滩"
}
}
}
},
"sort":[
{ "price":"desc"},
{"socre":"desc"}
]
}
这里表示先按照price字段排序,如果值相等,再按照score字段排序
还有一个是地理坐标排序,语法如下
#搜索结果排序处理 地理坐标排序 _geo_distance表示地理坐标排序
#location是一个经纬度字段 然后设置经纬度 通过order来排序
GET /hotel/_search
{
"query":{
"function_score":{
"query":{
"match":{
"all":"外滩"
}
}
}
},
"sort":[
{"_geo_distance": {
"location": {
"lat": 32,
"lon": 122
},
"order": "asc"
}}
]
}
处理结果分页
正常情况下默认分页10条,也可以手动指定,语法如下
#搜索结果分页处理 from表示从第几条数据开始显示 size表示要分页多少页
#这里表示从第10条数据开始显示 总共只显示5条
GET /hotel/_search
{
"query":{
"match": {
"all": "酒店"
}
},
"from": 10,
"size": 5
}
es分页原理是先把所有数据查出来,再根据我们设置的分页去截这一段数据,考虑到es存在多个集群,如果集群过多且分页数过大,会造成极大的内存消耗,所以es官方只运行最大分页到10000
比如:
GET /hotel/_search
{
"query":{
"match": {
"all": "酒店"
}
},
"from": 9995,
"size": 6
}
#当出现从第9995条数据开始,往后查6条,实际上就是第10001条数据,这时候就会报错,官方最多允许查10000条数据
如果要查10000之后的数据,可以用search after,分页时需要先排序,原理是从上一次的排序值开始,查询下一页数据,该方法只能向后分页,不能向前分页
scroll:原理是将排序数据形成快照,保存在内存,不推荐使用 。 内存消耗大,而且因为是快照,所以如果有数据更新了也无法及时获取新数据
高亮处理
将查询到的关键字进行高亮处理,方便显示,比如当搜索百度时,这个关键字就会变红,这就是做了高亮处理
语法如下,高亮添加只能用match,不要用match_all,全部搜索就没有高亮的意义了,这里表示对酒店进行高亮
#高亮处理 highlight表示高亮 fields表示需要高亮的字段,这里是name
#require_field_match表示是否需要和搜索的字段匹配,默认是true,因为我的搜索字段all,如果默认匹配的话和我要高亮的name字段就不匹配了,所以我选择false,正常情况如果我的搜索字段和高亮字段一致可以不写
# pre_tags表示要在搜索字段前面添加的标签,默认就是<em>,也可以不写出来 "post_tags"则是在后面添加的标签 添加标签后前端才好对其设置样式显示高亮
GET /hotel/_search
{
"query":{
"match": {
"all": "酒店"
}
},
"highlight": {
"fields": {"name":{ "require_field_match": "false"}},
"pre_tags": "<em>",
"post_tags": "</em>"
}
}
ResrClient操作es
Match_all查询
//首先初始化client
@Autowired
private IHotelService hotelService;
//声明对象,并做对象初始化连接到es,提高代码复用性
private RestHighLevelClient client;
@BeforeEach
void set() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.65.129:9200")//es地址
));
}
@AfterEach
void terDown() throws IOException {
this.client.close();
}
@Test //常用的查询方式
void testMatchall() throws IOException {
//1、准备请求
SearchRequest request = new SearchRequest("hotel");
//2、准备dsl,这里官方已经封装好了,直接调方法来用就行了 matchAll类型
request.source().query(QueryBuilders.matchAllQuery());
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//代码抽取后引用
handleReponse(response);
}
//抽取重复代码
private void handleReponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("总共搜索到" + total + "条数据");
//4.2文档数据
SearchHit[] hits = searchHits.getHits();
//遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//将数据反序列化为对象
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
//获取高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if(!CollectionUtils.isEmpty(highlightFields)){
//根据字段名字获取高亮结果
HighlightField highlightField = highlightFields.get("name");
if(highlightField!=null){
//获取高亮值
String name = highlightField.getFragments()[0].string();
//覆盖非高亮结果
hotelDoc.setName(name);
}
}
System.out.println("hotelDoc:" + hotelDoc);
}
}
}
Match查询
@Test //常用的查询方式
void testMatch() throws IOException {
//1、准备请求
SearchRequest request = new SearchRequest("hotel");
//2、准备dsl match类型
//request.source().query(QueryBuilders.matchQuery("all", "如家")); //里面的参数分别为搜索的字段名字和搜索的值
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//代码抽取后引用
handleReponse(response);
multi_match查询 term查询 range查询
@Test //常用的查询方式
void testMatch2() throws IOException {
//1、准备请求
SearchRequest request = new SearchRequest("hotel");
//2、准备dsl match类型
//multi_match类型
request.source().query(QueryBuilders.multiMatchQuery("如家","all","name"));//里面参数分别是要搜索的字段值,然后是要搜索的字段名字
//term查询
request.source().query(QueryBuilders.termQuery("city","北京"));//对应的参数分别是字段名称,要查询的字段的值
//range查询
request.source().query(QueryBuilders.rangeQuery("price").gte(200).lte(500));//对应的参数是字段名字,后面接一个取值范围,大于多少小于多少
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//代码抽取后引用
handleReponse(response);
复合查询及其分页操作
@Test //复合查询
void testComplexMatch() throws IOException {
//1、准备请求
SearchRequest request = new SearchRequest("hotel");
//创建BoolQueryBuilder对象,通过对象指定"与","或"等等,然后再指定查询的方法
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.termQuery("杭州","北京"));
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(200).lte(500));
//准备dsl
request.source().query(boolQueryBuilder);
//分页查询
request.source().from(5).size(10); //表示查询第五页的10条数据
//搜索结果排序
request.source().sort("price", SortOrder.ASC);
//发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//代码抽取后引用
handleReponse(response);
}
搜索结果高亮处理
//搜索结果的高亮处理
@Test
void testgaoliang() throws IOException {
//1、准备请求
SearchRequest request = new SearchRequest("hotel");
//2、准备dsl
request.source().query(QueryBuilders.matchQuery("all","如家"));
//高亮 设置高亮字段和设置是否让高亮字段和搜索字段匹配,默认是true,这里选false
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
//发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//代码抽取后引用
handleReponse(response);
}
更多推荐
所有评论(0)