我是靠谱客的博主 感动大叔,最近开发中收集的这篇文章主要介绍Elasticsearch搜索操作,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

示例数据

# 创建mapping
PUT /hotel
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"city": {
"type": "keyword"
},
"price": {
"type": "double"
},
"create_time": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"amenities": {
"type": "text"
},
"full_room": {
"type": "boolean"
},
"location": {
"type": "geo_point"
},
"praise": {
"type": "integer"
}
}
}
}
# 导入数据
POST /_bulk
{"index": {"_index": "hotel","_id":"001"}}
{"title": "文雅酒店", "city": "青岛", "price": 556.00, "create_time": "2020-04-18 12:00:00", "amenities": "浴池,普通停车场/充电停车场", "full_room": false, "location": {"lat": 36.083078, "lon": 120.37566},"praise": 10}
{"index": {"_index": "hotel","_id":"002"}}
{"title": "金都嘉怡假日酒店", "city": "北京", "price": 337.00, "create_time": "2021-03-15 20:00:00", "amenities": "wifi,充电停车场/可升降停车场", "full_room": false, "location": {"lat": 39.915153, "lon": 116.4030},"praise": 60}
{"index": {"_index": "hotel","_id":"003"}}
{"title": "金都欣欣酒店", "city": "天津", "price": 200.00, "create_time": "2021-05-09 16:00:00", "amenities": "提供假日part,免费早餐,可充电停车场", "full_room": true, "location": {"lat": 39.186555, "lon": 117.162007},"praise": 30}
{"index": {"_index": "hotel","_id":"004"}}
{"title": "金都酒店", "city": "北京", "price": 500.00, "create_time": "2021-02-18 08:00:00", "amenities": "浴池(假日需预定),室内游泳池,普通停车场", "full_room": true, "location": {"lat": 39.915343, "lon": 116.4239},"praise": 20}
{"index": {"_index": "hotel","_id":"005"}}
{"title": "文雅精选酒店", "city": "北京", "price": 800.00, "create_time": "2021-01-01 08:00:00", "amenities": "浴池(假日需预定),wifi,普通停车场", "full_room": true, "location": {"lat": 39.918229, "lon": 116.422011},"praise": 20}
{"index": {"_index": "hotel","_id":"006"}}
{"title": "完美商务酒店", "city": "东莞", "price": 190.00, "create_time": "2022-04-15 17:24:00", "amenities": "无早餐,wifi,普通停车场", "full_room": false, "location": {"lat": 23.014747, "lon": 113.770511},"praise": 80}

搜索辅助功能

指定返回的字段

_source子句可以设定返回结果的字段。

# 示例
GET /${index_name}/_search
{
"_source": ["${field}","${field}"]
# 仅返回指定字段
}

结果计数

_countAPI可以对返回的数据进行数量统计。

# 返回整个索引的文档数
GET /${index_name}/_count
# 返回过滤后的文档数
GET /${index_name}/_count
{
"query": {
"term": {
"${field}": {
"value": "${value}"
}
}
}
}

结果分页

在默认情况下,ES返回前10个搜索匹配的文档。可以通过设置from和size来定义搜索位置和每页显示的文档数量,from表示查询结果的起始下标,默认值为0,size表示从起始下标开始返回的文档个数,默认值为10。

分页的缺点:当用户查询第n页的时候,实际上es是把前n页的数据全部找出来,再去除前n-1页最后得到需要的数据返回,查最后一页就相当于全扫描。

# 返回20个结果
GET /${index_name}/_search
{
"from": 0,
"size": 20
}

在默认情况下,用户最多可以取得10000个文档,超过这个值会报错。可以修改max_result_window的值来调整最大限制。


PUT /${index_name}/_settings
{
"index": {
"max_result_window": 20000
# 设置最大限制为20000
}
}

滚动查询

scroll适合那种需要一次性或分批拉出大量数据做离线处理、迁移等。

# 语法
GET /${index_name}/_search?scroll=${time}
# time指的是数据保留时间,最大不超过1d,也就是24h
{
"size": ${num}
}
# 示例
GET /hotel12/_search?scroll=1m
# 查询10条数据,保留1分钟
{
"size": 10
}
# 上述命令会返回一个scroll_id,用scroll_id继续查询即可获取后续数据,无需指定索引,因为scroll_id是唯一的
# 重复请求以下api,最后会将全部数据取出
GET /_search/scroll
{
"scroll":"1m",
"scroll_id":"DnF1ZXJ5VGhlbkZldGNoBAAAAAAABPP1FmRFSU9NM1VNU2JxNG9UUlNnSmpXMVEAAAAAAL7OTxYxT0dJOVJVMVFxU2I0N2xCR2IyVzJnAAAAAAC-j70WVVlOZkxQRzJRLXlMRlVMbEQtalBfUQAAAAAAyWm-Fk9HdGx1b3VsUXRLZHV4c1E1OExja0E="
}

性能分析

ES提供了profile功能,该功能详细地列出了搜索时每一个步骤的耗时,可以帮助用户对DSL的性能进行剖析。

# 开启profile功能
GET /${index_name}/_search
{
"profile": true,
"query": {
"match": {
"${field}": "${value}"
}
}
}

评分分析

如果用户不指定按照某个字段进行升序或者降序排列,那么ES会使用打分算法计算的分数对文档进行排序。

ES提供了explain功能来帮助使用者查看搜索时的匹配详情。

# explain使用示例
GET /${index_name}/_explain/${_id}
{
"query": {
"match": {
"${field}": "${value}"
}
}
}

搜索匹配功能

查询所有文档

使用match_all查询文档时,ES不对文档进行打分计算,默认情况下给每个文档赋予1.0的得分。用户可以通过boost参数设定该分值。

# match_all默认也只会返回10条数据
GET /${index_name}/_search
{
"query": {
"match_all": {
"boost": ${num}
# 设置文档的分值
}
}
}

关键字别查询

term查询

term查询是结构化精准查询的主要查询方式,用于查询待查字段和查询值是否完全匹配。

# 语法
GET /${index_name}/_search
{
"query": {
"term": {
"${field}": {
"value": "${value}"
}
}
}
}

terms查询

terms查询是term查询的扩展形式,用于查询一个或多个值与待查字段是否完全匹配。

GET /${index_name}/_search
{
"query": {
"terms": {
"${field}": [
# 指定查询字段
"${value1}",
# 指定查询值,多个值之间用逗号分隔
"${value2}",
"${value3}",
...
]
}
}
}

range查询

range查询用于范围查询,一般是对数值型和日期型数据的查询。

范围比较符:

  • gt:大于
  • lt:小于
  • gte:大于或等于
  • lte:小于或等于
# 语法
GET /${index_name}/_search
{
"query": {
"range": {
"${field}": {
"${范围比较符}": "${value}"
}
}
}
}
# 示例:酒店价格在300-500之间
GET /hotel/_search
{
"query": {
"range": {
"price": {
"gte": "300",
"lte": "500"
}
}
}
}

注意,使用range查询时,查询值必须符合该字段在mappings中设置的规范。意思是不能拿字符串去搜数字类型的范围,会报错。

exists查询

使用exists搜索可以找到某个字段不为空的文档。

字段不为空的条件有:

  • 值存在且不是null
  • 值不是空数组
  • 值是数组,但不是[null]

字段为空的条件有:

  • 值是null
  • 值是[](空数组)
  • 值是[null],元素为null的数组
GET /${index_name}/_search
{
"query": {
"exists": {
"field": "${field}"
}
}
}

布尔查询

must查询

当查询中包含must查询时,表示当前查询为逻辑查询中的“与”查询,被命中的文档必须匹配该查询中的多个子查询结果。

# 语法
GET /${index_name}/_search
{
"query": {
"bool": {
"must": [
# 可以包含多个[关键字级别查询](https://www.wolai.com/oY96bxtB5oQV9ZvaZfb9Eg#9v5dJHAJNQhHjef65M5wWa)和[布尔查询](https://www.wolai.com/oY96bxtB5oQV9ZvaZfb9Eg#pM18FZBFcZkW4wrb7ZVJJH)
{
# term查询
},
{
# range查询或exists查询
}
]
}
}
}
# 示例:查询北京价格在350-500之间的酒店
GET /hotel/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"city": {
"value": "北京"
}
}
},
{
"range": {
"price": {
"gte": 350,
"lte": 500
}
}
}
]
}
}
}

should查询

当查询中包含should查询时,表示当前查询为逻辑查询中的“或”查询。被命中的文档可以匹配该查询中的一个或多个子查询结果。

# 语法
GET /${index_name}/_search
{
"query": {
"bool": {
"should": [
# 可以包含多个[term级别查询](https://www.wolai.com/oY96bxtB5oQV9ZvaZfb9Eg#9v5dJHAJNQhHjef65M5wWa)和布尔查询
{
# term查询
},
{
# range查询或exists查询
}
]
}
}
}
# 示例:查询北京或者天津的酒店
GET /hotel/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"city": {
"value": "北京"
}
}
},
{
"term": {
"city": {
"value": "天津"
}
}
}
]
}
}
}

must_not查询

当查询中包含must_not查询时,表示当前查询为逻辑查询中的“非”查询,被命中的文档必须不匹配该查询中的多个子查询结果。

# 语法
GET /${index_name}/_search
{
"query": {
"bool": {
"must_not": [
# 可以包含多个term级别查询和布尔查询
{
# term查询
},
{
# range查询或exists查询
}
]
}
}
}
# 示例:查询不是北京或者天津的酒店
GET /hotel/_search
{
"query": {
"bool": {
"must_not": [
{
"term": {
"city": {
"value": "北京"
}
}
},
{
"term": {
"city": {
"value": "天津"
}
}
}
]
}
}
}

filter查询

filter查询即过滤查询,排除不匹配的文档。

区别:

  • 其他布尔查询关注的是查询条件和文档的匹配程度,并按照匹配程度进行打分
  • 而filter查询关注的是查询条件和文档是否匹配,不打分,但是会对部分匹配结果进行缓存。
# 语法
GET /${index_name}/_search
{
"query": {
"bool": {
"filter": [
# 可以包含多个term级别查询和布尔查询
{
# term查询
},
{
# range查询或exists查询
}
]
}
}
}
# 示例:查询北京不满房的酒店
GET /hotel/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"city": {
"value": "北京"
}
}
},
{
"term": {
"full_room": false
}
}
]
}
}
}

Constant Score查询

Constant Score查询可以过滤出某个文本字段是否包含某个词,但是会忽略TF(Term Frequency,检索词频率),也就是会忽略搜索关键字在文档中的次数。

# 语法
GET /${index_name}/_search
{
"query": {
"constant_score": {
"filter": {
# 可以加各种搜索方式,如term、match、bool等
}
}
}
}
# 示例:查询amenities字段包含关键词“停车场”的酒店
GET /hotel/_search
{
"_source": ["amenities"],
"query": {
"constant_score": {
"filter": {
"match": {
"amenities": "停车场"
}
}
}
}
}
# 输出结果中,无论“停车场”出现几次,分数都是1,boost可以修改分数

Function Score查询

Function Score查询通过函数来控制文档的相关度,从而影响排序结果。

# 语法
GET /${index_name}/_search
{
"query": {
"function_score": {
"query": {},
"functions": [
{}
]
}
}
}
# 示例
GET /hotel/_search
{
"_source": ["title","city"],
"query": {
"function_score": {
"query": {
# 查询语句为term查询
"term": {
"city": {
"value": "北京"
}
}
},
"functions": [
# 使用随机分数函数
{
"random_score": {}
}
],
"score_mode": "sum"
# 最终分数设置为各个函数结果的总和
}
}
}

全文搜索

全文搜索首先对查询词进行分析,然后根据查询词的分词结果构建查询。

match查询

match查询只要分词中的一个或者多个在文档中存在即可。

# 语法
GET /${index_name}/_search
{
"query": {
"match": {
"${field}": "${value}"
}
}
}
# 示例:默认分词器会拆分成“金”“都”“酒”“店”,因此,只要文档中包含这4个字中的任何一个字,都会被搜索到
GET /hotel/_search
{
"_source": ["title"],
"query": {
"match": {
"title": "金都酒店"
}
}
}

multi_match查询

multi_match查询可以在多个字段中查询关键词。

# 语法
GET /${index_name}/_search
{
"query": {
"multi_match": {
"query": "${value}",
"fields": [
"${field}",
...
]
}
}
}
# 示例
GET /hotel/_search
{
"_source": ["title","amenities"],
"query": {
"multi_match": {
"query": "假日",
"fields": [
"title",
"amenities"
]
}
}
}

match_phrase查询

match_phrase用于搜索确切的短语或邻近的词语。

# 语法
GET /${index_name}/_search
{
"query": {
"match_phrase": {
"${field}": "${value}"
}
}
}
# 示例
GET /hotel/_search
{
"query": {
"match_phrase": {
"title": "文雅酒店"
}
}
}
# 只会在示例数据中匹配”文雅酒店“,不会匹配”文雅精选酒店“

基于地理位置查询

对于geo_point字段类型的查询方式有3种,分别为geo_distance查询、geo_bounding_box查询和geo_polygon

geo_distance查询

geo_distance查询方式需要用户指定一个坐标点,在指定距离该点的范围后,ES即可查询到相应的文档。

GET /hotel/_search
{
"_source": ["title","city","location"],
"query": {
"geo_distance": {
"distance": "5km",
# 指定范围为5km
"location": {
# 设置指定坐标点的纬度、精度
"lat": "39.915143",
"lon": "116.4039"
}
}
}
}

搜索建议

搜索建议:即在用户输入搜索关键词的过程中系统进行自动补全。

当字段的类型定义为completion时,才可以使用Completion Suggester提供的搜索建议功能。

GET /hotel_sug/_search
{
"suggest": {
"hotel_zh_sug": {
# 定义搜索建议的名称
"prefix": "如家",
# 设置搜索建议的前缀
"completion": {
# 设置搜索建议对应的字段
"field": "query_word"
}
}
}
}

排序功能

在默认情况下,ES对搜索结果是按照相关性降序排序的。

ES提供了sort子句可以对数据进行排序。使用sort子句一般是按照字段信息进行排序,不受相关性影响,而且打分步骤需要耗费一定的硬件资源和时间,因此默认情况下,不对文档进行打分。

按普通字段值排序

sort默认是升序,即asc,可通过order字段设置为降序,即desc。

# 语法
GET /${index_name}/_search
{
"sort": [
{
"${field}": {
"order": "desc"
# 设置为降序排列
}
}
]
}
# 示例
GET /hotel/_search
{
"_source": ["title","price"],
"query": {
"match": {
"title": "金都"
}
},
"sort": [
# sort是个数组,可以按照多个字段进行排序
{
"price": {
"order": "desc"
}
}
]
}

按地理距离排序

GET /hotel/_search
{
"_source": ["title","city","location"],
"query": {
"geo_distance": {
"distance": "5km",
# 查询的地理范围
"location": {
# 设置的中心点坐标
"lat": "39.915143",
"lon": "116.4039"
}
}
},
"sort": [
{
"_geo_distance": {
"location": {
# 设置排序的中心点坐标
"lat": "39.915143",
"lon": "116.4039"
},
"order": "asc",
# 距离由近到远
"unit": "km",
# 排序所使用的距离单位
"distance_type": "plane"
# 排序所使用的距离算法,默认算法是arc(精准但是耗时长),plane则相反
}
}
]
}

最后

以上就是感动大叔为你收集整理的Elasticsearch搜索操作的全部内容,希望文章能够帮你解决Elasticsearch搜索操作所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部