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

news2025/4/21 8:22:34

本教程展示了 ES|QL 语法的示例。请参考 Query DSL 版本,以获得等效的 Query DSL 语法示例。

这是一个使用 ES|QL 进行全文搜索和语义搜索基础知识的实践介绍。

有关 ES|QL 中所有搜索功能的概述,请参考《使用 ES|QL 进行搜索》。

在这个场景中,我们为一个烹饪博客实现搜索功能。该博客包含各种属性的食谱,包括文本内容、分类数据和数字评分。

安装

如果你还没有安装好自己的 Elasticsearch 及 Kibana,请参考如下的文章来进行安装。你可以选择 Elastic Stack 8.x 的安装步骤来进行安装:

  • 如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch

  • Kibana:如何在 Linux,MacOS 及 Windows 上安装 Elastic 栈中的 Kibana

如果你想使用 docker 来进行一键安装,请参考文章 “使用 start-local 脚本在本地运行 Elasticsearch”。

运行 ES|QL 查询

在本教程中,你将看到以下格式的 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
  """
}

如果你更喜欢使用你最喜欢的编程语言,请参考客户端库,以获取官方和社区支持的客户端列表。

步骤 1:创建索引

创建 cooking_blog 索引以开始:

PUT /cooking_blog

现在为索引定义映射:

PUT /cooking_blog/_mapping
{
  "properties": {
    "title": {
      "type": "text",
      "analyzer": "standard", /* 1 */
      "fields": {             /* 2 */
        "keyword": {
          "type": "keyword",
          "ignore_above": 256 /* 3 */
        }
      }
    },
    "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 analyzer。这里包含它是为了演示目的。
  2. 这里使用 multi-fields 将文本字段同时索引为 text 和 keyword 数据类型。这使得在同一个字段上既能进行全文搜索,也能进行精确匹配 / 过滤。注意,如果使用动态映射,这些 multi-fields 会自动创建。
  3. ignore_above 参数会防止在 keyword 字段中索引长度超过 256 个字符的值。同样,这是默认值,这里包含它是为了演示目的。它有助于节省磁盘空间,并避免 Lucene 的 term 字节长度限制所带来的潜在问题。

提示:全文搜索依赖于文本分析。文本分析会对文本数据进行规范化和标准化处理,从而可以高效地存储到倒排索引中,并实现近实时搜索。分析会在索引时和搜索时同时进行。本教程不会详细介绍分析过程,但了解文本是如何被处理的对于创建高效的搜索查询非常重要。

步骤 2:向索引添加示例博客文章

现在你需要使用 Bulk API 索引一些示例博客文章。注意,文本字段会在索引时进行分析,并生成 multi-fields。

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}

步骤 3:执行基本的全文搜索

全文搜索涉及在一个或多个文档字段上执行基于文本的查询。这些查询会根据文档内容与搜索词的匹配程度为每个匹配的文档计算相关性评分。Elasticsearch 提供了多种查询类型,每种类型都有其自己的文本匹配方式和相关性评分机制。

ES|QL 提供两种方式来执行全文搜索:

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

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

有关函数语法可用的高级参数,请参考 match 函数参考文档。

基本全文查询

以下是在 description 字段中搜索 "fluffy pancakes" 的方法:

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

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

默认情况下,就像 Query DSL 的 match 查询一样,ES|QL 在词项之间使用 OR 逻辑。这意味着它会匹配在 description 字段中包含 "fluffy" 或 "pancakes",或两者都有的文档。

提示:你可以使用 KEEP 命令控制响应中包含哪些字段:

FROM cooking_blog
| WHERE description:"fluffy pancakes"
| KEEP title, description, rating 
| LIMIT 1000

更多有关 ES|QL 的查阅,请阅读 “Elasticsearch:ES|QL 查询展示”。

在匹配查询中要求所有词项

有时你需要确保所有搜索词都出现在匹配的文档中。以下是使用函数语法和 operator 参数实现这一点的方法:

FROM cooking_blog
| WHERE match(description, "fluffy pancakes", {"operator": "AND"}) 
| LIMIT 1000
POST _query?format=csv
{
  "query": """
    FROM cooking_blog
    | WHERE match(description, "fluffy pancakes", {"operator": "AND"}) 
    | LIMIT 1000
  """
}

由于没有文档在 description 中同时包含 "fluffy" 和 "pancakes",因此这个更严格的搜索在我们的示例数据中返回零条结果。

指定匹配的最小词项数

有时,要求所有词项匹配过于严格,而默认的 OR 行为又过于宽松。你可以指定必须匹配的最小词项数:

FROM cooking_blog
| WHERE match(title, "fluffy pancakes breakfast", {"minimum_should_match": 2})
| LIMIT 1000

此查询搜索 title 字段,要求至少匹配 3 个词项中的 2 个:"fluffy"、"pancakes" 或 "breakfast"。

步骤 4:语义搜索和混合搜索

索引语义内容

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
}

注意:在上面,我们并没有指名是使用什么方法进行的向量化。在默认的情况下,它使用的是 ELSER 模型。你需要启动 ELSER。详细的部署,请参考文章 “Elasticsearch:部署 ELSER - Elastic Learned Sparse EncoderR”。

执行语义搜索

一旦文档被底层模型处理并运行在推理端点上,你就可以执行语义搜索。以下是针对 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

步骤 5:一次搜索多个字段

当用户输入搜索查询时,他们通常不知道(或不关心)他们的搜索词是否出现在特定字段中。ES|QL 提供了同时在多个字段中进行搜索的方法:

FROM cooking_blog
| WHERE title:"vegetarian curry" OR description:"vegetarian curry" OR tags:"vegetarian curry"
| LIMIT 1000

这个查询在 title、description 和 tags 字段中搜索 "vegetarian curry"。每个字段的重要性相同。

然而,在许多情况下,某些字段(如标题)中的匹配可能比其他字段更相关。我们可以通过评分来调整每个字段的重要性:

FROM cooking_blog METADATA _score /* 1 */
| WHERE match(title, "vegetarian curry", {"boost": 2.0}) /* 2 */
    OR match(description, "vegetarian curry") 
    OR match(tags, "vegetarian curry")
| KEEP title, description, tags, _score /* 3 */
| SORT _score DESC /* 4 */
| LIMIT 1000
  1. 请求 _score 元数据以获取基于相关性的结果
  2. 标题匹配的重要性是其他字段的两倍
  3. 在结果中包含相关性评分
  4. 必须明确按 _score 排序才能查看基于相关性的结果

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

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

如果你想要最相关的结果排在前面,必须通过显式使用 SORT _score DESC 或 SORT _score ASC 来按 _score 排序。

步骤 6:过滤和查找精确匹配

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

FROM cooking_blog
| WHERE category.keyword == "Breakfast" 
| KEEP title, author, rating, tags
| SORT rating DESC
| LIMIT 1000

使用 keyword 字段进行精确匹配(区分大小写)。

注意:这里使用了 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

在 author 字段上进行精确匹配。

与 Query DSL 中的 term 查询类似,这种查询没有灵活性,并且区分大小写。

步骤 7:组合多个搜索条件

复杂的搜索通常需要组合多个搜索条件:

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, ",") /* 1 */
| WHERE tags_concat LIKE "*vegetarian*" AND rating >= 4.5 /* 2 */ 
| WHERE match(title, "curry spicy", {"boost": 2.0}) OR match(description, "curry spicy") /* 3 */
| EVAL category_boost = CASE(category.keyword == "Main Course", 1.0, 0.0) /* 4 */ 
| EVAL date_boost = CASE(DATE_DIFF("month", date, NOW()) <= 1, 0.5, 0.0) /* 5 */
| EVAL custom_score = _score + category_boost + date_boost /* 6 */
| WHERE custom_score > 0 /* 7 */
| SORT custom_score DESC
| LIMIT 1000
  1. 将多值字段转换为字符串
  2. 通配符模式匹配
  3. 使用全文本功能,将更新 _score 元数据字段
  4. 条件加权
  5. 加权最近内容
  6. 组合评分
  7. 基于自定义评分进行过滤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2339306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL表与表之间的左连接和内连接

前言: 在上个实习生做的模块之中&#xff0c;在列表接口&#xff0c;涉及到多个表的联表查询的时候总会出现多条不匹配数据的奇怪的bug&#xff0c;我在后期维护的时候发现了&#xff0c;原来是这位实习生对MySQL的左连接和内连接不能正确的区分而导致的这种的情况。 表设置 …

【AI图像创作变现】02工具推荐与差异化对比

引言 市面上的AI绘图工具层出不穷&#xff0c;但每款工具都有自己的“性格”&#xff1a;有的美学惊艳但无法微调&#xff0c;有的自由度极高却需要动手配置&#xff0c;还有的完全零门槛适合小白直接上手。本节将用统一格式拆解五类主流工具&#xff0c;帮助你根据风格、控制…

相控阵列天线:原理、优势和类型

本文要点 相控阵列天线 &#xff08;Phased array antenna&#xff09; 是一种具有电子转向功能的天线阵列&#xff0c;不需要天线进行任何物理移动&#xff0c;即可改变辐射讯号的方向和形状。 这种电子转向要归功于阵列中每个天线的辐射信号之间的相位差。 相控阵列天线的基…

【HD-RK3576-PI】Ubuntu桌面多显、旋转以及更新Logo

硬件&#xff1a;HD-RK3576-PI 软件&#xff1a;Linux6.1Ubuntu22.04 在基于HD-RK3576-PI硬件平台运行Ubuntu 22系统的开发过程中&#xff0c;屏幕方向调整是提升人机交互体验的关键环节。然而&#xff0c;由于涉及uboot引导阶段、内核启动界面、桌面环境显示全流程适配&#x…

树莓派超全系列教程文档--(36)树莓派条件过滤器设置

树莓派条件过滤器设置 条件过滤器[all] 过滤器型号过滤器[none] 过滤器[tryboot] 过滤器[EDID*] 过滤器序列号过滤器GPIO过滤器组合条件过滤器 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 条件过滤器 当将单个 SD 卡&#xff08;或卡图像&am…

jetpack之LiveData的原理解析

前言 在一通研究下&#xff0c;我打算LiveData的解析通过从使用的方法上面切入进行LiveData的工作原理分析&#x1f60b;。感觉这样子更能让大家伙理解明白&#xff0c;LiveData的实现和Lifecycle分不开&#xff0c;并且还得需要知道LiveData的使用会用到什么样的方法。所以&a…

【微知】服务器如何获取服务器的SN序列号信息?(dmidecode -t 1)

文章目录 背景命令dmidecode -t的数字代表的字段 背景 各种场景都需要获取服务器的SN&#xff08;Serial Number&#xff09;&#xff0c;比如问题定位&#xff0c;文件命名&#xff0c;该部分信息在dmi中是标准信息&#xff0c;不同服务器&#xff0c;不同os都能用相同方式获…

51c大模型~合集119

我自己的原文哦~ https://blog.51cto.com/whaosoft/13852062 #264页智能体综述 MetaGPT等20家顶尖机构、47位学者参与 近期&#xff0c;大模型智能体&#xff08;Agent&#xff09;的相关话题爆火 —— 不论是 Anthropic 抢先 MCP 范式的快速普及&#xff0c;还是 OpenAI …

Vue3 + TypeScript,关于item[key]的报错处理方法

处理方法1&#xff1a;// ts-ignore 注释忽略报错 处理方法2&#xff1a;item 设置为 any 类型

【记录】服务器用命令开启端口号

这里记录下如何在服务器上开启适用于外界访问的端口号。 方法 1 使用防火墙 1 su &#xff0c;命令 输入密码 切换到root节点 2 开启防火墙 systemctl start firewalld3 配置开放端口 firewall-cmd --zonepublic --add-port8282/tcp --permanent4 重启防火墙 firewall-cmd…

OpenCV基础01-图像文件的读取与保存

介绍: OpenCV是 Open Souce C omputer V sion Library的简称。要使用OpenCV需要安装OpenCV包&#xff0c;使用前需要导入OpenCV模块 安装 命令 pip install opencv-python 导入 模块 import cv2 1. 图像的读取 import cv2 img cv2.imread(path, flag)这里的flag 是可选参数&…

go语言优雅关机和优雅重启笔记

一、优雅关机 生活化例子 餐馆关门&#xff1a;你去餐馆吃火锅&#xff0c;刚坐下点完菜&#xff08;客户端发请求&#xff09;&#xff0c;餐馆老板突然接到通知要停电&#xff08;收到关机指令&#xff09;。老板很贴心&#xff0c;先停止接待新客人&#xff08;停止接收新请…

【算法】计数排序、桶排序、基数排序

算法系列八&#xff1a;非比较排序 一、计数排序 1.实现 1.1步骤 1.2代码 2.性质 2.1稳定性 2.1.1从前往后前始版&#xff1a; 2.1.2从后往前末始版&#xff1a; 2.2复杂度 2.2.1时间复杂度 2.2.2空间复杂度 二、桶排序 1.实现 1.1步骤 1.2代码 2.稳定性 三、…

Halcon应用:相机标定

提示&#xff1a;若没有查找的算子&#xff0c;可以评论区留言&#xff0c;会尽快更新 Halcon应用&#xff1a;相机标定 前言一、Halcon应用&#xff1f;二、应用实战1、图像理解1.1、开始标定 前言 本篇博文主要用于记录学习Halcon中算子的应用场景&#xff0c;及其使用代码和…

【C++ 程序设计】实战:C++ 实践练习题(31~40)

目录 31. 数列&#xff1a;s 1 &#xff0b; 2 &#xff0b; 3 &#xff0b; … &#xff0b; n 32. 数列&#xff1a;s 1 - 2 - 3 - … - n 33. 数列&#xff1a;s 1 &#xff0b; 2 - 3 &#xff0b; … - n 34. 数列&#xff1a;s 1 - 2 &#xff0b; 3 - … &#…

绿幕抠图直播软件-蓝松抠图插件--使用相机直播,灯光需要怎么打?

使用SONY相机进行绿幕抠图直播时&#xff0c;灯光布置是关键&#xff0c;直接影响抠图效果和直播画质。以下是详细的灯光方案和注意事项&#xff1a; 一、绿幕灯光布置核心原则 均匀照明&#xff1a;绿幕表面光线需均匀&#xff0c;避免阴影和反光&#xff08;亮度差控制在0.5…

从外网访问局域网服务器的方法

一、为什么局域网的服务器无法在外网访问&#xff1f; 服务器、电脑之间靠IP地址寻址&#xff0c;目前大部分基于IPV4进行寻址访问。但是因为IPV4的地址数量有限&#xff0c;中国分到的还比较少&#xff0c;所以非常紧缺。 一个解决方案就是在局域网来建立一个内部的网…

机器学习 Day12 集成学习简单介绍

1.集成学习概述 1.1. 什么是集成学习 集成学习是一种通过组合多个模型来提高预测性能的机器学习方法。它类似于&#xff1a; 超级个体 vs 弱者联盟 单个复杂模型(如9次多项式函数)可能能力过强但容易过拟合 组合多个简单模型(如一堆1次函数)可以增强能力而不易过拟合 集成…

交换机与路由器的主要区别:深入分析其工作原理与应用场景

在现代网络架构中&#xff0c;交换机和路由器是两种至关重要的设备。它们在网络中扮演着不同的角色&#xff0c;但很多人对它们的工作原理和功能特性并不十分清楚。本文将深入分析交换机与路由器的主要区别&#xff0c;并探讨它们的工作原理和应用场景。 一、基本定义 1. 交换…

【Oracle专栏】Oracle中的虚拟列

Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.背景 在EXP方式导出时&#xff0c;发现 出现如下提示 EXP-00107: virtual column 不支持&#xff0c;因此采用expdp方式导出。于是本文针对oracle虚拟列进行简单介绍。 2. 相…