1.DSL查询分类
①查询所有:match_all
②全文检索:利用分词器对用户输入的内容分词,倒排索引去匹配
match_query
multi_match_query
③精确查询:根据精确词条查找数据,查找的是keyword,数值,日期,boolean类型字段
ids,range,term
④地理geo查询:根据经纬度查询
geo_distance
geo_bounding_box
⑤复合查询:将各种条件组合起来,合并查询条件
bool
function_score

总结:查询DSL的基本语法是什么?
GET /索引库名/_search
{ "query": { "查询类型": { "FIELD": "TEXT"}}}
2.全文检索
全文检索查询,会对用户输入内容进行分词。用于搜索框搜索

①match查询:对用户输入的内容分词,然后倒排索引库查询。一个字段

查询三钻的酒店
- GET /hotel/_search
- {
- "query": {
- "match": {
- "starName": "三钻"
- }
- }
- }
②multi_match:多个字段查询。参与的字段越多,查询性能越差。

查询品牌,酒店名,商业圈有“外滩如家”
- GET /hotel/_search
- {
- "query": {
- "multi_match": {
- "query": "外滩如家",
- "fields": ["brand","name","business"]
- }
- }
- }
3.精确查询
查询的keyword,不进行分词的字段
①term:根据词条准确值查询
②range:范围查询(价格)

①term:

查询品牌是“7天酒店”
- GET /hotel/_search
- {
- "query": {
- "term": {
- "brand": {
- "value": "7天酒店"
- }
- }
- }
- }
②range:
查询200-250酒店

- GET /hotel/_search
- {
- "query": {
- "range": {
- "price": {
- "gte": 200,
- "lte": 250
- }
- }
- }
- }
总结:精确查询常见的有哪些?
4.地理查询
场景:
查询附近的酒店,附近的人,打车附近的出租车

①矩形范围内:geo_bounding_box

②以指定中心点为半径:

查询这个点15公里范围内的酒店
- GET /hotel/_search
- {
- "query": {
- "geo_distance":{
- "distance":"15km",
- "location":"31.282444,121.479385"
- }
- }
- }
5.相关性算分:竞价排名
①fuction score:算分函数查询,可以控制文档相关性算分,控制文档排名


②词条频率越高,得分越高,排名越靠前

③elasticsearch中的相关性打分算法是什么?

6.修改相关性算分:竞价排名
使用 function score query,可以修改文档的相关性算分(query score),根据新得到的算分排序。

①原始条件查询,搜索文档并根据相关性打分(query score)
②过滤条件:符合条件的文档才重新算分
③算分函数:
算分函数,算分函数的结果称为function score ,将来会与query score运算,得到新算分,常见的算分函数有:
④加权模式,定义function score与query score的运算方式,包括:
案例:搜索外滩的酒店,“如家”品牌给公司充钱了,让他的排名靠前一些。
分析:
①文档为品牌是“如家”的
②算分函数是weight
③加权模式是求和sum
- GET /hotel/_search
- {
- "query": {
- "function_score": {
- "query": {
- "match": {
- "all": "外滩"
- }
- },
- "functions": [
- {
- "filter": {
- "term": {
- "brand": "如家"
- }
- },
- "weight": 2
- }
- ],
- "boost_mode": "sum"
- }
- }
- }
7.复合查询Boolean Query
布尔查询是一个或多个查询子句的组合。子句组合方式:
must:”与”,必须匹配每个子查询
should:“或”选择性匹配子查询
must_not:必须不匹配,不参与算分,类似“非”
filter:必须匹配,不算分。
案例1:查询上海的酒店,品牌是皇冠假日或华美达。价格不低于500,评分是大于45分的


案例2:搜索名字包含“如家”,价格不高于400,在坐标31.21,121.5周围10km范围内的酒店。
- GET /hotel/_search
- {
- "query": {
- "bool": {
- "must": [
- {
- "match": {
- "name": "如家"
- }
- }
- ],
- "must_not": [
- {
- "range": {
- "price": {
- "gte": 400
- }
- }
- }
- ],
- "filter": [
- {
- "geo_distance": {
- "distance": "10km",
- "location": {
- "lat": 31.21,
- "lon": 121.5
- }
- }
- }
- ]
-
- }
- }
- }
1.排序
es支持对搜索结果排序,默认是根据相关度算分(_score)排序。可以排序的字段:keyword类型,数值类型,地理坐标类型,日期类型。
排序语法

地理坐标排序语法

案例1:对酒店数据按照用户评价降序排序,评价相同的按照价格升序排序
- GET /hotel/_search
- {
- "query": {
- "match_all": {}
- },
- "sort": [
- {
- "score":"desc"
- },
- {
- "price": "asc"
- }
- ]
- }
案例2:实现对酒店数据按照到你的位置坐标的距离升序排序
获取经纬度的方式:https://lbs.amap.com/demo/jsapi-v2/example/map/click-to-get-lnglat/
- GET /hotel/_search
- {
- "query": {
- "match_all": {}
- },
- "sort": [
- {
- "_geo_distance": {
- "location": {
- "lat": 31.220393,
- "lon": 121.544427
- },
- "order": "asc",
- "unit": "km"
- }
- }
- ]
- }
2.分页
es的搜索结果默认是top10条。
es通过修改from,size参数控制返回的分页结果

深度分页问题
ES是分布式的,所以会面临深度分页问题。例如按price排序后,获取from = 990,size =10的数据:

①首先在每个数据分片上都排序并查询前1000条文档。
②然后将所有节点的结果聚合,在内存中重新排序选出前1000条文档
③最后从这1000条中,选取从990开始的10条文档
如果搜索页数过深,或者结果集(from + size)越大,对内存和CPU的消耗也越高。因此ES设定结果集查询的上限是10000
总结
from + size:
after search:
3.高亮
搜索关键字突出显示。

原理:
①搜索关键字标记出来
②页面加css样式

案例:如家酒店高亮

1.快速入门
①请求DSL的组织

RestAPI中其中构建DSL是通过HighLevelRestClient中的resource()来实现的,其中包含了查询、排序、分页、高亮等所有功能

RestAPI中其中构建查询条件的核心部分是由一个名为QueryBuilders的工具类提供的,其中包含了各种查询方法

②解析结果response

③查询全部酒店的完整代码
- @Test
- void testMatchAll() throws IOException {
- // 1.准备查询请求,参数是索引库名
- SearchRequest request = new SearchRequest("hotel");
- // 2.组织DSL参数
- request.source().query(QueryBuilders.matchAllQuery());
- // 3.发送请求,得到响应
- SearchResponse response = client.search(request, RequestOptions.DEFAULT);
- // 4.解析结果
- SearchHits searchHits = response.getHits();
- // 4.1 获取查询的条数
- long total = searchHits.getTotalHits().value;
- // 4.2 获取查询的集合
- SearchHit[] hits = searchHits.getHits();
- // 4.3 遍历
- List
hotelDocList = new ArrayList<>(); - for (SearchHit hit : hits) {
- // 转换为Json
- String json = hit.getSourceAsString();
- // 转换为java对象
- HotelDoc hotelDoc = JSONObject.parseObject(json, HotelDoc.class);
- // 保存在集合中
- hotelDocList.add(hotelDoc);
- }
- System.out.println(hotelDocList);
- }
查询的基本步骤是:
2.构建查询条件,只要记住一个类:QueryBuilders
①全文检索查询(分词,模糊查询)
单字段:QueryBuilders.matchQuery(字段名,值)
多字段:QueryBuilders.multiMatchQuery(值, 字段1,字段2);
演示:酒店名字带有“如家“的有哪些?

request.source().query(QueryBuilders.termQuery("name","如家"));
②精确查询,不分词
精确查询常见的有term查询和range查询

③复合查询boolean query
查询品牌为如家,价格在200元内的酒店
- // 创建bool查询
- BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
- // 添加must条件
- boolQuery.must(QueryBuilders.termQuery("brand","如家"));
- // 添加filter条件
- boolQuery.filter(QueryBuilders.rangeQuery("price").lte(200));
- request.source().query(boolQuery);
3.分页和排序

演示:查询名为“如家“的酒店,查询结果进行价格降序,每页显示3条
- // 页码
- int page = 1,size=3;
- // 2.组织DSL
- // 2.1 查询
- request.source().query(QueryBuilders.termQuery("name","如家"));
- // 2.2 分页 从from序号数size个
- request.source().from((page-1)*size).size(size);
- // 2.3 价格排序
- request.source().sort("price", SortOrder.DESC);
4.高亮
根据name搜索高亮


代码
- @Test
- void testHight() throws IOException{
- // 1.请求request
- SearchRequest request = new SearchRequest("hotel");
- // 2. 组织DSL
- request.source().query(QueryBuilders.matchQuery("all","如家"));
- request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
- // 3.发送请求,得到响应
- SearchResponse response = client.search(request, RequestOptions.DEFAULT);
- // 4.分析结果
- SearchHits searchHits = response.getHits();
- // 5.解析
- SearchHit[] hitss = searchHits.getHits();
- // 6.遍历
- for (SearchHit hit : hitss) {
- // 转换为json
- String json = hit.getSourceAsString();
- // 得到对象
- HotelDoc hotelDoc = JSONObject.parseObject(json, HotelDoc.class);
- // 获取高亮结果
- Map
highlightFields = hit.getHighlightFields(); - // 根据字段获取
- HighlightField highlightField = highlightFields.get("name");
- // 获取高亮值
- String name = highlightField.getFragments()[0].string();
- // 覆盖结果
- hotelDoc.setName(name);
- System.out.println(name);
-
- }
-
- }
- @Override
- public PageResult search(RequestParams params) throws IOException {
- // 1.得到请求参数
- String key = params.getKey();
- Integer page = params.getPage();
- Integer size = params.getSize();
- String sortBy = params.getSortBy();
- String brand = params.getBrand();
- String starName = params.getStarName();
- String city = params.getCity();
- Integer minPrice = params.getMinPrice();
- Integer maxPrice = params.getMaxPrice();
- String location = params.getLocation();
-
- // 2.创建搜索请求
- SearchRequest request = new SearchRequest(HotelConstants.HOTEL_INDEX);
- // 3.编写DSL 组合查询boolQuery
- BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
- // 3.1.1 输入框关键字must
- if (key != null && !"".equals(key)) { //输入框不为空,模糊查询
- boolQuery.must(QueryBuilders.matchQuery("all", key));
- } else {//输入框为空,查询全部
- boolQuery.must(QueryBuilders.matchAllQuery());
- }
- // 3.1.2 城市--filter
- if (city != null && !"".equals(city)) {
- boolQuery.filter(QueryBuilders.termQuery("city", city));
- }
- // 3.1.3 品牌--filter
- if (brand != null && !"".equals(brand)) {
- boolQuery.filter(QueryBuilders.termQuery("brand", brand));
- }
- // 3.1.4 星级--filter
- if (starName != null && !"".equals(starName)) {
- boolQuery.filter(QueryBuilders.termQuery("starName", starName));
- }
- // 3.1.5 价格--filter
- if (minPrice != null && maxPrice != null) {
- boolQuery.filter(QueryBuilders.rangeQuery("price").gte(minPrice).lte(maxPrice));
- }
- // 3.1.6 查询条件
- // 3.1.7 =====广告推荐算分查询(查询条件,算分条件)
- FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(boolQuery,
- new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
- new FunctionScoreQueryBuilder.FilterFunctionBuilder(
- QueryBuilders.termQuery("isAD",true),// 算分条件
- ScoreFunctionBuilders.weightFactorFunction(10) // 算分比例
- )
- });
-
-
- request.source().query(functionScoreQuery);
- // 3.2 页码
- request.source().from((page - 1) * size).size(size);
- // 3.3 排序
- if (location != null && !"".equals(location)) {
- request.source().sort(SortBuilders.geoDistanceSort("location", new GeoPoint(location))
- .order(SortOrder.ASC)
- .unit(DistanceUnit.KILOMETERS));
- }
- if (!SortConstants.DEFAULT.equals(sortBy)) {
- request.source().sort(sortBy, SortOrder.DESC);
- }
-
- //4. 发送请求得到响应
- SearchResponse response = client.search(request, RequestOptions.DEFAULT);
- // 5.解析响应
- PageResult pageResult = handleResponse(response);
- return pageResult;
- }