Elasticsearch搜索操作

本文介绍了Elasticsearch的搜索操作,包括指定返回字段、结果计数、分页、滚动查询和性能分析。同时,详细讲解了各种查询方式,如term、terms、range、exists查询,布尔查询,全文搜索match、multi_match、match_phrase查询,以及基于地理位置的查询。此外,还涵盖了搜索建议和排序功能,如按字段值和地理距离排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

示例数据

# 创建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则相反
      }
    }
  ]
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值