Skip to content
Snippets Groups Projects
Commit 8041a872 authored by Douwe Maan's avatar Douwe Maan
Browse files

Drastically improve project search performance by no longer searching namespace name

parent 3dd5bedb
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -18,6 +18,7 @@ class Project < ActiveRecord::Base
include SelectForProjectAuthorization
include Routable
include GroupDescendant
include Gitlab::SQL::Pattern
 
extend Gitlab::ConfigHelper
extend Gitlab::CurrentSettings
Loading
Loading
@@ -424,32 +425,17 @@ class Project < ActiveRecord::Base
#
# query - The search query as a String.
def search(query)
ptable = arel_table
ntable = Namespace.arel_table
pattern = "%#{query}%"
# unscoping unnecessary conditions that'll be applied
# when executing `where("projects.id IN (#{union.to_sql})")`
projects = unscoped.select(:id).where(
ptable[:path].matches(pattern)
.or(ptable[:name].matches(pattern))
.or(ptable[:description].matches(pattern))
)
namespaces = unscoped.select(:id)
.joins(:namespace)
.where(ntable[:name].matches(pattern))
union = Gitlab::SQL::Union.new([projects, namespaces])
pattern = to_pattern(query)
 
where("projects.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
where(
arel_table[:path].matches(pattern)
.or(arel_table[:name].matches(pattern))
.or(arel_table[:description].matches(pattern))
)
end
 
def search_by_title(query)
pattern = "%#{query}%"
table = Project.arel_table
non_archived.where(table[:name].matches(pattern))
non_archived.where(arel_table[:name].matches(to_pattern(query)))
end
 
def visibility_levels
Loading
Loading
---
title: Drastically improve project search performance by no longer searching namespace
name
merge_request:
author:
type: performance
Loading
Loading
@@ -30,7 +30,7 @@ module Gitlab
def initialize(current_user, limit_projects, query)
@current_user = current_user
@limit_projects = limit_projects || Project.all
@query = Shellwords.shellescape(query) if query.present?
@query = query
end
 
def objects(scope, page = nil)
Loading
Loading
Loading
Loading
@@ -136,7 +136,7 @@ describe Admin::ProjectsFinder do
context 'filter by name' do
let(:params) { { name: 'C' } }
 
it { is_expected.to match_array([shared_project, public_project, private_project]) }
it { is_expected.to match_array([public_project]) }
end
 
context 'sorting' do
Loading
Loading
Loading
Loading
@@ -1254,24 +1254,6 @@ describe Project do
expect(described_class.search(project.path.upcase)).to eq([project])
end
 
it 'returns projects with a matching namespace name' do
expect(described_class.search(project.namespace.name)).to eq([project])
end
it 'returns projects with a partially matching namespace name' do
expect(described_class.search(project.namespace.name[0..2])).to eq([project])
end
it 'returns projects with a matching namespace name regardless of the casing' do
expect(described_class.search(project.namespace.name.upcase)).to eq([project])
end
it 'returns projects when eager loading namespaces' do
relation = described_class.all.includes(:namespace)
expect(relation.search(project.namespace.name)).to eq([project])
end
describe 'with pending_delete project' do
let(:pending_delete_project) { create(:project, pending_delete: true) }
 
Loading
Loading
Loading
Loading
@@ -35,8 +35,8 @@ describe Search::GlobalService do
expect(results.objects('projects')).to match_array [internal_project, public_project]
end
 
it 'namespace name is searchable' do
results = described_class.new(user, search: found_project.namespace.path).execute
it 'project name is searchable' do
results = described_class.new(user, search: found_project.name).execute
 
expect(results.objects('projects')).to match_array [found_project]
end
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment