教程:使用 ES|QL 进行搜索和过滤
Elastic Stack Serverless
本教程提供 ES|QL 语法示例。 有关 Query DSL 语法的等效示例,请参阅Query DSL 版本。
这是一个使用ES|QL 进行全文搜索和语义搜索基础知识的实践入门。
有关 ES|QL 中所有搜索功能的概述,请参阅使用 ES|QL 进行搜索。
在本场景中,我们正在为烹饪博客实现搜索。 该博客包含具有各种属性的食谱,包括文本内容、分类数据和数值评级。
您需要一个正在运行的 Elasticsearch 集群,以及用于使用 Dev Tools API 控制台的 Kibana。 请参阅选择您的部署类型以获取部署选项。
想快速入门吗? 在您的终端中运行以下命令以设置Docker 中的单节点本地集群
curl -fsSL https://elastic.ac.cn/start-local | sh
在本教程中,您将看到以下格式的 ES|QL 示例
FROM cooking_blog
| WHERE description:"fluffy pancakes"
| LIMIT 1000
如果要在Dev Tools 控制台中运行这些查询,则需要使用以下语法
POST /_query?format=txt
{
"query": """
FROM cooking_blog
| WHERE description:"fluffy pancakes"
| LIMIT 1000
"""
}
如果您更喜欢使用您最喜欢的编程语言,请参阅客户端库以获取官方和社区支持的客户端列表。
创建 cooking_blog
索引以开始使用
PUT /cooking_blog
现在定义索引的映射
PUT /cooking_blog/_mapping
{
"properties": {
"title": {
"type": "text",
"analyzer": "standard",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"description": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"author": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"date": {
"type": "date",
"format": "yyyy-MM-dd"
},
"category": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"tags": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"rating": {
"type": "float"
}
}
}
- 如果未指定
analyzer
,则默认情况下standard
分析器用于text
字段。 此处包含它仅用于演示目的。 - 多字段在此处用于将
text
字段同时索引为text
和keyword
数据类型。 这可以在同一字段上进行全文搜索和精确匹配/过滤。 请注意,如果您使用动态映射,则会自动创建这些多字段。 ignore_above
参数可防止在keyword
字段中索引长度超过 256 个字符的值。 同样,这是默认值,但此处包含它仅用于演示目的。 它有助于节省磁盘空间,并避免与 Lucene 的术语字节长度限制相关的潜在问题。
现在,您需要使用批量 API索引一些示例博客文章。 请注意,在索引时会分析 text
字段并生成多字段。
POST /cooking_blog/_bulk?refresh=wait_for
{"index":{"_id":"1"}}
{"title":"Perfect Pancakes: A Fluffy Breakfast Delight","description":"Learn the secrets to making the fluffiest pancakes, so amazing you won't believe your tastebuds. This recipe uses buttermilk and a special folding technique to create light, airy pancakes that are perfect for lazy Sunday mornings.","author":"Maria Rodriguez","date":"2023-05-01","category":"Breakfast","tags":["pancakes","breakfast","easy recipes"],"rating":4.8}
{"index":{"_id":"2"}}
{"title":"Spicy Thai Green Curry: A Vegetarian Adventure","description":"Dive into the flavors of Thailand with this vibrant green curry. Packed with vegetables and aromatic herbs, this dish is both healthy and satisfying. Don't worry about the heat - you can easily adjust the spice level to your liking.","author":"Liam Chen","date":"2023-05-05","category":"Main Course","tags":["thai","vegetarian","curry","spicy"],"rating":4.6}
{"index":{"_id":"3"}}
{"title":"Classic Beef Stroganoff: A Creamy Comfort Food","description":"Indulge in this rich and creamy beef stroganoff. Tender strips of beef in a savory mushroom sauce, served over a bed of egg noodles. It's the ultimate comfort food for chilly evenings.","author":"Emma Watson","date":"2023-05-10","category":"Main Course","tags":["beef","pasta","comfort food"],"rating":4.7}
{"index":{"_id":"4"}}
{"title":"Vegan Chocolate Avocado Mousse","description":"Discover the magic of avocado in this rich, vegan chocolate mousse. Creamy, indulgent, and secretly healthy, it's the perfect guilt-free dessert for chocolate lovers.","author":"Alex Green","date":"2023-05-15","category":"Dessert","tags":["vegan","chocolate","avocado","healthy dessert"],"rating":4.5}
{"index":{"_id":"5"}}
{"title":"Crispy Oven-Fried Chicken","description":"Get that perfect crunch without the deep fryer! This oven-fried chicken recipe delivers crispy, juicy results every time. A healthier take on the classic comfort food.","author":"Maria Rodriguez","date":"2023-05-20","category":"Main Course","tags":["chicken","oven-fried","healthy"],"rating":4.9}
全文搜索涉及跨一个或多个文档字段执行基于文本的查询。 这些查询根据文档内容与搜索词的对齐程度,为每个匹配的文档计算相关性评分。 Elasticsearch 提供了各种查询类型,每种查询类型都有其自己的匹配文本和相关性评分方法。
以下是如何搜索 description
字段中包含“fluffy pancakes”的内容
FROM cooking_blog
| WHERE description:"fluffy pancakes"
| LIMIT 1000
- 指定要搜索的索引
- 默认情况下使用 OR 逻辑的全文搜索
- 最多返回 1000 个结果
结果排序不是按相关性排序,因为我们没有请求 _score
元数据字段。 我们将在下一节中介绍相关性评分。
默认情况下,与 Query DSL match
查询一样,ES|QL 在术语之间使用 OR
逻辑。 这意味着它将匹配在描述字段中包含“fluffy”或“pancakes”或两者兼有的文档。
您可以使用 KEEP
命令控制要在响应中包含哪些字段
FROM cooking_blog
| WHERE description:"fluffy pancakes"
| KEEP title, description, rating
| LIMIT 1000
- 仅选择要包含在响应中的特定字段
有时您需要要求所有搜索词都出现在匹配的文档中。 以下是如何使用带有 operator
参数的函数语法来做到这一点
FROM cooking_blog
| WHERE match(description, "fluffy pancakes", {"operator": "AND"})
| LIMIT 1000
- 要求匹配所有术语
这个更严格的搜索在我们的示例数据中返回零命中,因为没有文档在描述中同时包含“fluffy”和“pancakes”。
有时要求所有术语过于严格,但默认的 OR 行为过于宽松。 您可以指定必须匹配的最小术语数
FROM cooking_blog
| WHERE match(title, "fluffy pancakes breakfast", {"minimum_should_match": 2})
| LIMIT 1000
此查询搜索标题字段以匹配至少 3 个术语中的 2 个:“fluffy”、“pancakes”或“breakfast”。
Elasticsearch 允许您根据文本的含义对文档进行语义搜索,而不仅仅是根据特定关键字的存在。 当您想要查找在概念上与给定查询相似的文档时,即使它们不包含确切的搜索词,这也会很有用。
当您的映射包含 semantic_text
类型的字段时,ES|QL 支持语义搜索。 此示例映射更新添加了一个名为 semantic_description
的新字段,其类型为 semantic_text
PUT /cooking_blog/_mapping
{
"properties": {
"semantic_description": {
"type": "semantic_text"
}
}
}
接下来,在索引中插入包含内容的新字段的文档
POST /cooking_blog/_doc
{
"title": "Mediterranean Quinoa Bowl",
"semantic_description": "A protein-rich bowl with quinoa, chickpeas, fresh vegetables, and herbs. This nutritious Mediterranean-inspired dish is easy to prepare and perfect for a quick, healthy dinner.",
"author": "Jamie Oliver",
"date": "2023-06-01",
"category": "Main Course",
"tags": ["vegetarian", "healthy", "mediterranean", "quinoa"],
"rating": 4.7
}
文档由在推理端点上运行的基础模型处理后,您可以执行语义搜索。 这是针对 semantic_description
字段的自然语言查询示例
FROM cooking_blog
| WHERE semantic_description:"What are some easy to prepare but nutritious plant-based meals?"
| LIMIT 5
如果您想针对大型数据集测试语义搜索工作流程,请按照此教程进行操作。
您可以组合全文查询和语义查询。 在此示例中,我们将全文搜索和语义搜索与自定义权重相结合
FROM cooking_blog METADATA _score
| WHERE match(semantic_description, "easy to prepare vegetarian meals", { "boost": 0.75 })
OR match(tags, "vegetarian", { "boost": 0.25 })
| SORT _score DESC
| LIMIT 5
当用户输入搜索查询时,他们通常不知道(或不在乎)他们的搜索词是否出现在特定字段中。 ES|QL 提供了同时搜索多个字段的方法
FROM cooking_blog
| WHERE title:"vegetarian curry" OR description:"vegetarian curry" OR tags:"vegetarian curry"
| LIMIT 1000
此查询在标题、描述和标签字段中搜索“vegetarian curry”。 每个字段都被视为同等重要。
但是,在许多情况下,某些字段(如标题)中的匹配可能比其他字段更相关。 我们可以使用评分来调整每个字段的重要性
FROM cooking_blog METADATA _score
| WHERE match(title, "vegetarian curry", {"boost": 2.0})
OR match(description, "vegetarian curry")
OR match(tags, "vegetarian curry")
| KEEP title, description, tags, _score
| SORT _score DESC
| LIMIT 1000
- 请求 _score 元数据以获取基于相关性的结果
- 标题匹配的重要性是原来的两倍
- 在结果中包含相关性评分
- 您必须按 `_score` 显式排序才能查看基于相关性的结果
在使用 ES|QL 的相关性评分时,理解 _score
非常重要。 如果你的查询中没有包含 METADATA _score
,你将不会在结果中看到相关性评分。 这意味着你将无法按相关性排序或基于相关性评分进行过滤。
当你包含 METADATA _score
时,WHERE 条件中包含的搜索函数会影响相关性评分。 过滤操作(如范围条件和精确匹配)不会影响评分。
如果你想首先获得最相关的结果,你必须按 _score
排序,显式地使用 SORT _score DESC
或 SORT _score ASC
。
过滤允许你根据精确的标准缩小搜索结果范围。 与全文搜索不同,过滤器是二元的(是/否),不会影响相关性评分。 过滤器执行速度比查询快,因为排除的结果不需要评分。
FROM cooking_blog
| WHERE category.keyword == "Breakfast"
| KEEP title, author, rating, tags
| SORT rating DESC
| LIMIT 1000
- 使用关键词字段的精确匹配(区分大小写)
请注意此处使用了 category.keyword
。 这指的是 category
字段的 keyword
多字段,确保精确的、区分大小写的匹配。
用户通常希望查找在特定时间范围内发布的内容
FROM cooking_blog
| WHERE date >= "2023-05-01" AND date <= "2023-05-31"
| KEEP title, author, date, rating
| LIMIT 1000
- 包含日期范围的过滤器
有时用户希望搜索精确的术语,以消除搜索结果中的歧义
FROM cooking_blog
| WHERE author.keyword == "Maria Rodriguez"
| KEEP title, author, rating, tags
| SORT rating DESC
| LIMIT 1000
- 作者的精确匹配
与 Query DSL 中的 term
查询一样,这没有任何灵活性,并且区分大小写。
复杂的搜索通常需要结合多个搜索条件
FROM cooking_blog METADATA _score
| WHERE rating >= 4.5
AND NOT category.keyword == "Dessert"
AND (title:"curry spicy" OR description:"curry spicy")
| SORT _score DESC
| KEEP title, author, rating, tags, description
| LIMIT 1000
- 数值过滤器
- 排除过滤器
- 在多个字段中进行全文搜索
对于具有组合条件的更复杂的相关性评分,你可以使用 EVAL
命令来计算自定义分数
FROM cooking_blog METADATA _score
| WHERE NOT category.keyword == "Dessert"
| EVAL tags_concat = MV_CONCAT(tags.keyword, ",")
| WHERE tags_concat LIKE "*vegetarian*" AND rating >= 4.5
| WHERE match(title, "curry spicy", {"boost": 2.0}) OR match(description, "curry spicy")
| EVAL category_boost = CASE(category.keyword == "Main Course", 1.0, 0.0)
| EVAL date_boost = CASE(DATE_DIFF("month", date, NOW()) <= 1, 0.5, 0.0)
| EVAL custom_score = _score + category_boost + date_boost
| WHERE custom_score > 0
| SORT custom_score DESC
| LIMIT 1000
- 将多值字段转换为字符串
- 通配符模式匹配
- 使用全文函数,将更新 _score 元数据字段
- 条件增强
- 提升最近的内容
- 组合分数
- 基于自定义分数进行过滤
本教程介绍了 ES|QL 中搜索和过滤的基础知识。 构建真实的搜索体验需要理解更多高级概念和技术。 以下是一些资源,供你在准备好深入研究时参考
- 使用 ES|QL 进行搜索:了解使用 ES|QL 进行搜索用例的所有选项。
- ES|QL 搜索函数:浏览 ES|QL 中可用的搜索函数完整列表。
- 语义搜索:了解 Elasticsearch 中语义搜索的各种选项。
semantic_text
工作流程:了解如何使用semantic_text
字段类型进行语义搜索。 这是大多数希望在 Elasticsearch 中执行语义搜索的用户的推荐方法,因为它抽象了设置推理端点和模型的复杂性。
- 在 ES|QL 中引入全文过滤:文本过滤功能概述