微服务专题笔记|ElasticSearch——DSL查询及结果处理


文章目录

  • 1.DSL查询语法
    • 1.1.DSL查询分类和基本语法
    • 1.2.全文检索
    • 1.3.精确查询
    • 1.4.地理查询
    • 1.5复合查询
  • 2.查询结果处理
    • 2.1.排序
    • 2.2.分页
    • 2.3.高亮
  • 3.RestClient查询文档
  • 4.RestClient处理结果
    • 4.1分页与排序
    • 4.2高亮

1.DSL查询语法 1.1.DSL查询分类和基本语法 常见的查询类型包括:
查询类型 描述
查询所有 查询出所有数据 例如:match_all
全文检索查询 利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:match 、 multi_match
精确查询 根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。例如:ids、range、term
地理查询 根据经纬度查询。例如:geo_distance、geo_bounding_box
复合查询 复合查询可以将上述各种查询条件组合起来,合并查询条件。例如:bool、function_score
【基本查询语法】
GET /索引库名/_search { "query": { "查询类型": { "查询条件": "条件值" } } }

【案例】
微服务专题笔记|ElasticSearch——DSL查询及结果处理
文章图片

1.2.全文检索 全文检索会对用户输入内容分词,常用于搜索框搜索
【match语法】
GET /索引库名/_search { "query": { "match": { "要搜索的字段": "搜索的值" } } }

【multi_match语法】
GET /索引库名/_search { "query": { "multi_match": { "query": "搜索的值", "fields": ["要搜索的字段1","要搜索的字段2","要搜索的字段3"] } } }

【案例】
微服务专题笔记|ElasticSearch——DSL查询及结果处理
文章图片

参与查询的字段越多查询性能越差。建议使用match查询,将要查询的多个要查字段通过copy_to拷到一个字段中
1.3.精确查询 精确查询你一般是查找keyword、日期、boolean等字段类型,不会对搜索条件分词。
【term查询语法】
GET /索引库名/_search { "query": { "term": { "要搜索的字段": { "value": "要搜索的值" } } } }

【range查询语法】范围查询:可以是数值也可以是日期
GET /hotel/_search { "query": { "range": { "要搜索的字段": { "gte": 最小值, "lte": 最大值 } } } }

【案例】
微服务专题笔记|ElasticSearch——DSL查询及结果处理
文章图片

1.4.地理查询 根据经纬度查询
  • geo_bounding_box:查询geo_point落在某个矩形范围内的所有文档
  • geo_distance:查询到指定中心点小于某个举例值得所有文档
【geo_bounding_box语法】
GET /hotel/_search { "query": { "geo_bounding_box": { "位置字段": { "top_left": { "lat": 维度位置, "lon": 经度位置 }, "bottom_right": { "lat": 经度位置, "lon": 维度位置 } } } } }

【geo_distance查询语法】
GET /hotel/_search { "query": { "geo_distance": { "distance": "距离(例如15km)", "位置字段": "经纬度" } } }

【案例】
微服务专题笔记|ElasticSearch——DSL查询及结果处理
文章图片

1.5复合查询 复合查询可以将其他简单查询组合起来,实现更复杂的搜索逻辑
  • function_score:算分函数查询,可以控制文档相关性算分,控制文档排名
  • bool:布尔查询是一个或多个查询子句的组合
【微服务专题笔记|ElasticSearch——DSL查询及结果处理】【function_score语法】
GET /索引库名/_search { "query": { "function_score": { "query": { //原始查询条件 "查询类型": { "字段名": "值" } }, "functions": [ { "filter": { //过滤条件,符合条件的文档才会被重新算分 "term": { "字段名": "值" } }, "weight": 1 //算分函数 } ], "boost_mode": "multiply" //加权模式 } } }

常见算分模式:
  • weight:给一个常量值作为函数结果
  • field_value_factor:用文档中的某个字段作为函数结果
  • random_score:随机生成一个值作为函数的结果
  • script_score:自定义计算公式,公式结果作为函数结果
【案例】
微服务专题笔记|ElasticSearch——DSL查询及结果处理
文章图片

【bool语法】
GET /索引库名/_search { "query": { "bool": { "子查询一": [], "子查询二": [], "子查询三": [], //... } } }

子查询的组合方式有:
  • must:必须匹配每个子查询,类似"与"
  • should:选择性匹配子查询,类似"或"
  • must_not:必须不匹配,不参与算分,类似"非"
  • filter:必须匹配,不参与算分
【案例】
微服务专题笔记|ElasticSearch——DSL查询及结果处理
文章图片

2.查询结果处理 2.1.排序 ElasticSearch默认按照相关度算分(_score)排序,ES允许指定自定义排序字段。可以排序的字段有:keyword类型、数值类型、地理坐标类型、日期类型等。
【语法】
GET /索引库名/_search { "query": { "match_all": {} }, "sort": [ { "参与排序的字段": { "order": "desc" } } ] }

【案例】
微服务专题笔记|ElasticSearch——DSL查询及结果处理
文章图片

【按照距离排序】
GET /hotel/_search { "query": { "match_all": {} }, "sort": [ { "_geo_distance": { "location": { "lat": 32.123, "lon": 121.221 }, "order": "asc", "unit": "km" } } ] }

2.2.分页 ElasticSearch默认情况下只返回top10的数据,如果需要查询更多的数据就需要修改分页参数
【语法】
GET /hotel/_search { "query": { "match_all": {} }, "from": 45,//分页开始的位置,默认为0 "size": 15,//期望获得的文档总数,默认为10 "sort": [ { "price": "asc"} ] }

默认查询上限(from+size)是10000
2.3.高亮 【语法】
GET /hotel/_search { "query": { "match": { "name": "深圳" } }, "highlight": { "fields": { "name": { //指定要高亮的字段 "require_field_match": "false", //默认情况搜索字段要与高亮字段一致 "pre_tags": "",//标记高亮的前置标签 "post_tags": "" //标记高亮的后置标签 } } } }

3.RestClient查询文档
@Test void testMatchAll() throws IOException{ //1.准备request SearchRequest searchRequest = new SearchRequest("hotel"); //2.准备DSL参数 //searchRequest.source().query(QueryBuilders.matchAllQuery()); //match_all查询 //searchRequest.source().query(QueryBuilders.matchQuery("name","北京")); //match查询 //searchRequest.source().query(QueryBuilders.multiMatchQuery("南京","city","name")); //multi_match查询 //searchRequest.source().query(QueryBuilders.termQuery("city","上海")); //精确查询 //searchRequest.source().query(QueryBuilders.rangeQuery("price").gte(100).lte(200)); //范围查询 searchRequest.source().query(QueryBuilders.boolQuery() .must(QueryBuilders.termQuery("city","上海")) .filter(QueryBuilders.rangeQuery("price").gte(100).lte(200)) ); //组合查询//3.发送请求,得到响应结果 SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); //4.解析响应结果 SearchHits searchHits = searchResponse.getHits(); //4.1获取查询的总条数 long total = searchHits.getTotalHits().value; System.out.println(total); //4.2查询结果的数组 SearchHit[] hits = searchHits.getHits(); for (SearchHit hit : hits) { //4.3获取source String json = hit.getSourceAsString(); //4.4反序列化成hotelDoc对象 HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); System.out.println(hotelDoc); } }

4.RestClient处理结果 4.1分页与排序
@Test void testSort() throws IOException{ int page = 2,size = 15; SearchRequest searchRequest = new SearchRequest("hotel"); searchRequest.source().query(QueryBuilders.matchAllQuery()); //分页 searchRequest.source().from((page-1)*size).size(size); //排序 searchRequest.source().sort("price", SortOrder.DESC); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); //.... }

4.2高亮
@Test void testHeightLighter() throws IOException{ SearchRequest searchRequest = new SearchRequest("hotel"); searchRequest.source().query(QueryBuilders.termQuery("brand","喜来登")); //高亮 searchRequest.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false)); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); //结果高亮处理 SearchHits searchHits = searchResponse.getHits(); SearchHit[] hits = searchHits.getHits(); for (SearchHit hit : hits) { //4.3获取source String json = hit.getSourceAsString(); HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); Map 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); } }

    推荐阅读