【ElasticSearch】深入探索 DSL 查询语法,实现对文档不同程度的检索,以及对搜索结果的排序、分页和高亮操作

文章目录

  • 前言
  • 一、Elasticsearch DSL Query 的分类
  • 二、全文检索查询
    • 2.1 `match` 查询
    • 2.2 `multi_match` 查询
  • 三、精确查询
    • 3.1 term 查询
    • 3.2 range 查询
  • 四、地理坐标查询
    • 4.1 geo_bounding_box 查询
    • 4.2 geo_distance 查询
  • 五、复合查询
    • 5.1 function score 查询
    • 5.2 boolean 查询
  • 六、对搜索结果的处理
    • 6.1 对搜索结果进行排序
    • 6.2 对搜索结果进行分页
    • 6.3 对搜索结果中的搜索关键字高亮处理

前言

Elasticsearch(简称ES)是一个强大的开源搜索和分析引擎,广泛应用于各种应用程序中,从企业级搜索引擎到日志和指标分析。其强大之处在于其灵活的数据模型和丰富的查询语言,使得用户能够轻松地进行全文检索、精确查询、地理坐标查询等操作。

本文将深入探讨Elasticsearch的DSL(Domain Specific Language)查询,分为多个部分进行介绍。首先,我们会了解Elasticsearch DSL Query的分类,然后深入研究全文检索查询、精确查询、地理坐标查询以及复合查询等不同类型的查询。

每一节都会提供详细的语法和实际示例,以便读者能够更好地理解和运用Elasticsearch中强大的查询功能。最后,我们将介绍对搜索结果进行排序、分页以及搜索关键字高亮处理等实用的处理技巧,以完善搜索体验。

让我们开始深入探讨Elasticsearch DSL Query,发现如何利用其强大的功能来提升搜索和分析的效果。

一、Elasticsearch DSL Query 的分类

Elasticsearch 提供了强大而灵活的DSL(领域特定语言)查询,用于定义对索引库中文档的不同类型查询。下面将详细介绍一些常见的 DSL查询类型:

1. 查询所有 - match_all

查询所有文档,通常用于测试或获取整个索引的文档。

{"query": {"match_all": {}}
}

2. 全文检索查询

  • match 查询

利用分词器对用户输入的内容进行分词,然后在索引中匹配分词后的词语。

{"query": {"match": {"field_name": "search_text"}}
}
  • multi_match 查询

在多个字段上执行全文检索查询。

{"query": {"multi_match": {"query": "search_text","fields": ["field1", "field2"]}}
}

3. 精确查询

  • ids 查询

根据文档ID查询文档。

{"query": {"ids": {"values": ["doc_id1", "doc_id2"]}}
}
  • term 查询

根据精确词条值查找数据,适用于 keyword、数值、日期、boolean等类型字段。

{"query": {"term": {"field_name": "exact_value"}}
}
  • range 查询

根据范围查询,适用于数值、日期等类型的范围查询。

{"query": {"range": {"field_name": {"gte": "start_value","lte": "end_value"}}}
}

4. 地理查询

  • geo_distance 查询

根据经纬度查询指定距离范围内的文档。

{"query": {"geo_distance": {"distance": "10km","location": {"lat": 40.73,"lon": -73.98}}}
}
  • geo_bounding_box 查询

根据指定的矩形框查询文档。

{"query": {"geo_bounding_box": {"location": {"top_left": {"lat": 40.73,"lon": -74.1},"bottom_right": {"lat": 40.01,"lon": -71.12}}}}
}

5. 复合查询

  • bool 查询

通过组合多个查询条件,支持must、must_not、should等逻辑。

{"query": {"bool": {"must": [{ "match": { "field1": "value1" } },{ "range": { "field2": { "gte": 10, "lte": 20 } } }],"must_not": [{ "term": { "field3": "value2" } }],"should": [{ "match": { "field4": "value3" } }]}}
}
  • function_score 查询

根据某个函数计算的分数对查询结果进行打分,用于加权不同的查询条件。

{"query": {"function_score": {"query": { "match": { "field": "search_text" } },"functions": [{"filter": { "range": { "field2": { "gte": 10, "lte": 20 } } },"weight": 2}],"score_mode": "multiply"}}
}

以上是一些常见的 Elasticsearch DSL查询类型,在使用的时候可以根据具体需求灵活组合这些查询条件来实现复杂的搜索和过滤功能。下面是针对于这些不同查询的详细说明以及查询演示。

二、全文检索查询

全文检索查询是通过对用户输入的内容进行分词,然后在索引中匹配分词后的词语,实现更灵活的文本搜索。在Elasticsearch中,常用的关键词是 matchmulti_match

2.1 match 查询

match查询会根据一个字段进行查询,适用于单一字段的全文检索。在实际应用中,可以使用 copy_to 将多个字段的值合并到一个字段,从而实现类似 multi_match 的查询效果。

例如,针对 hotel 索引库的全文检索查询:

GET /hotel/_search
{"query": {"match": {"all": "如家"}}
}

这里假设 all 字段是通过 copy_to 包含了多个字段的内容,如:“brand”、“business”、“name”。查询结果如下:

match查询结果

2.2 multi_match 查询

multi_match查询允许根据多个字段进行全文检索查询,但需要注意,参与查询的字段越多,查询效率可能越低。

例如,使用 multi_match 查询:

GET /hotel/_search
{"query": {"multi_match": {"query": "如家","fields": ["brand", "business", "name"]}}
}

在这个例子中,参与查询的字段同样是:“brand”、“business”、 “name”。查询结果如下:

multi_match查询结果

可以观察到,matchmulti_match 的查询结果是相同的。在实际应用中,选择使用哪种方式要根据具体需求和性能考虑来决定。

三、精确查询

精确查询是搜索引擎中常用的查询方式,特别适用于针对关键字、数值、日期、boolean等类型字段的精准检索。在酒店订购网站等应用中,用户通常希望根据特定的条件,如城市、星级、品牌、价格范围等,进行准确的信息检索。

下面将介绍在 Elasticsearch 中如何使用 termrange 进行精确查询。

3.1 term 查询

term 查询用于根据词条的精确值进行查询。例如,在酒店订购网站中,用户希望查找位于上海的所有酒店,可以使用以下 DSL 语句:

GET /hotel/_search
{"query": {"term": {"city": {"value": "上海"}}}
}

查询结果:

上述查询返回了所有城市为上海的酒店信息。然而,要注意的是,term 查询对查询关键字的精确匹配要求较高。如果将查询的值更改为 “上海北京”,将找不到匹配的结果:

因此,在使用 term 查询时,务必确保查询的关键字是准确的。

3.2 range 查询

range 查询用于根据值的范围进行查询,特别适用于数值型字段,比如价格范围。例如,用户希望查找价格在 100 到 200 之间的酒店,可以使用以下 DSL 语句:

GET /hotel/_search
{"query": {"range": {"price": {"gte": 100,"lte": 200}}}
}

查询结果:

在上述查询中,使用了 gte 表示大于等于某个值,而 lte 表示小于等于某个值。通过这样的查询,可以精确地获取符合价格范围的酒店信息。

总的来说,精确查询在搜索引擎中是非常常用且实用的功能,通过合理使用 termrange 查询,可以满足用户对于准确信息检索的需求。

四、地理坐标查询

地理坐标查询是 Elasticsearch 中常见的功能之一,特别适用于需要根据地理位置信息进行搜索的场景,如查询附近的酒店、出租车、或者附近的人。下面介绍两种常用的地理坐标查询方式:geo_bounding_boxgeo_distance

4.1 geo_bounding_box 查询

geo_bounding_box 查询用于查询 geo_point 值在某个矩形范围内的所有文档。以下是一个示例:

GET /indexName/_search
{"query": {"geo_bounding_box": {"FIELD": {"top_left": {"lat": 31.1,"lon": 121.5},"bottom_right": {"lat": 30.9,"lon": 121.7}}}}
}

在这个例子中,通过指定矩形的左上角和右下角的经纬度,可以查询所有位置在这个矩形范围内的文档。

搜索范围示意图,形状为矩形:

4.2 geo_distance 查询

geo_distance 查询用于查询到指定中心点距离小于某个距离值的所有文档。以下是一个示例:

GET /indexName/_search
{"query": {"geo_distance": {"distance": "15km","FIELD": "31.21,121.5"}}
}

在这个例子中,通过指定中心点的经纬度和距离值,可以查询所有距离中心点小于 15 公里的文档。

搜索范围示意图,形状为圆:

通过这两种方式,可以在地理坐标信息中实现灵活而精确的查询,满足用户在不同应用场景下的位置搜索需求。

五、复合查询

复合(compound)查询可以将其它简单查询组合起来,实现更复杂的搜索逻辑,例如:

  • function score: 算分函数查询,可以控制文档相关性算分,控制文档排名,类似于百度搜索结果中一些顶置的广告。

  • Boolean Query:布尔查询,一个或多个查询子句的组合,子查询的组合方式有:

    • must:必须匹配每个子查询,类似“与”。
    • should:选择性匹配子查询,类似“或”。
    • must_not:必须不匹配,不参与算分,类似“非”。
    • filter:必须匹配,不参与算分。

5.1 function score 查询

假设,现在文档中有一些是广告,我们希望这些广告在查询结果中是最靠前的,因此可以使用 function score 查询来修改特定文档的打分,例如,给“如家”这个品牌的酒店排名靠前一定:

为了实现这个目标,我们需要提供以下三个要素:

  1. 哪些文档需要算分加权?

    • 品牌为如家的酒店。
  2. 算分函数是什么?

    • weight
  3. 加权模式是什么?

    • 乘积。

查询 DSL 语句如下:

GET /hotel/_search
{"query": {"function_score": {"query": {"match": {"all": "上海"}},"functions": [{"filter": {"term": {"brand": "如家"}},"weight": 10}],"boost_mode": "multiply"}}
}

说明:

  • query :原始查询条件,搜索文档并根据相关性打分(query score)。
  • filter:过滤条件,符合条件的文档才会被重新算分。
  • weight:算分函数,算分函数的结果称为 function score ,将来会与 query score 运算,得到新算分。常见的算分函数有:
    • weight:给一个常量值,作为函数结果(function score)。
    • field_value_factor:用文档中的某个字段值作为函数结果。
    • random_score:随机生成一个值,作为函数结果。
    • script_score:自定义计算公式,公式结果作为函数结果。
  • boost_mode:加权模式,定义 function score 与 query score 的运算方式,包括:
    • multiply:两者相乘。默认就是这个。
    • replace:用 function score 替换 query score。
    • 其它:sumavgmaxmin

查询结果:
Function Score Query Result

5.2 boolean 查询

例如,现在有一个查询需求:搜索名字包含“如家”,价格不高于400,在坐标31.21,121.5周围 10km 范围内的酒店。

GET /hotel/_search
{"query": {"bool": {"must": [{"match": {"name": "如家"}}],"must_not": [{"range": {"price": {"gte": 400}}}],"filter": [{"geo_distance": {"distance": "10km","location": {"lat": 31.21,"lon": 121.5}}}]}}
}

说明:

  • must:必须匹配每个子查询,类似“与”。
  • must_not:必须不匹配,不参与算分,类似“非”。
  • filter:必须匹配,不参与算分。

搜索结果:

Boolean Query Result

通过这个例子,我们可以看到如何使用布尔查询来组合多个条件,实现更精确的搜索。

六、对搜索结果的处理

6.1 对搜索结果进行排序

ElasticSearch 支持对搜索结果排序,默认是根据相关度算分(_score)来排序。可以排序字段类型有:keyword 类型、数值类型、地理坐标类型、日期类型等。

示例一:对酒店数据按照用户评价降序排序,评价相同的按照价格升序排序

评价是 score 字段,价格是 price 字段,按照顺序添加两个排序规则即可。

GET /hotel/_search
{"query": {"match_all": {}},"sort": [{"score": "desc"},{"price": "asc"}]
}

示例二:实现对酒店数据按照到(121.507712,31.224612)的位置坐标的距离升序排序

获取经纬度的方式:https://lbs.amap.com/demo/jsapi-v2/example/map/click-to-get-lnglat/。

GET /hotel/_search
{"query": {"match_all": {}},"sort": [{"_geo_distance": {"location": {"lat": 31.224612,"lon": 121.507712},"order": "asc","unit": "km"}}]
}

6.2 对搜索结果进行分页

ElasticSearch 默认情况下只返回 top 10 的数据。而如果要查询更多数据就需要修改分页参数了。ElasticSearch 中通过修改 fromsize 参数来控制要返回的分页结果。

基本语法如下:

GET /hotel/_search
{"query": {"match_all": {}},"from": 990, // 分页开始的位置,默认为0"size": 10, // 期望获取的文档总数"sort": [{"price": "asc"}]
}

示例:使用 match_all 查询,然后对结果进行分页

GET /hotel/_search
{"query": {"match_all": {}},"from": 0,"size": 5
}

搜索结果,现在就只展示5条结果了:

分页结果

深度分页问题:

ES是分布式的,所以会面临深度分页问题。例如按 price 排序后,获取 from = 990,size =10 的数据:

  1. 首先在每个数据分片上都排序并查询前1000条文档。
  2. 然后将所有节点的结果聚合,在内存中重新排序选出前1000条文档。
  3. 最后从这1000条中,选取从990开始的10条文档。

如果搜索页数过深,或者结果集(from + size)越大,对内存和 CPU 的消耗也越高。因此 ES 设定结果集查询的上限是10000。

深度分页解决方案:

针对深度分页,ES提供了两种解决方案:

  1. **search after:**分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式。
  2. **scroll:**原理将排序数据形成快照,保存在内存。官方已经不推荐使用。

6.3 对搜索结果中的搜索关键字高亮处理

高亮处理,就是在搜索结果中把搜索关键字突出显示。

原理:

  • 将搜索结果中的关键字用标签标记出来。
  • 在页面中给标签添加 CSS 样式。

语法:

GET /hotel/_search
{"query": {"match": {"FIELD": "TEXT"}},"highlight": {"fields": {"FIELD": {"pre_tags": "<em>",  // 用来标记高亮字段的前置标签"post_tags": "</em>" // 用来标记高亮字段的后置标签}}}
}

示例:对搜索的品牌名称进行高亮处理

GET /hotel/_search
{"query": {"match": {"brand": "如家"}},"highlight": {"fields": {"brand": {"pre_tags": "<em>","post_tags": "</em>"}}}
}

搜索结果:

高亮搜索结果

以上便是对ElasticSearch搜索结果进行排序、分页和关键字高亮处理的一些示例和基本操作。

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

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

相关文章

WorkPlus一站式解决方案,助力企业构建统一门户系统

在信息爆炸的时代&#xff0c;企业管理面临着海量的数据和各类业务应用的复杂性。如何实现信息的井然有序、高效管理&#xff0c;成为企业发展的关键。WorkPlus作为领先的品牌&#xff0c;致力于打造统一门户系统&#xff0c;为企业提供全方位的服务和解决方案。本文将以知乎的…

常见的C/C++开源QP问题求解器

1. qpSWIFT qpSWIFT 是面向嵌入式和机器人应用的轻量级稀疏二次规划求解器。它采用带有 Mehrotra Predictor 校正步骤和 Nesterov Todd 缩放的 Primal-Dual Interioir Point 方法。 开发语言&#xff1a;C文档&#xff1a;传送门项目&#xff1a;传送门 2. OSQP OSQP&#…

广州华锐互动:候车室智能数字孪生系统实现交通信息可视化

随着科技的不断发展&#xff0c;数字化技术在各个领域得到了广泛的应用。智慧车站作为一种新型的交通服务模式&#xff0c;通过运用先进的数字化技术&#xff0c;为乘客提供了更加便捷、舒适的出行体验。 将智慧车站与数字孪生大屏结合&#xff0c;可以将实际现实世界的实体车站…

Python 中最常用的4种股票价格移动平均方法(三)

一、简介 移动平均线是各级交易者和投资者最广泛使用的技术指标之一。它们通过计算特定时期内的平均价格来帮助消除股票价格的固有波动性。移动平均线计算起来很简单,但也有更复杂的形式,旨在捕捉市场的更多细微差别。 这个由四部分组成的系列将讨论总共 4 种不同的移动平均方…

【8】c++设计模式——>单一职责原则

C面向对象三大特性之一的封装指的就是将单一事物抽象出来组合成一个类&#xff0c;所以我们在设计类的时候每个类中处理的是单一事物而不是某些事物的集合。让类的功能单一&#xff0c;不让类与具体的事物耦合。 设计模式中所谓的单一职责原则&#xff0c;就是对一个类而言&…

CountDownLatch闭锁原理解析

CountDownLatch闭锁原理解析 在Java并发编程中&#xff0c;CountDownLatch是一个常用的工具类&#xff0c;用于实现闭锁(latch)。闭锁是一种常见的同步机制&#xff0c;用于控制线程的执行流程&#xff0c;确保某些线程在执行之前满足特定的条件。CountDownLatch尤其在多线程协…

DIY一个智能音箱

十一假期里将蓝牙音箱改造成一个智能音箱, 参考了网上的实现方法, 后台的大语言模型使用的是百度的文心一言. 账号 Picovoice 唤醒词服务 https://console.picovoice.ai/ 我绑定了github账号. 访问https://picovoice.ai/&#xff0c;注册账号&#xff0c;然后进入控制台, 目前不…

java 无感hook实现(修改jdk)

背景 1 工作需要&#xff0c;需要修改一个java的程序逻辑&#xff0c;之前都是用的frida修改的&#xff0c;但是现在的工作场景&#xff0c;重视效率&#xff0c;所以frida这种重工具被pass了&#xff0c;只能重新选其他工具&#xff0c;初始的时候是想用java本身的一些修改工…

纸、纸板和纸制品 有效回收组分的测定

声明 本文是学习GB-T 42944-2023 纸、纸板和纸制品 有效回收组分的测定. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件描述了纸、纸板和纸制品中有效回收组分的测定方法。 本文件适用于各种纸、纸板和纸制品&#xff0c;也适用于铝箔…

微信小程序通过 movable-area 做一个与vuedraggable相似的上下拖动排序控件

因为只是做个小案例 我就直接代码写page页面里了 其实很简单 组件稍微改一下就好了 wxss /* 设置movable-area的宽度 */ .area{width: 100%; }/* a b c 每条元素的样式 */ movable-view {width: 100%;background-color: red;height: 40px;line-height: 40px;color: #FFFFFF;tex…

docker命令,免sudo

docker命令&#xff0c;免sudo 一、创建docker用户组 # 查看有无用户组 cat /etc/group | grep docker # 若无&#xff0c;创建 sudo groupadd docker二、添加当前用户到用户组 sudo gpasswd -a ${USER} docker三、重启docker服务 sudo service docker restart四、重启会话…

day

#include <iostream> using namespace std; class Per {//算术运算符friend const Per operator(const Per &k1,const Per &k2);friend const Per operator-(const Per &k1,const Per &k2);friend const Per operator*(const Per &k1,const Per &…

3ds Max渲染太慢?创意云“一键云渲染”提升3ds Max渲染体验

&#xfeff;在数字艺术设计领域&#xff0c;3ds Max是广泛使用的三维建模和渲染软件之一。然而&#xff0c;许多用户都面临着一个共同的问题&#xff1a;渲染速度太慢。渲染一帧画面需要耗费数小时&#xff0c;让人无法忍受。除了之前给大家介绍的几种解决方法外&#xff1a; …

uvm中transaction的response和id的解读

在公司写代码的时候发现前辈有一段这样的代码&#xff1a; ....//其他transaction uvm_create(trans);........ uvm_send(trans); tmp_id trans.get_transaction_id(); get_response(rsp,tmp_id); 如果前面有其他transaction&#xff0c;这段代码里的get_response不带id的话…

C#学习系列相关之多线程(五)----线程池ThreadPool用法

一、线程池的作用 线程池是一种多线程处理形式&#xff0c;处理过程中将任务添加到队列&#xff0c;然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认堆栈大小&#xff0c;以默认的优先级运行&#xff0c;并处于多线程单元中。如果某个线程在托管…

Vue3中reactive, onMounted, ref,toRaw,conmpted 使用方法

import { reactive, onMounted, ref,toRaw,conmpted } from vue; vue3中 reactive &#xff0c;ref &#xff0c; toRaw&#xff0c;watch&#xff0c;conmpted 用法 toRaw 返回原响应式对象 用法&#xff1a; const rowList toRaw(row) reactive:ref: ref和reactive都是V…

快讯|Tubi 有 Rabbit AI 啦

在每月一期的 Tubi 快讯中&#xff0c;你将全面及时地获取 Tubi 最新发展动态&#xff0c;欢迎星标关注【比图科技】微信公众号&#xff0c;一起成长变强&#xff01; Tubi 推出 Rabbit AI 帮助用户找到喜欢的视频内容 Tubi 于今年九月底推出了 Rabbit AI&#xff0c;这是一项…

有效回收组分含量

声明 本文是学习GB-T 42944-2023 纸、纸板和纸制品 有效回收组分的测定. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件描述了纸、纸板和纸制品中有效回收组分的测定方法。 本文件适用于各种纸、纸板和纸制品&#xff0c;也适用于铝箔…

AndroidStudio报错:Plugin with id ‘kotlin-android‘ not found.

第一步 要在自己的项目的build.gradle的buildscript中添加ext.kotlin_version 1.3.72 第二步 然后在dependencies里添加classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 大体如下&#xff1a; buildscript {ext.kotlin_version 1.3.72r…

Qt如何在视频画面上新增车道线显示

在Qt中向视频画面上新增车道线显示通常需要以下步骤&#xff1a; 1.获取视频流或帧数据&#xff1a;首先&#xff0c;您需要获取视频流或视频帧的数据。您可以使用Qt的多媒体模块或其他第三方库来捕获视频流&#xff0c;或者从视频文件中读取帧数据。这将是您要在其上绘制车道…