能够描述es基础搜索语法?常见query类型?
- 查询所有
- 查询出所有数据,一般测试用。例如:match_all
- 全文检索查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如
- match_query 根据一个字段查询
```json @Test void testMatch() throws IOException { // 1.准备Request SearchRequest request = new SearchRequest(“hotel”); // 2.准备DSL request.source() .query(QueryBuilders.matchQuery(“all”, “如家”)); // 3.发送请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.解析响应 handleResponse(response);GET /indexName/_search{"query": {"match": {"FIELD": "TEXT"}}}
- match_query 根据一个字段查询
}
- multi_match_query 根据多个字段查询,参与查询字段越多,查询性能越差```jsonGET /indexName/_search{"query": {"multi_match": {"query": "TEXT","fields": ["FIELD1", " FIELD12"]}}}
精确查询
根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。例如:
- ids
range
// range查询 GET /indexName/_search { "query": { "range": { "FIELD": { "gte": 10, "lte": 20 } } } }Integer minPrice = params.getMinPrice(); Integer maxPrice = params.getMaxPrice(); if (maxPrice != null && minPrice != null) { boolQuery.filter(QueryBuilders.rangeQuery("price").gte(minPrice).lt(maxPrice)); }term
// term查询 GET /indexName/_search { "query": { "term": { "FIELD": { "value": "VALUE" } } } }//城市不为空使用term查询字段 String starName = params.getCity(); if (StringUtils.isBlank(starName)) { boolQuery.filter(QueryBuilders.termQuery("starName", starName)); }
地理(geo)查询
根据经纬度查询。例如
geo_distance 查询到指定中心点小于某个距离值的所有文档
// geo_distance 查询 GET /indexName/_search { "query": { "geo_distance": { "distance": "15km", "FIELD": "31.21,121.5" } } }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 } } } } }
复合(compound)查询
复合查询可以将上述各种查询条件组合起来,合并查询条件。例如
- bool
- must:必须匹配每个子查询,类似“与”
- should:选择性匹配子查询,类似“或”
- must_not:必须不匹配,不参与算分,类似“非”
- filter:必须匹配,不参与算分
```json @Test void testBool() throws IOException { // 1.准备Request SearchRequest request = new SearchRequest(“hotel”); // 2.准备DSL // 2.1.准备BooleanQuery BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // 2.2.添加term boolQuery.must(QueryBuilders.termQuery(“city”, “杭州”)); // 2.3.添加range boolQuery.filter(QueryBuilders.rangeQuery(“price”).lte(250));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} } } ] } } }
request.source().query(boolQuery); // 3.发送请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.解析响应 handleResponse(response); } ```
- function_score
- bool

- 查询的语法基本一致
```json
GET /indexName/_search
{
“query”: {
“查询类型”: {
} } }"查询条件": "条件值"
查询类型为match_all // 查询所有 GET /indexName/_search { “query”: { “match_all”: { } } }
<a name="pgMDS"></a>
### es实现地理坐标查询思路?
- 修改RequestParams参数,接收location字段
- 修改search方法业务逻辑,如果location有值,添加根据geo_distance排序的功能
```java
@Override
public PageResult search(RequestParams params) {
try {
// 1.准备Request
SearchRequest request = new SearchRequest("hotel");
// 2.准备DSL
// 2.1.query
buildBasicQuery(params, request);
// 2.2.分页
int page = params.getPage();
int size = params.getSize();
request.source().from((page - 1) * size).size(size);
// 2.3.排序
String location = params.getLocation();
if (location != null && !location.equals("")) {
request.source().sort(SortBuilders
.geoDistanceSort("location", new GeoPoint(location))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS)
);
}
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
排序距离显示
- 修改HotelDoc,添加排序距离字段,用于页面显示
- 修改HotelService类中的handleResponse方法,添加对sort值的获取
//解析响应结果 SearchHits hits = response.getHits(); PageResult pageResult = new PageResult(); //设置查询数量 pageResult.setTotal(hits.getTotalHits().value); List<HotelDoc> list = new ArrayList<>(); //遍历文档列表 for (SearchHit hit : hits) { HotelDoc hotelDoc = JSON.parseObject(hit.getSourceAsString(), HotelDoc.class); if (StringUtils.isBlank(location)) { Object[] sortValues = hit.getSortValues(); if (sortValues != null && sortValues.length > 0) { hotelDoc.setDistance(sortValues[0]); } } list.add(hotelDoc); } pageResult.setHotels(list); return pageResult; } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("es搜索出错了!"); }es实现高亮思路?
第一步:从结果中获取source。hit.getSourceAsString(),这部分是非高亮结果,json字符串。还需要反序列为HotelDoc对象
- 第二步:获取高亮结果。hit.getHighlightFields(),返回值是一个Map,key是高亮字段名称,值是HighlightField对象,代表高亮值
- 第三步:从map中根据高亮字段名称,获取高亮字段值对象HighlightField
- 第四步:从HighlightField中获取Fragments,并且转为字符串。这部分就是真正的高亮字符串了
- 第五步:用高亮的结果替换HotelDoc中的非高亮结果
private void handleResponse(SearchResponse response) { // 4.解析响应 SearchHits searchHits = response.getHits(); // 4.1.获取总条数 long total = searchHits.getTotalHits().value; System.out.println("共搜索到" + total + "条数据"); // 4.2.文档数组 SearchHit[] hits = searchHits.getHits(); // 4.3.遍历 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); } }es实现竞价排名思路?
- 给HotelDoc类添加isAD字段,Boolean类型
- 挑选几个你喜欢的酒店,给它的文档数据添加isAD字段,值为true
修改search方法,添加function score功能,给isAD值为true的酒店增加权重
private void buildBasicQuery(RequestParams params, SearchRequest request) { // 1.构建BooleanQuery BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // 关键字搜索 String key = params.getKey(); if (key == null || "".equals(key)) { boolQuery.must(QueryBuilders.matchAllQuery()); } else { boolQuery.must(QueryBuilders.matchQuery("all", key)); } // 城市条件 if (params.getCity() != null && !params.getCity().equals("")) { boolQuery.filter(QueryBuilders.termQuery("city", params.getCity())); } // 品牌条件 if (params.getBrand() != null && !params.getBrand().equals("")) { boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand())); } // 星级条件 if (params.getStarName() != null && !params.getStarName().equals("")) { boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName())); } // 价格 if (params.getMinPrice() != null && params.getMaxPrice() != null) { boolQuery.filter(QueryBuilders .rangeQuery("price") .gte(params.getMinPrice()) .lte(params.getMaxPrice()) ); } // 2.算分控制 FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery( // 原始查询,相关性算分的查询 boolQuery, // function score的数组 new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ // 其中的一个function score 元素 new FunctionScoreQueryBuilder.FilterFunctionBuilder( // 过滤条件 QueryBuilders.termQuery("isAD", true), // 算分函数 ScoreFunctionBuilders.weightFactorFunction(10) ) }); request.source().query(functionScoreQuery); }排序、分页查询
通过修改from、size参数来控制要返回的分页结果
GET /hotel/_search { "query": { "match_all": {} }, "from": 990, // 分页开始的位置,默认为0 "size": 10, // 期望获取的文档总数 "sort": [ {"price": "asc"} ] }代码示例 ```json @Test void testPageAndSort() throws IOException { // 页码,每页大小 int page = 1, size = 5;
// 1.准备Request SearchRequest request = new SearchRequest(“hotel”); // 2.准备DSL // 2.1.query request.source().query(QueryBuilders.matchAllQuery()); // 2.2.排序 sort request.source().sort(“price”, SortOrder.ASC); // 2.3.分页 from、size request.source().from((page - 1) * size).size(5); // 3.发送请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.解析响应 handleResponse(response);
} ```
