GLQL/Work Items Advanced Search missing Elasticsearch routing parameter causing performance degradation
Summary
The GLQL/Work Items Advanced Search integration with Elasticsearch does not pass the root_ancestor_ids parameter in es_search_options, which prevents Elasticsearch from using shard routing. This causes queries to search across ALL shards instead of targeting specific shards for the namespace, resulting in performance degradation and increased cluster load.
Steps to reproduce
- Enable Advanced Search (Elasticsearch) for a GitLab instance
- Enable either
glql_es_integrationorwork_items_list_es_integrationfeature flag - Execute a GLQL query or Work Items List query for a specific project or group
- Observe the Elasticsearch query (via ES slow logs or monitoring)
- Notice the query does NOT include a
routingparameter
Example: Query a group's work items via GLQL:
query GLQL_WorkItems {
group(fullPath: "mygroup") {
workItems(state: OPENED) {
nodes { id title }
}
}
}
What is the current bug behavior?
Current behavior:
- Elasticsearch queries from the Advanced Finder do NOT include the
routingparameter - ES searches across ALL shards in the work_items index
- Query performance degrades proportionally to the number of shards
- Increased resource consumption on the Elasticsearch cluster
Evidence:
In ee/lib/ee/search/advanced_finders/work_items_finder.rb (lines 105-109):
def es_search_options
{
index_name: INDEX_NAME
}
end
The root_ancestor_ids parameter is missing, which is required for Elasticsearch routing.
What is the expected correct behavior?
Expected behavior:
- Elasticsearch queries should include the
routingparameter with the root namespace ID - ES should only search shards containing data for the specified namespace
- Query performance should be optimal, especially on large GitLab instances
- Resource consumption should be minimized
Expected ES query format:
{
"routing": "group_123",
"index": "gitlab-production-work-items",
"body": { ... }
}
Relevant logs and/or screenshots
Working implementation for comparison:
The Vulnerability Elastic Finder correctly implements routing in ee/app/finders/security/vulnerability_elastic_base_finder.rb (lines 134-145):
def es_search_options
{
index_name: INDEX_NAME,
# This key is used by es to find the correct shard.
# See Elastic::Latest::Routing for how its used
root_ancestor_ids: root_ancestor_ids
}
end
def root_ancestor_ids
[vulnerable.root_ancestor.id]
end
Routing flow:
-
es_search_optionsincludesroot_ancestor_ids: [123] -
Search::Elastic::Relationpasses options toGitlab::Search::Client.execute_search -
Gitlab::Search::ClientincludesElastic::Latest::Routingmodule -
routing_options(options)is called, which builds{ routing: "group_123" } - Routing parameter is added to the Elasticsearch query
Possible fixes
Solution:
Add root_ancestor_ids to es_search_options in ee/lib/ee/search/advanced_finders/work_items_finder.rb:
def es_search_options
{
index_name: INDEX_NAME,
# This key is used by ES to find the correct shard
# See Elastic::Latest::Routing for how it's used
root_ancestor_ids: root_ancestor_ids
}
end
def root_ancestor_ids
[resource_parent.root_ancestor.id]
end
Why this works:
- The
resource_parentis already available (either a Project or Group) - Both Project and Group have a
root_ancestormethod - The
root_ancestor.idis already calculated inbase_params(line 154) for query filters - The routing infrastructure (
Elastic::Latest::Routing) is already included inGitlab::Search::Client
Performance Impact:
- On GitLab.com with 1000+ top-level groups across 10 shards:
- Without routing: Queries search 10 shards
- With routing: Queries search ~1 shard (10x improvement)
Files to modify:
-
ee/lib/ee/search/advanced_finders/work_items_finder.rb(addroot_ancestor_idstoes_search_options)
Testing needed:
- Unit tests: Verify
es_search_optionsincludesroot_ancestor_ids - Integration tests: Verify routing string is included in actual ES queries
- Performance tests: Compare query times with/without routing
References:
- Routing module:
ee/lib/elastic/latest/routing.rb - Client integration:
ee/lib/gitlab/search/client.rb(lines 40-48) - Working example:
ee/app/finders/security/vulnerability_elastic_base_finder.rb(lines 134-145)