search.rb 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. class Service::Search < Service::BaseWithCurrentUser
  3. def execute(term:, objects:, options: { limit: 10 })
  4. options[:limit] = 10 if options[:limit].blank?
  5. perform_search(term: term, objects: objects, options: options)
  6. end
  7. def perform_search(term:, objects:, options:)
  8. if SearchIndexBackend.enabled?
  9. # Performance optimization: some models may allow combining their Elasticsearch queries into one.
  10. result_by_model = combined_backend_search(term: term, objects: objects, options: options)
  11. # Other models require dedicated handling, e.g. for permission checks.
  12. result_by_model.merge!(models(objects: objects, direct_search_index: false).index_with do |model|
  13. model_search(model: model, term: term, options: options)
  14. end)
  15. # Finally, sort by object priority.
  16. models(objects: objects).map do |model|
  17. result_by_model[model]
  18. end.flatten
  19. else
  20. models(objects: objects).map do |model|
  21. model_search(model: model, term: term, options: options)
  22. end.flatten
  23. end
  24. end
  25. # Perform a direct, cross-module Elasticsearch query and map the results by class.
  26. def combined_backend_search(term:, objects:, options:)
  27. result_by_model = {}
  28. models_with_direct_search_index = models(objects: objects, direct_search_index: true).map(&:to_s)
  29. if models_with_direct_search_index
  30. SearchIndexBackend.search(term, models_with_direct_search_index, options).each do |item|
  31. klass = "::#{item[:type]}".constantize
  32. record = klass.lookup(id: item[:id])
  33. (result_by_model[klass] ||= []).push(record) if record
  34. end
  35. end
  36. result_by_model
  37. end
  38. # Call the model specific search, which will query Elasticsearch if available,
  39. # or the Database otherwise.
  40. def model_search(model:, term:, options:)
  41. model.search({ query: term, current_user: current_user, limit: options[:limit], ids: options[:ids] })
  42. end
  43. # Get a prioritized list of searchable models
  44. def models(objects:, direct_search_index: nil)
  45. objects.select do |model|
  46. prefs = model.search_preferences(current_user)
  47. next false if !prefs
  48. next false if direct_search_index.present? && !prefs[:direct_search_index] != direct_search_index
  49. true
  50. end.sort_by do |model|
  51. model.search_preferences(current_user)[:prio]
  52. end.reverse
  53. end
  54. end