es的dsl语法以及javaAPI的使用

查询方法

查询所有:查询出所有数据,一般测试用。例如:match_all

GET _search
{
  "query": {
    "match_all": {}
  }
}
  request.source().query(
                QueryBuilders.matchAllQuery()
        );
  • 全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:

    • match查询:单字段查询

    • multi_match查询:多字段查询,任意一个字段符合条件就算符合查询条件

    • 搜索字段越多,对查询性能影响越大,因此建议采用copy_to,然后单字段查询的方式
    • #全文检索
      GET /hotel/_search
      {
        "query": {
          "match": {
            "all": "如家"
          }
        }
      }
      GET /hotel/_search
      {
        "query": {
          "multi_match": {
            "query": "7天",
            "fields": ["name","brand","city"]
          }
        }
      }
         request.source().query(
                      QueryBuilders.matchQuery("all", "如家")
              );
      
      
         request.source().query(
                      QueryBuilders.multiMatchQuery("如家", "name", "brand", "city")
              );

    • 精确查询

    • 精确查询一般是查找keyword、数值、日期、boolean等类型字段。所以不会对搜索条件分词。常见的有
      • ids

      • term:根据词条精确值查询

      • range:范围查询,一般应用在对数值类型做范围过滤的时候。比如做价格范围过滤。

      • 因为精确查询的字段搜是不分词的字段,因此查询的条件也必须是不分词的词条。查询时,用户输入的内容跟自动值完全匹配时才认为符合条件。如果用户输入的内容过多,反而搜索不到数据。

      • #精确查询
        #term 根据词条精确查询
        #range 根据值的范围查询
        GET /hotel/_search
        {
          "query": {
           "term": {
             "city": {
               "value": "北京"
             }
           } 
          }
        }
        
        
        GET /hotel/_search
        {
          "query": {
            "range": {
              "price": {
                "gte": 100,
                "lte": 1000
              }
            }
          }
        }
              request.source().query(
                        QueryBuilders.termQuery("city", "北京")
                );
               request.source().query(
                        QueryBuilders.rangeQuery("price")
                                .gt(1000)
                                .lt(3000)
                );
        

      • 地理(geo)查询:根据经纬度查询。例如:

        • geo_distance

        • geo_bounding_box

    • #地理查询
      #查询附件的坐标点
      GET /hotel/_search
      {
        "query": {
         "geo_distance":{
           "distance" : "15km",
            "location" : "31.21,121.5"
         }
        }
      }

    • 复合(compound)查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如:

      • fuction score:算分函数查询,可以控制文档相关性算分,控制文档排名

      • bool query:布尔查询,利用逻辑关系组合多个其它的查询,实现复杂搜索

      • 
        GET /hotel/_search
        {
          "query": {
            "bool": {
              "must": [
                {
                 "match": {
                   "name": "如家"
                 }
                }
              ],
              "must_not": [
                {
                  "range": {
                    "price": {
                      "gt": 400
                    }
                  }
                }
              ],
              "filter": [
                {
                  "geo_distance": {
                    "distance": "15km"
                    , "location": {
                      "lat": 31.21,
                      "lon": 121.5
                    }
                  }
                }
              ]
            }
          }
        }
        

        算分函数

      • GET /hotel/_search
        {
          "query": {
            "function_score": {
              "query": {
                 "match": {
                   "all": "外滩"
                 }
              },
              "functions": [
                {
                  "filter": {
                    "term": {
                      "brand": "如家"
                    }
                  }
                  , "weight": 10
                }
              ],
              "boost_mode": "sum"
            }
          }
        }

        值得注意的是,算分函数,在查询语句要在算分函数内,

      • 意义是先查到文档,然后过滤,进行算分

      • must:必须匹配每个子查询,类似“与”

      • should:选择性匹配子查询,类似“或”

      • must_not:必须不匹配,不参与算分,类似“非”

      • filter:必须匹配,不参与算分

      elasticsearch默认是根据相关度算分(_score)来排序,但是也支持自定义方式对搜索结果排序。可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。
    • 值得注意的是,如果进行排序了,原始的算分排序就失效了
    • 普通排序
    • 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" // 排序的距离单位
            }
          }
        ]
      }

      分页

    • GET /hotel/_search
      {
        "query": {
          "match_all": {}
        },
        "from": 0, // 分页开始的位置,默认为0
        "size": 10, // 期望获取的文档总数
        "sort": [
          {"price": "asc"}
        ]
      }

      深度分页问题

      现在,我要查询990~1000的数据,查询逻辑要这么写

    • 高亮原理

    • 值得注意的是高亮的时候,必须有搜索值的传入
    • #高亮
      #就是在搜索结果中把所有关键字突出显示
      GET /hotel/_search
      {
        "query": {
           "match": {
             "all": "如家"
           }
        },
        "highlight": {
          "fields": {
            "name": {
              "require_field_match": "false"
            }
             
          }
        }
      }

      下面是统一的java,api实现

    • @Service
      public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
          @Resource
          private RestHighLevelClient client;
          @Override
          public PageResult search(RequestParams params) {
              //查询数据
              SearchRequest request = new SearchRequest("hotel");
              //使用bool复合查询
              BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
              //判断params有没有key
              String key = params.getKey();
              if (StringUtils.isBlank(key)){
                  //查所有
                  boolQueryBuilder.must(QueryBuilders.matchAllQuery());
              }else {
                  boolQueryBuilder.must(QueryBuilders.matchQuery("all",key));
                  //有搜索项就可以高亮啦
                  request.source().highlighter(new  HighlightBuilder().field("name").requireFieldMatch(false)
                  );
              }
              if (StringUtils.isNotBlank(params.getBrand())){
                  //如果又品牌条件使用不参与算分
                  boolQueryBuilder.filter(QueryBuilders.termQuery("brand",params.getBrand()));
              }
              if (StringUtils.isNotBlank(params.getCity())){
                  //如果又城市条件使用不参与算分
                  boolQueryBuilder.filter(QueryBuilders.termQuery("city",params.getCity()));
              }
              if (StringUtils.isNotBlank(params.getStarName())){
                  //如果又星级条件使用不参与算分
                  boolQueryBuilder.filter(QueryBuilders.termQuery("starName",params.getStarName()));
              }
              if (params.getMinPrice()!=null&&params.getMaxPrice()!=null){
                  //如果价钱又限制,不参与算分
                  boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
              }
              //加广告
              FunctionScoreQueryBuilder isAD = QueryBuilders.functionScoreQuery(
                      boolQueryBuilder, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                              new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("isAD", true),
                                      ScoreFunctionBuilders.weightFactorFunction(10))
                      }
              ).boostMode(CombineFunction.MULTIPLY);
              request.source().query(isAD);
              //如果又距离的话需要根据距离排序
              if (StringUtils.isNotBlank(params.getLocation())){
                  request.source().sort(SortBuilders.geoDistanceSort(
                          "location",new GeoPoint(params.getLocation())
                  ).unit(DistanceUnit.KILOMETERS).order(SortOrder.ASC));
              }
      
             //分页
              Integer size = params.getSize();
              int page = (params.getPage() - 1) * size;
              request.source().from(page).size(size);
              //显示距离
              try {
                  SearchResponse response = client.search(request, RequestOptions.DEFAULT);
                  PageResult pageResult = new PageResult();
                  SearchHits searchHits = response.getHits();
                  long value = searchHits.getTotalHits().value;
                  SearchHit[] hits = searchHits.getHits();
                  pageResult.setTotal(value);
                  List<HotelDoc> hotelDocs = new ArrayList<>();
                  for (SearchHit hit : hits) {
                      String json = hit.getSourceAsString();
                      HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
              //需要获得地址距离,和高亮的覆盖
                      Object[] sortValues = hit.getSortValues();
                    if (sortValues.length>0){
                        hotelDoc.setDistance(sortValues[0]);
                    }
               //显示高亮
                      Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    if (CollectionUtils.isNotEmpty(highlightFields)){
                        HighlightField name = highlightFields.get("name");
                        if (Objects.nonNull(name)){
                            String s = name.getFragments()[0].toString();
                            hotelDoc.setName(s);
                        }
                    }
                    hotelDocs.add(hotelDoc);
                  }
                  pageResult.setHotels(hotelDocs);
                  return pageResult;
              } catch (IOException e) {
                 throw  new RuntimeException(e);
              }
              //解析返回值
          }
      }
      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值