32、Elasticsearch查询全解析:从基础到高级应用

Elasticsearch查询全解析:从基础到高级应用

在数据处理和分析的领域中,高效准确地查询数据是至关重要的。Elasticsearch作为一款强大的搜索引擎,提供了多种查询方式,能够满足不同场景下的数据检索需求。本文将详细介绍Elasticsearch中的多种查询类型,包括ids查询、terms查询、exists查询、range查询、wildcard查询、prefix查询和fuzzy查询,并给出具体的操作步骤和示例代码。

1. ids查询和terms查询

ids查询用于根据文档的ID来获取多个文档。示例代码如下:

GET movies/_search
{
  "query": {
    "ids": {
      "values": [10,4,6,8]
    }
  }
}

此查询会返回具有对应四个ID的文档。每个被索引的文档都有一个必需的 _id 字段,需要注意的是,元数据字段(如 _id )不能作为映射模式的一部分。

除了ids查询,我们还可以使用terms查询来根据文档ID获取文档,示例如下:

GET movies/_search
{
  "query": {
    "terms": {
      "_id":[10,4,6,8]
    }
  }
}

在这个查询中,我们将文档标识符数组设置在 _id 字段上作为搜索条件。

2. exists查询

在处理包含大量字段的文档时,获取所有字段会浪费带宽。exists查询可以在尝试获取字段之前检查该字段是否存在,从而避免不必要的数据传输。示例代码如下:

GET movies/_search
{
  "query": {
    "exists": {
      "field": "title"
    }
  }
}

如果字段存在,查询会返回包含该字段的文档;如果字段不存在,结果将返回一个空的 hits 数组。

exists查询还有另一个微妙的用例,即检索不包含特定字段的所有文档。例如,我们要查找未被分类为机密的文档,可以使用以下查询:

PUT top_secret_files/_doc/1
{
  "code":"Flying Bird",
  "confidential":true
}

PUT top_secret_files/_doc/2
{
  "code":"Cold Rock"
}

GET top_secret_files/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "exists": {
            "field": "confidential"
          }
        }
      ]
    }
  }
}

这个查询通过在bool查询的 must_not 子句中使用exists查询,获取不包含 confidential 字段的文档。

3. range查询

range查询用于获取某个字段在指定范围内的文档。查询接受字段的下限和上限。例如,要获取评分在9.0到9.5之间的所有电影,可以使用以下查询:

GET movies/_search
{
  "query": {
    "range": {
      "rating": {
        "gte": 9.0,
        "lte": 9.5
      }
    }
  }
}

range查询中可以使用的操作符如下表所示:
| 操作符 | 含义 |
| ---- | ---- |
| gt | 大于 |
| gte | 大于或等于 |
| lt | 小于 |
| lte | 小于或等于 |

我们还可以使用range查询来搜索特定日期范围内的数据。例如,要获取1970年之后发布的所有电影,并按发布日期升序排序,可以使用以下查询:

GET movies/_search
{
  "query": {
    "range": {
      "release_date": {
        "gte": "01-01-1970"
      }
    }
  },
  "sort": [
    {
      "release_date": {
        "order": "asc"
      }
    }
  ]
}
4. range查询中的日期数学

Elasticsearch支持在查询中使用复杂的日期数学。例如,要获取特定日期(如2022年1月1日)两天后发布的电影,可以使用以下表达式:

01-01-2022||+2d

其中, 01-01-2022 是锚定日期, || 表示对锚定日期进行操作, +2d 表示加上两天。

如果要获取几天前发布的电影,可以使用当前日期作为锚定日期,并减去相应的天数。示例代码如下:

GET movies/_search
{
  "query": {
    "range": {
      "release_date": {
        "lte": "01-03-2022||-2d"
      }
    }
  }
}

Elasticsearch还允许使用 now 关键字来表示当前日期。例如,要获取去年发布的所有电影,可以使用以下查询:

GET movies/_search
{
  "query": {
    "range": {
      "release_date": {
        "lte": "now-1y"
      }
    }
  }
}

Elasticsearch有一个字母字典,用于表示不同的时间单位,如 y 表示年, M 表示月, w 表示周, d 表示天, h 表示小时, m 表示分钟, s 表示秒等。

5. wildcard查询

wildcard查询允许我们搜索包含缺失字符、后缀或前缀的单词。查询中可以使用星号( * )或问号( ? )作为通配符。具体含义如下表所示:
| 字符 | 描述 |
| ---- | ---- |
| *(星号) | 用于搜索零个或多个字符 |
| ?(问号) | 用于搜索单个字符 |

例如,要搜索标题以 god 开头的所有电影,可以使用以下查询:

GET movies/_search
{
  "query": {
    "wildcard": {
      "title": {
        "value": "god*"
      }
    }
  }
}

这个查询会返回所有标题以 god 开头的电影,如《教父》《教父2》和《上帝之城》等。

需要注意的是,当在文本字段上运行wildcard查询时,由于术语级查询不会进行分析,我们需要使用小写的搜索词。如果要使用关键字字段,可以将 title 改为 title.original ,并使用相应的搜索值。

我们还可以在单词中任意位置使用通配符来调整查询。例如,查询 g*d 会返回《黄金三镖客》和《上帝之城》这两部电影。如果要查看查询结果中匹配的字段,可以使用高亮显示功能,示例代码如下:

GET movies/_search
{
  "_source": false,
  "query": {
    "wildcard": {
      "title": {
        "value": "g*d"
      }
    }
  },
  "highlight": {
    "fields": {
      "title": {}
    }
  }
}
6. 昂贵查询及处理方法

有些查询由于其实现方式的原因,运行成本较高,如wildcard查询、range查询、prefix查询、fuzzy查询、regex查询和join查询等。偶尔使用这些查询可能不会影响服务器性能,但过度使用可能会导致集群不稳定,影响用户体验。

Elasticsearch允许我们在集群上执行这些昂贵的查询,但我们也可以通过设置 allow_expensive_queries 属性为 false 来禁止执行这些查询,示例代码如下:

PUT _cluster/settings
{
  "transient": {
    "search.allow_expensive_queries": "false"
  }
}

如果将 allow_expensive_queries 设置为 false ,尝试执行这些昂贵查询时会收到错误提示。

7. prefix查询

prefix查询用于根据单词的前缀来查询记录。例如,要查询演员姓名以 Mar 开头的所有电影,可以使用以下查询:

GET movies/_search
{
  "query": {
    "prefix": {
      "actors.original": {
        "value": "Mar"
      }
    }
  }
}

这个查询会返回包含演员马龙·白兰度、马克·哈米尔和马丁·巴尔萨姆的三部电影。

prefix查询也可以简化使用,示例代码如下:

GET movies/_search
{
  "query": {
    "prefix": {
      "actors.original":  "Leo"
    }
  }
}

为了突出显示查询结果中匹配的字段,可以在查询中添加高亮显示功能,示例如下:

GET movies/_search
{
  "_source": false,
  "query": {
    "prefix": {
      "actors.original": {
        "value": "Mar"
      }
    }
  },
  "highlight": {
    "fields": {
      "actors.original": {}
    }
  }
}
8. 加速prefix查询

由于prefix查询需要根据前缀来推导结果,运行速度较慢。为了加速prefix查询,可以在字段上使用 index_prefixes 参数。具体操作步骤如下:
1. 在开发映射模式时,在字段上设置 index_prefixes 参数。例如,创建一个新的索引 boxoffice_hit_movies ,并在 title 字段上设置 index_prefixes 参数:

PUT boxoffice_hit_movies
{
  "mappings": {
    "properties": {
      "title":{
        "type": "text",
        "index_prefixes":{}
      }
    }
  }
}
  1. 当索引新文档时,Elasticsearch会默认创建最小字符大小为2、最大字符大小为5的前缀,并存储这些值。例如:
PUT boxoffice_hit_movies/_doc/1
{
  "title":"Gladiator"
}
  1. 我们还可以自定义前缀的最小和最大字符长度。例如,创建一个新的索引 boxoffice_hit_movies_custom_prefix_sizes ,并设置 title 字段的 index_prefixes 参数:
PUT boxoffice_hit_movies_custom_prefix_sizes
{
  "mappings": {
    "properties": {
      "title":{
        "type": "text",
        "index_prefixes":{
          "min_chars":4,
          "max_chars":10
        }
      }
    }
  }
}

需要注意的是, min_chars 必须大于0, max_chars 应小于20个字符。

9. fuzzy查询

在搜索过程中,拼写错误是常见的。fuzzy查询可以通过模糊匹配来纠正拼写错误,返回相似的查询结果。模糊匹配基于Levenshtein距离算法(也称为编辑距离),即需要交换的字符数量。

例如,搜索 "rama" 电影时,如果设置模糊度为1,查询会返回所有 "drama" 类型的电影,示例代码如下:

GET movies/_search
{
  "query": {
    "fuzzy": {
      "genre": {
        "value": "rama",
        "fuzziness": 1
      }
    }
  },
  "highlight": {
    "fields": {
      "genre": {}
    }
  }
}

如果搜索词缺失两个字母,如 "ama" ,需要将模糊度设置为2才能返回结果,示例如下:

GET movies/_search
{
  "query": {
    "fuzzy": {
      "genre": {
        "value": "ama",
        "fuzziness": 2
      }
    }
  }
}

为了避免手动设置模糊度的麻烦,Elasticsearch提供了默认的 AUTO 设置。该设置会根据单词的长度自动推导编辑距离。

综上所述,Elasticsearch提供了丰富的查询方式,能够满足不同场景下的数据检索需求。通过合理使用这些查询类型,并根据实际情况进行优化,可以提高数据查询的效率和准确性。

Elasticsearch查询全解析:从基础到高级应用

在前面的内容中,我们已经介绍了 Elasticsearch 中多种常见的查询类型,包括 ids 查询、terms 查询、exists 查询、range 查询、wildcard 查询、prefix 查询和 fuzzy 查询,以及相关的操作步骤和优化方法。接下来,我们将进一步探讨这些查询在实际应用中的一些注意事项和技巧。

10. 查询的组合使用

在实际应用中,我们往往需要将多种查询组合起来,以满足更复杂的搜索需求。Elasticsearch 提供了 bool 查询来实现这一目的。bool 查询由四个子句组成: must must_not should filter ,它们的含义如下:
- must :文档必须匹配这些查询条件,类似于逻辑与(AND)。
- must_not :文档必须不匹配这些查询条件,类似于逻辑非(NOT)。
- should :文档可以匹配这些查询条件,类似于逻辑或(OR)。
- filter :对查询结果进行过滤,不影响文档的评分。

以下是一个使用 bool 查询组合多种查询的示例:

GET movies/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "rating": {
              "gte": 8.0
            }
          }
        },
        {
          "prefix": {
            "title": {
              "value": "The"
            }
          }
        }
      ],
      "must_not": [
        {
          "wildcard": {
            "genre": {
              "value": "horror*"
            }
          }
        }
      ],
      "should": [
        {
          "fuzzy": {
            "actors": {
              "value": "DiCaprio",
              "fuzziness": 1
            }
          }
        }
      ],
      "filter": [
        {
          "range": {
            "release_date": {
              "gte": "2000-01-01"
            }
          }
        }
      ]
    }
  }
}

在这个示例中,我们使用 bool 查询组合了 range 查询、prefix 查询、wildcard 查询和 fuzzy 查询。具体来说,文档必须满足评分大于等于 8.0 且标题以 The 开头的条件,不能属于恐怖类型,最好包含演员莱昂纳多·迪卡普里奥,并且发布日期在 2000 年 1 月 1 日之后。

11. 查询性能优化

为了提高 Elasticsearch 查询的性能,我们可以采取以下几种方法:
- 合理使用索引 :确保在需要查询的字段上创建了合适的索引。例如,对于经常用于范围查询的字段,可以考虑使用数值类型的索引;对于经常用于前缀查询的字段,可以使用 index_prefixes 参数。
- 避免使用昂贵的查询 :如前所述,wildcard 查询、range 查询、prefix 查询、fuzzy 查询等可能会对性能产生较大影响,应尽量避免过度使用。如果确实需要使用,可以考虑使用 allow_expensive_queries 属性进行限制。
- 使用缓存 :Elasticsearch 提供了多种缓存机制,如查询缓存、字段数据缓存等。可以根据实际情况启用这些缓存,以减少重复查询的开销。
- 优化查询语句 :尽量简化查询语句,避免使用复杂的嵌套查询。同时,合理使用 bool 查询的子句,避免不必要的计算。

12. 查询结果的处理

在获取查询结果后,我们可能需要对结果进行进一步的处理,如分页、排序、高亮显示等。以下是一些常见的处理方法:
- 分页 :使用 from size 参数来实现分页。例如,要获取第 2 页(每页 10 条记录)的结果,可以使用以下查询:

GET movies/_search
{
  "from": 10,
  "size": 10,
  "query": {
    "match_all": {}
  }
}
  • 排序 :使用 sort 参数对查询结果进行排序。例如,要按评分降序排序,可以使用以下查询:
GET movies/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "rating": {
        "order": "desc"
      }
    }
  ]
}
  • 高亮显示 :使用 highlight 参数对匹配的字段进行高亮显示。例如,要对标题字段进行高亮显示,可以使用以下查询:
GET movies/_search
{
  "query": {
    "match": {
      "title": "The Godfather"
    }
  },
  "highlight": {
    "fields": {
      "title": {}
    }
  }
}
13. 总结

Elasticsearch 作为一款强大的搜索引擎,提供了丰富的查询功能和优化手段。通过合理使用各种查询类型,如 ids 查询、terms 查询、exists 查询、range 查询、wildcard 查询、prefix 查询和 fuzzy 查询,并结合 bool 查询进行组合,我们可以满足不同场景下的复杂搜索需求。同时,通过优化查询性能和处理查询结果,我们可以提高数据检索的效率和用户体验。

在实际应用中,我们需要根据具体的业务需求和数据特点,选择合适的查询方式和优化策略。同时,要不断学习和掌握 Elasticsearch 的最新功能和技术,以应对不断变化的业务挑战。

以下是一个简单的流程图,展示了 Elasticsearch 查询的基本流程:

graph TD;
    A[定义查询条件] --> B[执行查询];
    B --> C{查询结果处理};
    C -->|分页| D[设置 from 和 size 参数];
    C -->|排序| E[设置 sort 参数];
    C -->|高亮显示| F[设置 highlight 参数];
    D --> G[返回结果];
    E --> G;
    F --> G;

希望本文能够帮助你更好地理解和使用 Elasticsearch 查询,如果你有任何问题或建议,欢迎留言讨论。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值