写点什么

大数据 -176 Elasticsearch Filter DSL 全面实战:过滤查询、排序分页、高亮与批量操作

作者:武子康
  • 2025-12-07
    山东
  • 本文字数:3255 字

    阅读完需:约 11 分钟

大数据-176 Elasticsearch Filter DSL 全面实战:过滤查询、排序分页、高亮与批量操作

TL;DR

  • 场景:在日志检索、电商搜索等场景中,需要在 Elasticsearch 中组合过滤、排序、分页、高亮与批量操作。

  • 结论:Filter DSL 负责“是否匹配”、Query 负责“匹配程度”,再配合 sort/from/size/highlight/_mget/_bulk 形成一整套检索实战组合拳。

  • 产出:一篇覆盖 Filter DSL、排序分页、高亮展示与批量读写的实战笔记,可直接套用到线上检索与数据写入链路。


版本矩阵


Filter DSL

基本介绍

Filter DSL:过滤器查询语言)Filter DSL 是 Elasticsearch 提供的一种用于构建过滤查询的方式。与 query 语句不同,过滤器不会计算与文档相关的评分,而是简单地筛选出符合条件的文档。这通常用于只关心是否匹配而不考虑匹配度的情况,如日志分析、数据分类等场景。Filter 查询更高效,适合不需要计算相关性的操作。

实际使用

Elasticsearch 中的所有的查询都会触发相关度得分计算,对于那些不需要相关度得分的场景下,Elasticsearch 以过滤器的形式提供了另一种查询功能,过滤器在概念上类似于查询,但是他们有非常快的执行速度,执行速度快主要有以下两个原因:


  • 过滤器不会计算相关度的得分,所以它们在计算上更快一些

  • 过滤器可以被缓存到内存中,这使得他在重复的搜索查询上,其要比相应的查询快的多


为了理解过滤器,可以将一个查询(像是 match_all,match,bool 等)和一个过滤器结合起来,我们以范围过滤器为例,它允许我们通过一个区间值来过滤文档,这通常被用在数字和日期的过滤上,下面这个例子使用一个被过滤的 查询,其返回值是 200 到 1000 之间(闭区间)的书:


POST /book/_search{  "query": {    "bool": {      "must": {        "match_all": {}      },      "filter": {        "range": {          "price": {            "gte": 200,            "lte": 1000          }        }      }    }  }}
复制代码


运行的结果如下图所示:



分解上面的例子,被过滤的查询包含一个 match_all 查询和一个过滤器。可以在查询部分放入其他查询,在 Filter 部分放入其他过滤器,在上面的应用场景中,由于所有的在这个范围之内的文档都是平等的(相关度都一样),没有一个文档比另一个文档更相关。所以这个时候就要使用范围过滤器。通常情况下,要决定使用过滤器还是查询,你就需要问自己是否需要相关度得分,如果相关度不重要,那就使用过滤器,否则使用查询。查询和过滤器在概念上类似于 SELECT WHERE 语句。

查询排序

在 Elasticsearch 中,查询结果可以按不同的字段进行排序,默认情况下是按 _score(相关性得分)排序。如果想根据其他字段排序,比如时间戳或价格,可以通过在查询请求中指定 sort 参数来完成。排序可以是升序(asc)或降序(desc),常用于电商、日志分析等需要按时间或数值排序的场景。

相关性评分

默认情况下,返回的结果都是按照相关性进行排序的,最相关的文档排在最前面,首先看看 sort 参数以及如何使用它。为了按照相关性来排序,需要将相关性表示为一个数值,在 Elasticsearch 中,相关性得分由一个浮点数进行表示,并在搜索结果中通过_score 参数返回,默认排序是_score 降序,按照相关性评分升序排序如下:


# 默认查询时的排序POST /book/_search{  "query": {    "match": {"description":"solr"}  }}
复制代码


执行结果如下图所示:


字段值排序

# 按照 order 字段进行排序POST /book/_search{  "query": {    "match_all": {}  },  "sort": [    {      "price": {        "order": "desc"      }    }  ]}
复制代码


执行的结果如下图所示:


多级排序

# 多种排序字段POST /book/_search{  "query":{    "match_all":{}  },  "sort": [    { "price": {       "order": "desc"     }    },    {       "timestamp": {         "order": "desc"       }    }  ]}
复制代码


执行结果如下图所示:


分页查询

Elasticsearch 分页的方式是非常简单的:


# 分页查询POST /book/_search{  "query": {    "match_all": {}  },  "sort": [    {      "price": {        "order": "desc"      }    }  ],  "size": 2,  "from": 0}
复制代码


执行结果如下图所示:


结果高亮

结果高亮功能用于在查询结果中突出显示匹配的关键词。当用户搜索特定的词时,Elasticsearch 可以在返回的文档中用 <em> 标签或其他 HTML 元素将匹配的关键词包裹起来,方便前端展示。这个功能常用于搜索引擎或全文检索的结果展示中,提升用户体验。


POST /book/_search{  "query": {    "match": {      "name": "elasticsearch"    }  },  "highlight": {    "pre_tags": "<font color='pink'>",    "post_tags": "</font>",    "fields": [{"name":{}}]  }}
复制代码


执行的结果如下图所示:



使用 match 查询的同时,加上一个 highlight 属性:


  • pre_tags 前置标签

  • post_tags 后置标签

  • fields 需要高亮的字段,name 这里声明 title 字段需要高亮

批量操作

Elasticsearch 提供了批量操作的 API,用于一次性执行多个操作,如插入、更新、删除等。这种批量操作可以显著提高处理大量数据的效率,减少与服务器的交互次数。Bulk API 在需要进行大规模数据处理或日志批量写入时非常有用。

批量查询

可以使用 mget 提供批量查询单条查询 ID 的时候,比如很多个 ID,一条一条的查询,网络开销是非常大的。


# 批量查询POST /_mget{  "docs" : [    {      "_index" : "book",      "_id" : 1    },    {      "_index" : "book",      "_id" : 2    }  ]}
复制代码


运行的结果如下图所示:


同一索引批量查询

# book索引下检索POST /book/_mget{  "docs" : [    {      "_id" : 2    },    {      "_id" : 3    }  ]}
# 当然也有一个简化的写法POST /book/_search{ "query": { "ids" : { "values" : ["1", "4"] } }}
复制代码


执行的结果如下图所示:


bulk 批量增删改

Bulk 操作解释将文档的增删改查一系列操作,通过一次请求全部做完,减少网络的传输次数。


POST /_bulk{"action": {"metadata"}}{"data"}
复制代码


示例:


# 批量的操作,增删改查POST /_bulk{ "delete": { "_index": "book", "_id": "1" }}{ "create": { "_index": "book", "_id": "5" }}{ "name": "test14","price":100.99 }{ "update": { "_index": "book", "_id": "2"} }{ "doc" : {"name" : "test"} }
复制代码


功能:


  • delete 删除一个文档,只要 1 个 JSON 串就可以 删除的批量操作不需要请求体

  • create 相当于强制创建 PUT /index/type/id/_create

  • index 普通的 put 操作,可以是创建文档,也可以是全量替换文档

  • update 执行的是局部更新 partial update 操作


格式:


  • 每个 JSON 不能换行,相邻 JSON 换行


隔离:


  • 每个操作互不影响,操作失败的行会返回其失败信息


实际用法:


  • bulk 请求一次不要太大,否则一下会挤压到内存中,性能会下降。

  • 一次请求几千个操作,大小在几 M 正好

  • bulk 会将要处理的数据载入内存中,所以数据量是有限的,最佳的数据量不是一个确定的值。取决于你的硬件能力、文档复杂性、索引以及搜索的负载

  • 一般建议 1 万-5 万个文档,大小建议是 15MB,默认不能超过 100MB,可以在(ES) config/elasticsearch.yml 中进行设置 http.max_content_length: 10mb

错误速查

其他系列

🚀 AI 篇持续更新中(长期更新)

AI 炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究,持续打造实用 AI 工具指南!AI 研究-132 Java 生态前沿 2025:Spring、Quarkus、GraalVM、CRaC 与云原生落地🔗 AI模块直达链接

💻 Java 篇持续更新中(长期更新)

Java-180 Java 接入 FastDFS:自编译客户端与 Maven/Spring Boot 实战 MyBatis 已完结,Spring 已完结,Nginx 已完结,Tomcat 已完结,分布式服务已完结,Dubbo 已完结,MySQL 已完结,MongoDB 已完结,Neo4j 已完结,FastDFS 已完结,OSS 正在更新... 深入浅出助你打牢基础!🔗 Java模块直达链接

📊 大数据板块已完成多项干货更新(300 篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT 案例 详解🔗 大数据模块直达链接

发布于: 刚刚阅读数: 4
用户头像

武子康

关注

永远好奇 无限进步 2019-04-14 加入

Hi, I'm Zikang,好奇心驱动的探索者 | INTJ / INFJ 我热爱探索一切值得深究的事物。对技术、成长、效率、认知、人生有着持续的好奇心和行动力。 坚信「飞轮效应」,相信每一次微小的积累,终将带来深远的改变。

评论

发布
暂无评论
大数据-176 Elasticsearch Filter DSL 全面实战:过滤查询、排序分页、高亮与批量操作_nosql_武子康_InfoQ写作社区