elasticsearch中精确、全文、地理位置、布尔、排序、分页、聚合检索详解

导读:本篇文章讲解 elasticsearch中精确、全文、地理位置、布尔、排序、分页、聚合检索详解,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一、概述

Elasticsearch提供了基于JSONDSL来定义查询。常见的查询类型包括:

  • 查询所有:查询出所有数据,一般测试用。

    例如:match_all

  • 全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。

    例如:

    • match_query
    • multi_match_query
  • 精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。

    例如:

    • ids
    • range
    • term
  • 地理(geo)查询:根据经纬度查询。

    例如:

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

    例如:

    • bool
    • function_score

二、查询全部

查询语法基本格式:

GET /索引库名称/_search
{
  "query": {
    "查询类型": {
      "查询条件": "条件值"
    }
  }
}

查询所有的语法示例:

GET /indexName/_search
{
  "query": {
    "match_all": {
    }
  }
}

这里有两个注意点:

1.查询类型为match_all

2.{}中并没有查询条件

三、根据查询内容全文检索

常见的全文检索查询有以下两种:

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

3.1 match查询

match查询语法格式:

GET /索引库名称/_search
{
  "query": {
    "match": {
      "查询字段": "字段值"
    }
  }
}

match查询语法示例:

GET /indexName/_search
{
  "query": {
    "match": {
      "all": "猪蹄"
    }
  }
}

3.2 multi_match查询

multi_match查询语法格式:

GET /索引库名称/_search
{
  "query": {
    "multi_match": {
      "查询条件": "条件值",
      "查询字段": "字段值列表"
    }
  }
}

multi_match查询语法示例:

GET /indexName/_search
{
  "query": {
    "multi_match": {
      "query": "猪蹄",
      "fields": ["brand", "name", "business"]
    }
  }
}

这种查询其实就相当于一种全文模糊查询。

实际使用时,不推荐使用第二种方式进行全文检索,因为字段过多会降低查询效率。

可以把要查询的几个字段拷贝到一个字段当中,然后只检索那一个字段就可以了。

四、精确查询

精确查询一般是查找keyword、数值、日期、boolean等类型字段,并不会对搜索条件分词。

常见的两种精确查询有:

  • term:根据词条精确值查询
  • range:根据值的范围查询,可以是数值、日期的范围

4.1 term查询

因为精确查询的字段搜是不分词的字段,因此查询的条件也必须是不分词的词条。

查询时,用户输入的内容跟自动值完全匹配时才认为符合条件。如果用户输入的内容过多,反而搜索不到数据

term查询语法示例:

GET /indexName/_search
{
  "query": {
    "term": {
      "city": {
          "value": "广州"
      },
    }
  }
}

注意:

当搜索的内容不是词条,而是多个词语形成的短语时,反而搜索不到。

4.2 range查询

范围查询,一般应用在对数值类型做范围过滤的时候。比如做价格范围过滤或者日期范围过滤。

range查询语法示例:

GET /indexName/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 10,
        "lte": 20
      }
    }
  }
}

gte代表大于等于,gt则代表大于

lte代表小于等于,lt则代表小于

五、地理坐标查询

地理坐标查询,其实就是根据经纬度查询。

官方文档:

https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-queries.html

常见的使用场景包括:

  • 搜索我附近的酒店
  • 搜索我附近的出租车
  • 搜索我附近的人

5.1 矩形范围查询

矩形范围查询,也就是geo_bounding_box查询,查询坐标落在某个矩形范围的所有文档。

查询时,需要指定矩形的左上右下两个点的坐标,然后画出一个矩形,落在该矩形内的都是符合条件的点。

geo_bounding_box查询语法示例:

GET /indexName/_search
{
  "query": {
    "geo_bounding_box": {
      "location": {
        "top_left": {
          "lat": 31.1,
          "lon": 121.5
        },
        "bottom_right": {
          "lat": 30.9,
          "lon": 121.7
        }
      }
    }
  }
}

location是字段名称,是一种经纬度格式:31.21,121.5。如果location在矩形范围内则满足要求。

top_left:矩形左上角点位

bottom_right:矩形右下角点位

5.2 附近查询

也叫做距离查询(geo_distance):查询到指定中心点小于某个距离值的所有文档。

就是在地图上找一个点作为圆心,以指定距离为半径,画一个圆,落在圆内的坐标都算符合条件。

geo_distance查询语法示例:

GET /indexName/_search
{
  "query": {
    "geo_distance": {
      "distance": "15km", 			// 半径
      "location": "31.21,121.5" 	// 圆心
    }
  }
}

distance是固定的,代表圆的半径

location是字段名称,代表圆心

这也是更常用的查询,一般更习惯用圆圈去搜索,而不是用矩形范围去检索。

六、布尔查询

布尔查询是一个或多个查询子句的组合,每一个子句就是一个子查询

子查询的组合方式有:

  • must:必须匹配每个子查询,类似“与”(参与算分)
  • should:选择性匹配子查询,类似“或”(参与算分)
  • must_not:必须不匹配,类似“非”(不参与算分)
  • filter:必须匹配(不参与算分)

需要注意的是,搜索时,参与打分的字段越多,查询的性能也越差。因此这种多条件查询时,建议这样做:

  • 搜索框的关键字搜索,是全文检索查询,使用must查询,参与算分
  • 其它过滤条件,采用filter查询。不参与算分

布尔查询语法示例:

GET /indexName/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"city": "广州" }}
      ],
      "should": [
        {"term": {"brand": "皇冠假日" }},
        {"term": {"brand": "华美达" }}
      ],
      "must_not": [
        { "range": { "price": { "lte": 500 } }}
      ],
      "filter": [
        { "range": {"score": { "gte": 45 } }}
      ]
    }
  }
}

七、搜索结果处理

7.1 排序

elasticsearch默认是根据相关度算分(_score)来排序,但是也支持自定义方式对搜索结果排序。

可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。

文档说明:

https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html

7.1.1 普通字段排序

keyword、数值、日期类型排序的语法基本一致。

布尔查询语法示例:

GET /indexName/_search
{
  "query": {			
    "match_all": {}			// 查询全部
  },
  "sort": [
    {
      "FIELD": "desc"  		// 排序字段、排序方式ASC、DESC
    }
  ]
}

7.1.2 地理坐标排序

GET /indexName/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance" : {
          "location": {
              "lat": 31.03,
              "lon": 121.61
          }, 					// 位置字段:文档中geo_point类型的字段名、目标坐标点
          "order" : "asc", 		// 排序方式
          "unit" : "km" 		// 排序的距离单位
      }
    }
  ]
}

7.1.3 可以获取某个位置经纬度的网站

https://lbs.amap.com/demo/jsapi-v2/example/map/click-to-get-lnglat/

只要在地图上点击想要获取坐标的位置就可以得到该位置的经纬度

7.2 .分页

elasticsearch 默认情况下只返回top10的数据。如果要查询更多数据就需要修改分页参数了。

elasticsearch中通过修改fromsize参数来控制要返回的分页结果:

  • from:从第几个文档开始
  • size:总共查询几个文档

类似于mysql中的limit ?, ?

7.2.1 基础分页

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

7.2.2 深度分页

假设需要查询990~1000的数据,可以这么写DSL语句:

GET /indexName/_search
{
  "query": {
    "match_all": {}
  },
  "from": 990, 			// 分页开始的位置990
  "size": 10, 			// 期望获取的文档总数10
  "sort": [
    {"price": "asc"}	// 升序排列
  ]
}

但是elasticsearch内部分页时,必须先查询 0~1000条,然后截取其中的990 ~ 1000的这10文档数据条。

查询前1000,如果es是单点模式,则没有任何问题。

但是elasticsearch将来一定是集群,例如集群有5个节点,要查询TOP1000的数据,并不是每个节点查询200条就可以了。

要想获取整个集群的TOP1000,必须先查询出每个节点的TOP1000,汇总结果后,重新排名,重新截取TOP1000

当查询分页深度较大时,汇总数据过多,对内存和CPU会产生非常大的压力,因此elasticsearch会禁止from+ size 超过10000的请求。

针对深度分页,ES主要提供了两种解决方案:

  • search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式。
  • scroll:原理将排序后的文档id形成快照,保存在内存。官方已经不推荐使用。

官方文档位置:

https://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html

一般来说,业务层面就会避免超出10000条的请求。

如果实在有这种需求,再按照官方文档来解决

7.3 结果高亮

百度,京东搜索时,关键字会变成红色,比较醒目,这叫搜索结果高亮显示。

搜索结果高亮显示的实现分为两步:

  • 给文档中的所有关键字都添加一个自定义标签(或者其它约定好的名称),例如<em>标签
  • <em>标签编写CSS样式

结果高亮的语法示例

GET /indexName/_search
{
  "query": {
    "match": {
      "all": "如家" 			// 查询条件,高亮一定要使用全文检索查询
    }
  },
  "highlight": {
    "fields": { 		     
      "name": {			 	  // 指定要高亮的字段的名字
        "pre_tags": "<em>",   // 用来标记高亮字段的前置标签
        "post_tags": "</em>"  // 用来标记高亮字段的后置标签
      }
    }
  }
}

注意:

  • 高亮是对关键字高亮,因此搜索条件必须带有关键字,而不能是范围这样的查询。
  • 默认情况下,高亮的字段,必须与搜索指定的字段一致,否则无法高亮
  • 如果要对非搜索字段高亮,则需要添加一个属性:required_field_match=false

这样的话返回的数据会自带高亮标签包裹,前端可以直接进行渲染

八、聚合

聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。

elasticsearch实现统计功能比数据库的sql要方便的多,而且查询速度非常快,可以实现近实时搜索效果。

8.1 聚合的种类

  • 桶(Bucket) 聚合:用来对文档做分组

    • TermAggregation:按照文档字段值分组,例如按照品牌值分组、按照国家分组
    • Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组
  • 度量(Metric) 聚合:用以计算一些值,比如:最大值、最小值、平均值等

    • Avg:求平均值
    • Max:求最大值
    • Min:求最小值
    • Stats:同时求maxminavgsum
  • 管道(pipeline) 聚合:其它聚合的结果为基础做聚合,并不对文档中的字段进行聚合

能使用聚合的字段一定是不分词的,可以是任何数据类型,但是不可以是text类型

8.2 Bucket聚合语法

8.2.1 Bucket聚合语法

GET /indexName/_search
{
  "size": 0,  				// 设置size为0,结果中不包含文档,只包含聚合结果
  "aggs": { 				// 定义聚合
    "brandAgg": { 			// 给聚合起个名字
      "terms": { 			// 聚合的类型,按照品牌值聚合,所以选择term,精确查询
        "field": "brand", 	// 参与聚合的字段
        "size": 20 			// 希望获取的聚合结果数量
      }
    }
  }
}

8.2.2 限定聚合范围

默认情况下,Bucket聚合是对索引库的所有文档做聚合,

真实场景下,用户会输入搜索条件,因此聚合必须是对搜索结果聚合。那么聚合必须添加限定条件。

我们可以限定要聚合的文档范围,只要添加query条件即可:

GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "lte": 200 // 只对200元以下的文档聚合
      }
    }
  }, 
  "size": 0, 
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20,
        "order": {
          "_count": "asc" 
        }
      }
    }
  }
}

8.3 Metric聚合语法

当要获取每个桶内minmaxavg等值的时候,可以使用Metric聚合。

GET /hotel/_search
{
  "size": 0, 
  "aggs": {
    "brandAgg": { 
      "terms": { 
        "field": "brand", 
        "size": 20,
        "order": {
           "scoreAgg.avg": "desc"	// 给聚合结果排序
        }
      },
      "aggs": { 				// 是brandAgg聚合的子聚合,也就是分组后对每组分别计算
        "score_stats": { 		// 聚合名称
          "stats": { 			// 聚合类型,这里stats可以计算min、max、avg等
            "field": "score" 	// 聚合字段,这里是score
          }
        }
      }
    }
  }
}

小结:

  • 聚合三要素
    • 聚合名称
    • 聚合类型
    • 聚合字段
  • 聚合可配置属性
    • size:指定聚合结果数量
    • order:指定聚合结果排序方式
    • field:指定聚合字段

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/116465.html

(0)
seven_的头像seven_bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!