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":{}
}
}
}
}
- 当索引新文档时,Elasticsearch会默认创建最小字符大小为2、最大字符大小为5的前缀,并存储这些值。例如:
PUT boxoffice_hit_movies/_doc/1
{
"title":"Gladiator"
}
-
我们还可以自定义前缀的最小和最大字符长度。例如,创建一个新的索引
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 查询,如果你有任何问题或建议,欢迎留言讨论。
超级会员免费看

被折叠的 条评论
为什么被折叠?



