通过项目标签和路由,在 Elasticsearch Serverless 中实现更快的跨项目搜索

作者:来自 Elastic Stas MalyshevLuigi Dell'Aquila

在 Elasticsearch Serverless 中,使用项目路由将跨项目搜索范围限定为完全跳过不匹配的项目,或使用项目标签字段在查询内部按标签进行过滤、聚合和排序。

通过 Elastic Cloud Serverless 摆脱运维负担。自动扩展、处理负载峰值,并专注于构建 ------ 立即开始 14 天免费试用,亲自体验!

你可以按照这些指南构建 AI 驱动的搜索体验,或跨业务系统和软件进行搜索


Elastic Cloud Serverless 中的跨项目搜索( CPS )允许你在单个请求中查询多个项目的数据,这是许多组织都有的需求。借助项目标签和路由,你可以轻松限定搜索范围。项目路由会在查询运行之前按项目别名进行过滤,因此 Elasticsearch 完全不会触碰不匹配的项目:无需索引解析、无需协调、无需计算。项目标签字段则像其他字段一样在查询内部工作,因此你可以按环境或部门等标签值对结果进行过滤、聚合、排序和分组。

本文介绍了 Serverless 项目标签,并详细说明了如何在跨项目搜索场景中使用它们,以便在查询中定位特定项目并提升查询性能。

项目标签背景

每个 Serverless 项目都关联了一组键值对,用于对项目进行分类和组织。这些被称为项目标签( project tags )。标签有两种类型:

  • 预构建标签( Prebuilt tags ):每个项目都存在的预定义标签,并会自动生成;例如, _alias 、 _id 、 _type ,分别对应项目别名、项目 ID 和项目类型。预定义标签名称始终以下划线开头。
  • 自定义标签( Custom tags ):用户定义的标签;它们可以使用任何以字母开头的名称,并且可以包含小写字母、数字、下划线和连字符。例如,你可以为 QA 环境项目使用标签 env:qa ,为生产环境项目使用标签 env:production 。

在 Elastic Cloud 控制台中,你可以在"管理项目( Manage project )"页面中管理项目标签:

你也可以通过编程方式,使用 Elasticsearch API GET _project/tags 查看这些标签:

复制代码
{
 "origin": {
   "f58ef00d1538476f884c137bf7d304ff": {
     "_alias": "my-origin-project-1",
     "_csp": "aws",
     "_id": "f58ef00d1538476f884c137bf7d304ff",
     "_organization": "500590167",
     "_region": "aws-eu-west-1",
     "_type": "security"
   }
 },
 "linked_projects": {
   "a4f8c2fa86824395a845e4a055e1ce83": {
     "_alias": "my-linked-1",
     "_csp": "aws",
     "_id": "a4f8c2fa86824395a845e4a055e1ce83",
     "_organization": "500590167",
     "_region": "aws-eu-west-1",
     "_type": "observability",
     "env": "qa",
     "test": "abcd"
   }
 }
}

在查询中,你可以使用项目标签将搜索范围限制为已关联项目中的某个子集;例如,仅搜索可观测性项目,或仅搜索属于计费部门的项目。这被称为项目路由( project routing );对于每次搜索,你都可以提供一个过滤表达式,将搜索范围限定为标签匹配该表达式的项目。这是一种非常高效的缩小搜索范围的方法,因为它不需要访问任何不包含匹配数据的项目。

此外,你还可以像使用普通索引字段一样,在查询中使用项目标签:用于匹配、聚合、排序、作为搜索字段输出的一部分等等。以这种方式使用时,项目标签看起来与任何映射字段完全相同,但它们的值并不存储在索引中;而是从项目配置中动态加载。这为在搜索和聚合中使用项目标签信息提供了更大的灵活性。

以这种方式使用时,项目标签始终带有 _project. 前缀;例如,项目标签 _alias 会变成 _project._alias ,项目标签 department 会变成 _project.department

项目路由

项目路由( project routing )通过在查询处理开始之前应用过滤表达式,将跨项目搜索限制在已关联项目的某个子集内;例如, _alias:my_search_project 。该过滤表达式使用的是 Lucene 查询语法的一个子集。这是一种非常高效的查询限制方式,因为过滤会在任何操作执行之前完成,不匹配过滤条件的关联项目甚至不会在此次查询中被访问。不过,这种过滤方式也存在限制,因为它只能用于排除整个项目。

这种过滤会应用到每个索引表达式上。例如,在没有路由表达式的情况下执行 GET logs/_search 时,它会在源项目以及所有关联项目中查找 logs 索引;但如果使用路由表达式 _alias:my-o11y-project ,则只会使用别名为 my-o11y-project 的项目。

为了方便使用,你可以将常用的路由表达式保存为命名项目路由表达式( named project routing expressions ),并在不同查询之间复用,只需指定表达式名称即可: @routing-expression

在 Technical Preview 版本中 ,项目路由仅支持基于 _alias 标签匹配进行过滤;例如, _alias:my-security-* 。在未来版本中,我们计划支持所有标签以及大部分 Lucene 过滤语法。

Query DSL

可以通过请求体字段为搜索指定项目路由:

复制代码
GET logs/_search 
{
  "project_routing": "_alias:my_search_project"
}

Elasticsearch 查询语言( ES|QL )

你可以通过在主查询之前添加语句来指定项目路由:

复制代码
SET project_routing = "_alias:my-project-alias" ;
FROM my_index
| LIMIT 10

或者,你也可以在 API 调用中使用 project_routing 查询参数,但在 ES|QL 中,更推荐使用 SET 语法。

优先级规则 :如果同时使用了 SET project_routing 语法,并且 API 也提供了 project_routing 查询参数,则以 SET 语法为准。

项目标签作为字段

项目标签可以通过 _project. 前缀在查询中作为字段使用(用于获取、匹配、聚合和排序)。这是通过创建一种特殊的动态映射类型实现的,并将其挂载到名为 _project 的字段上。这个字段本身没有任何数据,不能直接使用,但它包含与项目标签名称对应的子字段;例如 _project._alias_project.env 。这些字段会返回常量 keyword 值,这些值直接来自内存中存储的项目标签映射。

查询 DSL

Query DSL 中,你可以像使用普通字段一样,在任何可以使用字段名的地方使用项目标签字段,例如:

获取:

复制代码
{
  "fields": ["count", "_project._id", "_project._alias", "_project.env"]
}

通配符模式也同样适用:

复制代码
{
  "fields": ["count", "_project.my-tag-*"]
}

但是默认情况下,项目标签不会出现在输出字段中(即使使用 * 作为字段也一样);你始终需要通过 _project. 前缀显式地将它们包含进来。你不需要将项目标签加入输出字段就可以在匹配或聚合中使用它们;这些功能彼此是独立的。

匹配:

复制代码
"query": {
    "match": {
        "_project._alias": "my-project"
    }
}

对于这个简单示例,项目路由可能是一种更高效的方式;不过,也可以使用更复杂的匹配方式:

复制代码
{
  "query": {
    "bool": {
      "should": [
        { "term": { "_project._alias": "my-project" } },
        { "term": { "_project.env": "qa" } }
      ],
      "minimum_should_match": 1
    }
  }
}

与项目路由不同,这里可以使用完整的 Elasticsearch 匹配表达式集,即使在 Technical Preview 版本中也是如此。但需要注意,这会带来性能开销:索引表达式中指定的所有索引仍然会被解析,并且所有关联项目仍然会被访问,即使最终匹配表达式排除了它们的全部数据。

你也可以在项目标签上使用聚合:

复制代码
{
	"size": 0,
	"aggs": {
		"by_project": {
			"terms": {
				"field": "_project._alias"
			},
			"aggs": {
				"total_count": {
					"sum": {
						"field": "int_count"
					}
				}
			}
		}
	}
}

并且可以按项目标签进行排序:

复制代码
{
	"size": 4,
	"sort": [
		{
			"_project._alias": {
				"order": "asc"
			}
		}
	],
	"fields": [
		"count",
		"_project._id",
		"_project._alias"
	]
}

ES|QL

要在查询结果中将项目标签作为字段使用,你必须在 FROM 子句中使用 METADATA 关键字显式包含它们:

复制代码
FROM my_index METADATA _project._alias
| LIMIT 5

通配符可用于包含多个标签:

复制代码
FROM my_index METADATA _project.*
| LIMIT 5

一旦包含,这些标签字段就会像其他字段一样工作,可以被所有 ES|QL 命令使用;例如:

复制代码
FROM my_index METADATA _project._alias
| WHERE _project._alias == "production-data"
| STATS count() by status

在 ES|QL 中,在使用 project_routing 和在 WHERE 命令中基于项目标签定义过滤条件之间存在一些重要差异。

索引解析

  • 使用 project_routing="..." 时,索引只会在指定的项目中解析,因此你不会看到仅存在于被排除项目映射中的字段。
  • 而使用简单过滤,例如 WHERE _project._alias LIKE "..." 时,索引解析会在所有项目中进行,因此你也会看到仅存在于那些不匹配别名模式的项目中的列。

查询路由

  • 使用 project_routing="..." 时,查询只会路由到相关的项目。
  • 使用 WHERE _project._alias LIKE "..." 时,查询会路由到所有项目,因此你至少需要承担查询协调的成本。

查询执行

  • 使用 project_routing="..." 时,查询只会在匹配表达式的节点上执行。
  • 使用 WHERE _project._alias LIKE "..." 时,查询会路由到所有节点,但 ES|QL 会进行第二阶段优化,并将项目标签替换为常量,对匹配条件的项目执行 WHERE true,对不匹配的项目执行 WHERE false。在这种情况下,引擎会识别该查询不会返回结果,因此实际上不会发生执行。结论是,你仍然需要承担协调成本和本地重新规划成本,但实际执行将是空操作。

灵活性

  • 在 Technical Preview 版本中,project_routing 仅支持基于项目别名的过滤。未来版本将支持更复杂的语法和所有标签。
  • ES|QL 语言支持在任何允许字段名的位置使用项目标签,包括过滤器,即使是非常复杂的表达式。

结论

项目路由和项目标签字段都可以控制跨项目搜索中参与的项目,但它们的用途不同。

当性能最重要时使用项目路由 。无论是在 Query DSL 请求体中设置 project_routing,还是在 ES|QL 中使用 SET project_routing,效果都是一样的:在查询开始之前就排除不匹配的项目;没有索引解析、没有协调开销、没有浪费计算资源。如果你已经明确知道要查询哪些项目,这始终是最优路径。

当你需要灵活性时使用项目标签字段。项目标签在 Query DSL 和 ES|QL 中都像普通字段一样工作。你可以进行过滤、聚合、排序并将其包含在输出中。这支持项目路由无法实现的场景,例如将标签与布尔逻辑组合、按项目分组结果,或按"env""department"等自定义标签过滤。代价是,即使最终过滤掉数据,所有关联项目仍然会被访问。

结合两者可以获得最佳效果。先使用项目路由缩小相关项目范围,然后在查询中使用项目标签字段进行更细粒度逻辑处理。这样既能获得早期过滤带来的性能优势,又能保留完整查询表达能力。

原文:https://www.elastic.co/search-labs/blog/serverless-cross-project-search-project-tags-routing

相关推荐
翼达口香糖1 小时前
当大模型吃掉你的App,从高德开放平台看AI服务重构
大数据·人工智能·深度学习·语言模型·数据分析·边缘计算
lizhihai_991 小时前
股市学习心得-量比的作用
大数据·人工智能·学习
海兰1 小时前
使用 OpenTelemetry 与 Elastic APM 追踪 MCP 服务器工具调用
运维·服务器·elasticsearch·wpf
逆境不可逃2 小时前
一篇速通互联网架构的不断升级过程:从单机到云原生
java·elasticsearch·搜索引擎·云原生·架构
白云偷星子2 小时前
云原生笔记8
笔记·云原生
ai_coder_ai2 小时前
自动化脚本云原生之FaaS通用服务
云原生·autojs·自动化脚本·冰狐智能辅助·easyclick
AI周红伟3 小时前
All in Token, 移动,电信,联通,阿里,百度,华为,字节,Token石油战争,Token经济,百度要“重写”AI价值度量
大数据·人工智能·机器学习·百度·copilot·openclaw
AI周红伟3 小时前
Token经济学:AI时代的新货币战争,All in Token, 新时代的石油战争,华为,阿里,百度,字节的石油战争
大数据·人工智能·机器学习·百度·华为·copilot·openclaw
珂玥c10 小时前
k8s集群网络插件caclico切换为flannel
云原生·容器·kubernetes