通过项目标签和路由,在 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 查看这些标签:

bash 复制代码
`

1.  {
2.   "origin": {
3.     "f58ef00d1538476f884c137bf7d304ff": {
4.       "_alias": "my-origin-project-1",
5.       "_csp": "aws",
6.       "_id": "f58ef00d1538476f884c137bf7d304ff",
7.       "_organization": "500590167",
8.       "_region": "aws-eu-west-1",
9.       "_type": "security"
10.     }
11.   },
12.   "linked_projects": {
13.     "a4f8c2fa86824395a845e4a055e1ce83": {
14.       "_alias": "my-linked-1",
15.       "_csp": "aws",
16.       "_id": "a4f8c2fa86824395a845e4a055e1ce83",
17.       "_organization": "500590167",
18.       "_region": "aws-eu-west-1",
19.       "_type": "observability",
20.       "env": "qa",
21.       "test": "abcd"
22.     }
23.   }
24.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

在查询中,你可以使用项目标签将搜索范围限制为已关联项目中的某个子集;例如,仅搜索可观测性项目,或仅搜索属于计费部门的项目。这被称为项目路由( 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

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

bash 复制代码
`

1.  GET logs/_search 
2.  {
3.    "project_routing": "_alias:my_search_project"
4.  }

`AI写代码

Elasticsearch 查询语言( ES|QL )

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

ini 复制代码
`

1.  SET project_routing = "_alias:my-project-alias" ;
2.  FROM my_index
3.  | LIMIT 10

`AI写代码

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

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

项目标签作为字段

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

查询 DSL

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

获取:

json 复制代码
`

1.  {
2.    "fields": ["count", "_project._id", "_project._alias", "_project.env"]
3.  }

`AI写代码

通配符模式也同样适用:

json 复制代码
`

1.  {
2.    "fields": ["count", "_project.my-tag-*"]
3.  }

`AI写代码

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

匹配:

markdown 复制代码
`

1.  "query": {
2.      "match": {
3.          "_project._alias": "my-project"
4.      }
5.  }

`AI写代码

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

bash 复制代码
`

1.  {
2.    "query": {
3.      "bool": {
4.        "should": [
5.          { "term": { "_project._alias": "my-project" } },
6.          { "term": { "_project.env": "qa" } }
7.        ],
8.        "minimum_should_match": 1
9.      }
10.    }
11.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

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

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

bash 复制代码
`

1.  {
2.  	"size": 0,
3.  	"aggs": {
4.  		"by_project": {
5.  			"terms": {
6.  				"field": "_project._alias"
7.  			},
8.  			"aggs": {
9.  				"total_count": {
10.  					"sum": {
11.  						"field": "int_count"
12.  					}
13.  				}
14.  			}
15.  		}
16.  	}
17.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

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

markdown 复制代码
`

1.  {
2.  	"size": 4,
3.  	"sort": [
4.  		{
5.  			"_project._alias": {
6.  				"order": "asc"
7.  			}
8.  		}
9.  	],
10.  	"fields": [
11.  		"count",
12.  		"_project._id",
13.  		"_project._alias"
14.  	]
15.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

ES|QL

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

css 复制代码
`

1.  FROM my_index METADATA _project._alias
2.  | LIMIT 5

`AI写代码

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

markdown 复制代码
`

1.  FROM my_index METADATA _project.*
2.  | LIMIT 5

`AI写代码

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

sql 复制代码
`

1.  FROM my_index METADATA _project._alias
2.  | WHERE _project._alias == "production-data"
3.  | STATS count() by status

`AI写代码

在 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"等自定义标签过滤。代价是,即使最终过滤掉数据,所有关联项目仍然会被访问。

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

原文:www.elastic.co/search-labs...

相关推荐
OYangxf2 小时前
Git速查命令
大数据·git·elasticsearch
OYangxf2 小时前
Git Common Errors
大数据·git·elasticsearch
敖正炀2 小时前
映射与文档建模:动态映射、嵌套与父子关系
elasticsearch
Mike_6662 小时前
git@gitlab-rdc.xxxxx.com: Permission denied (publickey).fatal: 无法读取远程仓库。
git·elasticsearch·gitlab
明月_清风2 小时前
深入浅出 Elasticsearch:核心概念、工具链与底层原理全解析
后端·elasticsearch
zh路西法2 小时前
【git一键push脚本】基于Windows bat脚本的一键git提交脚本
windows·git·elasticsearch
递归尽头是星辰3 小时前
跳表为核:串联 Redis、ES 与业务架构的底层思想复用
redis·elasticsearch·跳表·数据结构的应用·中间件底层原理
爱喝热水的呀哈喽4 小时前
agent4hypermesh计划
大数据·elasticsearch·搜索引擎
Elastic 中国社区官方博客18 小时前
在 Elasticsearch 中使用利润率与流行度加权来优化电商搜索
大数据·数据库·elasticsearch·搜索引擎·全文检索