【Elastic Engineering】使用 Elasticsearch 时间点读取器获得随时间推移而保持一致的数据视图

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 大多数数据都不断变化。在 Elasticsearch 中查询索引,实际上是在一个给定的时间点搜索数据。由于索引不断变化(在大多数可观测性和安全性用例中皆如此),在不同的时间执行两个相同的查询将返回不同的结果,因为数据会随着时间而变化。那么,如果需要消除时间变量的影响,该怎么做呢?

  作者: Alexander Reelsen  Principal Community Advocate

总结一下:如果可行,我们推荐您使用 Elasticsearch 的全新时间点功能。对于深度分页,我们不再推荐使滚动 API虽然它仍然有效)。


     大多数数据都不断变化。在 Elasticsearch 中查询索引,实际上是在一个给定的时间点搜索数据。由于索引不断变化(在大多数可观测性和安全性用例中皆如此),在不同的时间执行两个相同的查询将返回不同的结果,因为数据会随着时间而变化。那么,如果需要消除时间变量的影响,该怎么做呢?


      Elasticsearch 7.10 中引入的时间点读取器可以让您反复查询某个索引,仿佛该索引处于某个特定的时间点。


     从这个高度概括的介绍看,时间点功能似乎与滚动 API 类似,后者会检索下一批结果以完成滚动搜索。但两者间有一个微妙的差别,可以清楚表明为何时间点在未来将是“有状态”查询不可或缺的部分。


滚动 API:快速回顾

     

     滚动 API 的运行原理如下所述:


     常规搜索查询会附带滚动参数执行 每个搜索响应都包含一个 _scroll_id,用于下次查询 在滚动完所有响应后,可以删除 _scroll_id 以释放资源

     在您启动初始搜索请求的那一刻,返回的数据基本上都是冻结的。在滚动开始后发生的写入操作将不会成为搜索响应的一部分。这也适用于删除、索引和更新操作。这样可以保证整个数据集在某个时间点上是一致的。

     在需要释放资源的后台发生了什么?滚动搜索只在初始滚动搜索创建时考虑数据。这意味着在较低的级别,从初始请求返回数据所需的资源都不会被修改或删除。段(segments)会持续保持可用,即使段可能已经被合并而且不再为实时数据集所需。请注意,使用其他滚动 id 或完全未使用滚动的其他搜索也同时进行,查看与初始滚动搜索不同的数据。这导致更多数据被保持可用,而不仅仅是实时数据集。数据更多意味着段更多、文件句柄更多,从而造成堆更多,因为要将来自段的元数据保存在堆中。

     保持实时数据不需要的段可用也意味着需要更多磁盘空间来保持这些段继续存在,因为    它们在滚动 id 被删之前不能被删除。这种内部运行方式利用了引用计数。只要有一个组件(如滚动搜索)保有对数据的引用(例如通过与一个索引节点对应的打开文件句柄),就不会最终删除该数据,即使它不再属于实时数据集。这也是滚动 id 存在的原因。通过将其指定为查询的一部分,可指定要查询的语句。

     为了尽快释放资源,我们建议使用清除滚动 API还可以使用切片滚动等优化来并行执行数据检索。


那么时间点又如何呢?


     我们已经介绍了滚动搜索的基础知识,现在回到最重要的问题:如果我们已经有了所有这些基础架构,为什么还要使用时间点呢?

     目前,滚动搜索及其上下文与查询绑定。这意味着编写一个查询,添加一个滚动参数,来自这个查询的响应数据就会保持一致。然而,这并不总是我们所需要的。有时想对同一固定数据集适时运行不同的查询。这是一个重大的区别。时间点的首批用户之一是 EQL,即用于在时间序列数据中查询的事件查询语言。让我们看一下这个 EQL 查询:

GET /auth-logs/_eql/search
{
  "query": """
  sequence by host.name,source.ip,user.name with maxspan=15s
    [ authentication where event.outcome == "failure" ]
    [ authentication where event.outcome == "failure" ]
    [ authentication where event.outcome == "failure" ]
    [ authentication where event.outcome == "success" ]
  """
}

     它会在 15 秒内搜索 3 次失败的登录,然后再搜索一次成功的登录。这是 EQL 的一个完美用例,因为需要不止一个查询。

     在此情况中,关键点是时间点读取器实际上与搜索请求相分离。时间点结构在专用操作中创建,因此可用于任意搜索请求。您可使用时间点 API 做到这一点。来自此类请求的结果包括一个 id,其现在可用于您即将执行的任何搜索请求。 让我们看看在调用时间点 API 时,机房中发生了什么。基本上,这将执行一个分片操作,该操作会调用 SearchService.openReaderContext()。然而,这并不会为索引中的所有分片调用,而只会为命中搜索请求的分片调用。让我们看一个例子,它要求一个集群中至少有两个节点:

PUT test?wait_for_active_shards=all
{
  "settings": {
    "number_of_shards":5,
    "number_of_replicas":1
  }
}
POST test/_pit?keep_alive=1m
GET test/_stats?filter_path=**.open_contexts

最后一个调用返回

{
  "_all" : {
    "primaries" : {
      "search" : {
        "open_contexts" :2
      }
    },
    "total" : {
      "search" : {
        "open_contexts" :5
      }
    }
  },
  "indices" : {
    "test" : {
      "primaries" : {
        "search" : {
          "open_contexts" :2
        }
      },
      "total" : {
        "search" : {
          "open_contexts" :5
        }
      }
    }
  }
}

正如您在此所见,我们打开的上下文与主分片的数量一样多,但与常规搜索一样,上下文分布在主分片和副本分片之间。

您可以通过下面的例子了解时间点查询如何运行:

PUT test/_doc/1
{
  "name" :"Alex"
}
PUT test/_doc/2?refresh
{
  "name" :"David"
}
# 记下 id 并在下面再次使用
POST test/_pit?keep_alive=1m
DELETE test/_doc/1
# 这将返回 David doc
GET /_search
{
  "size":1,
  "from":0,
  "query": {
    "match_all": {}
  },
  "pit": {
        "id": "ID_RETURNED_FROM_PIT_REQUEST",
        "keep_alive":"1m"
  },
  "sort": [
    {
      "name.keyword": {
        "order": "desc"
      }
    }
  ]
}
# 这将返回 Alex doc
# 因为时间点读取器比这次删除更早
GET /_search
{
  "size":1,
  "query": {
    "match_all": {}
  },
  "pit": {
        "id": "ID_RETURNED_FROM_PIT_REQUEST",
        "keep_alive":"1m"
  },
  "sort": [
    {
      "name.keyword": {
        "order": "desc"
      }
    }
  ],
  "search_after" : ["David", 1]
}

      上面的代码片段在创建时间点读取器之后会执行文档的删除。所以,不论何时您采用添加时间点的方式运行搜索请求,被删除的文档都会成为结果集的一部分。

      但精彩不止如此!除了添加时间点架构以外,Elasticsearch 7.12 版还有其他改进之处。通过将分片的上下文 id 纳入考虑范围, Elasticsearch 建立了一种机制,可以在原始分片副本不再可用的情况下,在另一个分片副本上重新尝试时间点查询。不过,这一机制只会在两个分片都含有完全相同的段时才会发挥作用,只适用于可搜索快照或只读数据。

      并且,与可搜索滚动的一样,Elasticsearch 客户端将为时间点提供帮助工具。

      那么,现在应该一直使用时间点吗?关于滚动搜索的相同规则仍然适用。如果对于一个不断变化的索引有着很高的搜索负载,那么为每个请求创建一个新的时间点查询恐怕并不是一个好的主意,因为相当多的资源需要保持开放状态。但是,您可以通过使用一个后台进程每隔几分钟创建一个时间点 id 并将其用于所有搜索请求的方式来避免这种情况。通过这种方式,可以对所有请求保持一致的数据视图,代价就是不会考虑最新的数据。开发者已经规划了更进一步的改进方案,例如在使用时间点读取器时,结合切片查询

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
5月前
|
API 网络架构 索引
Elasticsearch索引中数据的增删改查与并发控制
Elasticsearch索引中数据的增删改查与并发控制
|
27天前
|
Web App开发 JavaScript Java
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
这篇文章是关于如何使用Spring Boot整合Elasticsearch,并通过REST客户端操作Elasticsearch,实现一个简单的搜索前后端,以及如何爬取京东数据到Elasticsearch的案例教程。
160 0
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
|
1月前
|
消息中间件 监控 关系型数据库
MySQL数据实时同步到Elasticsearch:技术深度解析与实践分享
在当今的数据驱动时代,实时数据同步成为许多应用系统的核心需求之一。MySQL作为关系型数据库的代表,以其强大的事务处理能力和数据完整性保障,广泛应用于各种业务场景中。然而,随着数据量的增长和查询复杂度的提升,单一依赖MySQL进行高效的数据检索和分析变得日益困难。这时,Elasticsearch(简称ES)以其卓越的搜索性能、灵活的数据模式以及强大的可扩展性,成为处理复杂查询需求的理想选择。本文将深入探讨MySQL数据实时同步到Elasticsearch的技术实现与最佳实践。
70 0
|
3月前
|
存储 缓存 监控
|
3月前
|
数据采集 人工智能 自然语言处理
阿里云Elasticsearch AI语义搜索:解锁未来搜索新纪元,精准洞察数据背后的故事!
【8月更文挑战第2天】阿里云Elasticsearch AI场景语义搜索最佳实践
186 5
|
4月前
|
存储 安全 文件存储
【elasticsearch】es6重启服务后数据消失,es6如何配置数据持久化储存
【elasticsearch】es6重启服务后数据消失,es6如何配置数据持久化储存
50 1
|
5月前
|
索引
利用滚动索引来管理海量Elasticsearch数据
利用滚动索引来管理海量Elasticsearch数据
|
5月前
|
数据库 索引
Elasticsearch索引别名:管理与优化数据访问
Elasticsearch索引别名:管理与优化数据访问
|
4月前
|
Java
Java 实现 Elasticsearch 查询全部数据
【7月更文挑战第7天】Java 实现 Elasticsearch 查询全部数据
|
5月前
|
数据安全/隐私保护 网络架构 索引
Elasticsearch索引数据的路由规则与自定义路由分发
Elasticsearch索引数据的路由规则与自定义路由分发
113 0

相关产品

  • 检索分析服务 Elasticsearch版