Merge pull request #6216 from betagouv/faster_search

Accélere la recherche sur les dossiers en évitant une etape de stockage de dossiers_id
This commit is contained in:
LeSim 2021-05-20 12:17:04 +02:00 committed by GitHub
commit 7a0538fafb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 17 deletions

View file

@ -10,25 +10,24 @@ class RechercheController < ApplicationController
def index def index
@search_terms = search_terms @search_terms = search_terms
@instructeur_dossiers_ids = current_instructeur&.dossiers&.ids || [] @instructeur_dossiers_ids = DossierSearchService
matching_dossiers_ids = DossierSearchService .matching_dossiers(current_instructeur&.dossiers, @search_terms, with_annotation: true)
.matching_dossiers(@instructeur_dossiers_ids, @search_terms, with_annotation: true)
.to_set
@dossier_avis_ids_h = current_expert&.avis&.pluck(:dossier_id, :id).to_h || {} expert_dossier_ids = DossierSearchService
expert_dossiers_ids = @dossier_avis_ids_h.keys .matching_dossiers(current_expert&.dossiers, @search_terms)
matching_dossiers_ids.merge(DossierSearchService.matching_dossiers(expert_dossiers_ids, @search_terms))
@dossiers_count = matching_dossiers_ids.count matching_dossiers_ids = (@instructeur_dossiers_ids + expert_dossier_ids).uniq
@paginated_ids = Kaminari @paginated_ids = Kaminari
.paginate_array(matching_dossiers_ids.to_a) .paginate_array(matching_dossiers_ids)
.page(page) .page(page)
.per(ITEMS_PER_PAGE) .per(ITEMS_PER_PAGE)
@projected_dossiers = DossierProjectionService.project(@paginated_ids, PROJECTIONS) @projected_dossiers = DossierProjectionService.project(@paginated_ids, PROJECTIONS)
@dossiers_count = matching_dossiers_ids.count
@followed_dossiers_id = current_instructeur&.followed_dossiers&.where(id: @paginated_ids)&.ids || [] @followed_dossiers_id = current_instructeur&.followed_dossiers&.where(id: @paginated_ids)&.ids || []
@dossier_avis_ids_h = current_expert&.avis&.where(dossier_id: @paginated_ids)&.pluck(:dossier_id, :id).to_h || {}
end end
private private

View file

@ -1,7 +1,11 @@
class DossierSearchService class DossierSearchService
def self.matching_dossiers(ids, search_terms, with_annotations = false) def self.matching_dossiers(dossiers, search_terms, with_annotations = false)
dossier_by_exact_id(ids, search_terms) if dossiers.nil?
.presence || dossier_by_full_text(ids, search_terms, with_annotations) []
else
dossier_by_exact_id(dossiers, search_terms)
.presence || dossier_by_full_text(dossiers, search_terms, with_annotations)
end
end end
def self.matching_dossiers_for_user(search_terms, user) def self.matching_dossiers_for_user(search_terms, user)
@ -11,20 +15,20 @@ class DossierSearchService
private private
def self.dossier_by_exact_id(ids, search_terms) def self.dossier_by_exact_id(dossiers, search_terms)
id = search_terms.to_i id = search_terms.to_i
if id != 0 && id_compatible?(id) # Sometimes instructeur is searching dossiers with a big number (ex: SIRET), ActiveRecord can't deal with them and throws ActiveModel::RangeError. id_compatible? prevents this. if id != 0 && id_compatible?(id) # Sometimes instructeur is searching dossiers with a big number (ex: SIRET), ActiveRecord can't deal with them and throws ActiveModel::RangeError. id_compatible? prevents this.
ids.filter { |dossier_id| dossier_id == id }.uniq dossiers.where(id: id).ids
else else
Dossier.none []
end end
end end
def self.dossier_by_full_text(ids, search_terms, with_annotations) def self.dossier_by_full_text(dossiers, search_terms, with_annotations)
ts_vector = "to_tsvector('french', #{with_annotations ? 'dossiers.search_terms || dossiers.private_search_terms' : 'dossiers.search_terms'})" ts_vector = "to_tsvector('french', #{with_annotations ? 'dossiers.search_terms || dossiers.private_search_terms' : 'dossiers.search_terms'})"
ts_query = "to_tsquery('french', #{Dossier.connection.quote(to_tsquery(search_terms))})" ts_query = "to_tsquery('french', #{Dossier.connection.quote(to_tsquery(search_terms))})"
Dossier.where(id: ids) dossiers
.where("#{ts_vector} @@ #{ts_query}") .where("#{ts_vector} @@ #{ts_query}")
.order(Arel.sql("COALESCE(ts_rank(#{ts_vector}, #{ts_query}), 0) DESC")) .order(Arel.sql("COALESCE(ts_rank(#{ts_vector}, #{ts_query}), 0) DESC"))
.pluck('id') .pluck('id')