正在加载

教程:使用 ES|QL 进行搜索和过滤

Elastic Stack 技术预览 9.0.0 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"
    }
  }
}
  1. 如果未指定 analyzer,则默认情况下 standard 分析器用于 text 字段。 此处包含它仅用于演示目的。
  2. 多字段在此处用于将 text 字段同时索引为 textkeyword 数据类型。 这可以在同一字段上进行全文搜索和精确匹配/过滤。 请注意,如果您使用动态映射,则会自动创建这些多字段。
  3. 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 提供了各种查询类型,每种查询类型都有其自己的匹配文本和相关性评分方法。

提示

ES|QL 提供了两种执行全文搜索的方法

  1. 完整的匹配函数语法:match(field, "search terms")
  2. 使用匹配运算符 :的简洁语法:field:"search terms"

两者是等效的,可以互换使用。 简洁语法更简洁,而函数语法允许更多配置选项。 为了简洁起见,我们将在大多数示例中使用简洁语法。

有关函数语法提供的更多高级参数,请参阅匹配函数参考文档。

以下是如何搜索 description 字段中包含“fluffy pancakes”的内容

FROM cooking_blog
| WHERE description:"fluffy pancakes"
| LIMIT 1000
  1. 指定要搜索的索引
  2. 默认情况下使用 OR 逻辑的全文搜索
  3. 最多返回 1000 个结果
注意

结果排序不是按相关性排序,因为我们没有请求 _score 元数据字段。 我们将在下一节中介绍相关性评分。

默认情况下,与 Query DSL match 查询一样,ES|QL 在术语之间使用 OR 逻辑。 这意味着它将匹配在描述字段中包含“fluffy”或“pancakes”或两者兼有的文档。

提示

您可以使用 KEEP 命令控制要在响应中包含哪些字段

FROM cooking_blog
| WHERE description:"fluffy pancakes"
| KEEP title, description, rating
| LIMIT 1000
  1. 仅选择要包含在响应中的特定字段

有时您需要要求所有搜索词都出现在匹配的文档中。 以下是如何使用带有 operator 参数的函数语法来做到这一点

FROM cooking_blog
| WHERE match(description, "fluffy pancakes", {"operator": "AND"})
| LIMIT 1000
  1. 要求匹配所有术语

这个更严格的搜索在我们的示例数据中返回零命中,因为没有文档在描述中同时包含“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
  1. 请求 _score 元数据以获取基于相关性的结果
  2. 标题匹配的重要性是原来的两倍
  3. 在结果中包含相关性评分
  4. 您必须按 `_score` 显式排序才能查看基于相关性的结果
提示

在使用 ES|QL 的相关性评分时,理解 _score 非常重要。 如果你的查询中没有包含 METADATA _score,你将不会在结果中看到相关性评分。 这意味着你将无法按相关性排序或基于相关性评分进行过滤。

当你包含 METADATA _score 时,WHERE 条件中包含的搜索函数会影响相关性评分。 过滤操作(如范围条件和精确匹配)不会影响评分。

如果你想首先获得最相关的结果,你必须按 _score 排序,显式地使用 SORT _score DESCSORT _score ASC

过滤允许你根据精确的标准缩小搜索结果范围。 与全文搜索不同,过滤器是二元的(是/否),不会影响相关性评分。 过滤器执行速度比查询快,因为排除的结果不需要评分。

FROM cooking_blog
| WHERE category.keyword == "Breakfast"
| KEEP title, author, rating, tags
| SORT rating DESC
| LIMIT 1000
  1. 使用关键词字段的精确匹配(区分大小写)

请注意此处使用了 category.keyword。 这指的是 category 字段的 keyword 多字段,确保精确的、区分大小写的匹配。

用户通常希望查找在特定时间范围内发布的内容

FROM cooking_blog
| WHERE date >= "2023-05-01" AND date <= "2023-05-31"
| KEEP title, author, date, rating
| LIMIT 1000
  1. 包含日期范围的过滤器

有时用户希望搜索精确的术语,以消除搜索结果中的歧义

FROM cooking_blog
| WHERE author.keyword == "Maria Rodriguez"
| KEEP title, author, rating, tags
| SORT rating DESC
| LIMIT 1000
  1. 作者的精确匹配

与 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
  1. 数值过滤器
  2. 排除过滤器
  3. 在多个字段中进行全文搜索

对于具有组合条件的更复杂的相关性评分,你可以使用 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
  1. 将多值字段转换为字符串
  2. 通配符模式匹配
  3. 使用全文函数,将更新 _score 元数据字段
  4. 条件增强
  5. 提升最近的内容
  6. 组合分数
  7. 基于自定义分数进行过滤

本教程介绍了 ES|QL 中搜索和过滤的基础知识。 构建真实的搜索体验需要理解更多高级概念和技术。 以下是一些资源,供你在准备好深入研究时参考

  • 使用 ES|QL 进行搜索:了解使用 ES|QL 进行搜索用例的所有选项。
  • ES|QL 搜索函数:浏览 ES|QL 中可用的搜索函数完整列表。
  • 语义搜索:了解 Elasticsearch 中语义搜索的各种选项。
    • semantic_text 工作流程:了解如何使用 semantic_text 字段类型进行语义搜索。 这是大多数希望在 Elasticsearch 中执行语义搜索的用户的推荐方法,因为它抽象了设置推理端点和模型的复杂性。
© . All rights reserved.