Elasticsearch 高级查询与过滤实战指南
在 Elasticsearch 的日常开发中,Kibana 的 Dev Tools 是进行 DSL 调试的核心工具。本文将通过一系列实际案例,演示如何构建从基础到复杂的复合查询语句。
1. 初始数据准备
首先,我们在 store/products 索引中批量导入一些演示数据。这些数据涵盖了字符串、数值、日期等常见类型:
POST /store/products/_bulk
{ "index": { "_id": 1 }}
{ "title" : "ThinkPad X1 Carbon", "price" : 8999, "category": "laptop", "on_sale": "2023-01-10", "tags": "work high-end lightweight" }
{ "index": { "_id": 2 }}
{ "title" : "iPhone 14 Pro", "price" : 7999, "category": "phone", "on_sale": "2022-09-15", "tags": "apple mobile photography" }
{ "index": { "_id": 3 }}
{ "title" : "Mechanical Keyboard", "price" : 499, "category": "accessory", "on_sale": "2023-03-01", "tags": "gaming office" }
{ "index": { "_id": 4 }}
{ "title" : "Dell UltraSharp Monitor", "price" : 3500, "category": "monitor", "on_sale": "2022-12-20", "tags": "design 4k" }
{ "index": { "_id": 5 }}
{ "title" : "MacBook Pro 16", "price" : 18999, "category": "laptop", "on_sale": "2023-02-15", "tags": "apple designer workstation" }
{ "index": { "_id": 6 }}
{ "title" : "Logitech Mouse", "price" : 299, "category": "accessory", "on_sale": "2023-01-05", "tags": "wireless office" }
2. 基础查询:match_all
match_all 用于检索索引中的所有文档。但在生产环境中需谨慎使用,因为全量检索会消耗大量 CPU 和内存资源,并可能引发频繁的 GC。
GET /store/products/_search
{
"query": {
"match_all": {}
}
}
3. 全文搜索:match
match 查询会对输入的内容进行分词,然后与索引中的字段进行匹配。这是最常用的模糊搜索方式。
GET /store/products/_search
{
"query": {
"match": {
"tags": "apple"
}
}
}
4. 布尔复合查询:bool
当业务逻辑需要多个条件组合(如"且"、"或"、"非")时,必须使用 bool 查询。其核心子句包括:
- must:必须满足的条件,影响评分。
- must_not:绝对不能满足的条件。
- should:可选条件,如果满足会增加相关性得分。
案例:查询非 laptop 类别中包含 "office" 标签的产品:
GET /store/products/_search
{
"query": {
"bool": {
"must": [
{ "match": { "tags": "office" }}
],
"must_not": [
{ "match": { "category": "laptop" }}
]
}
}
}
5. 精确匹配:term 与 terms
term 主要用于匹配未经分词的精确值,如数字、日期或类型为 keyword 的字符串。terms 则允许匹配多个可选的精确值。
GET /store/products/_search
{
"query": {
"bool": {
"must": [
{ "terms": { "category.keyword": ["phone", "monitor"] }}
]
}
}
}
6. 范围过滤:range
range 用于筛选数值或日期范围。参数包括:gt(大于)、gte(大于等于)、lt(小于)、lte(小于等于)。
案例:查询价格在 3000 到 10000 之间的产品:
GET /store/products/_search
{
"query": {
"range": {
"price": {
"gte": 3000,
"lte": 10000
}
}
}
}
7. 字段存在性检查:exists
exists 查询用于返回包含指定字段非空值的文档。
GET /store/products/_search
{
"query": {
"exists": {
"field": "tags"
}
}
}
8. 查询与过滤的性能优化:filter
在 bool 查询中,filter 子句与 must 类似,但它不计算相关性评分(Score),且 Elasticsearch 会自动缓存常用的 filter 结果,性能显著高于常规查询。
案例:搜索标签包含 "apple" 且价格高于 8000 的产品,并使用 filter 优化价格筛选:
GET /store/products/_search
{
"query": {
"bool": {
"must": [
{ "match": { "tags": "apple" }}
],
"filter": [
{ "range": { "price": { "gt": 8000 }}}
]
}
}
}