cirandas.net

ref: master

plugins/elasticsearch/helpers/elasticsearch_helper.rb


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
module ElasticsearchHelper

  def searchable_types
    {
     :all              =>  _("All results"),
     :text_article     =>  _("Articles"),
     :uploaded_file    =>  _("Files"),
     :community        =>  _("Communities"),
     :event            =>  _("Events"),
     :person           =>  _("People")
    }
  end

  def sort_types
    sorts = {
     :relevance      => _("Relevance"),
     :lexical        => _("Alphabetical"),
     :more_recent    => _("More recent")
    }

    selected_type = (params[:selected_type] || nil)

    if selected_type and selected_type.to_sym != :all
      klass = selected_type.to_s.classify.constantize
      sorts.update klass.specific_sort if klass.respond_to? :specific_sort
    end
    sorts
  end

  def process_results
    selected_type = (params[:selected_type].presence|| :all).to_sym
    selected_type == :all ? search_from_all_models : search_from_model(selected_type)
  end

  private

  def search_from_all_models
    begin
      filter = (params[:filter] || "").to_sym
      query = get_query params[:query], sort_by: get_sort_by(filter), categories: params[:categories]
      Elasticsearch::Model.search(query,searchable_models, size: default_per_page(params[:per_page])).page(params[:page]).records
    rescue
      []
    end
  end

  def search_from_model(model)
    begin
      klass = model.to_s.classify.constantize
      filter = (params[:filter] || "").to_sym
      query = get_query params[:query], klass: klass, sort_by: get_sort_by(filter ,klass), categories: params[:categories]
      klass.search(query, size: default_per_page(params[:per_page])).page(params[:page]).records
    rescue
      []
    end
  end

  def default_per_page(per_page=nil)
    per_page || 10
  end

  def get_sort_by(sort_by, klass=nil)
    case sort_by
      when :lexical
        {"name.raw" => {"order" => "asc"}}
      when :more_recent
        {"created_at" => {"order" => "desc"}}
      else
        (klass and klass.respond_to?(:get_sort_by)) ? klass.get_sort_by(sort_by) : nil
    end
  end

  def searchable_models
    searchable_types.except(:all).keys.map {|model| model.to_s.classify.constantize}
  end

  def query_string(expression="", models=[])
    return { match_all: {}  } if not expression
    {
      query_string: {
        query: "*"+expression.downcase.split.join('* *')+"*",
        fields: fields_from_models(models),
        tie_breaker: 0.4,
        minimum_should_match: "100%"
      }
    }
  end


  def query_method(expression="", models=[], categories=[])
    query = {}
    current_user ||= nil

    query[:query] = {
      filtered: {
        query: query_string(expression, models),
        filter: {
          bool: {}
        }
      }
    }

    query[:query][:filtered][:filter][:bool] = {
      should: models.map {|model| model.filter(environment: @environment.id, user: current_user )}
    }

    unless categories.blank?
      query[:query][:filtered][:filter][:bool][:must] = models.first.filter_category(categories)
    end

    query
  end

  def get_query(text="", options={})
    klass = options[:klass]
    sort_by = options[:sort_by]
    categories = (options[:categories] || "").split(",")
    categories = categories.map(&:to_i)

    models = (klass.nil?) ? searchable_models : [klass]

    query = query_method(text, models, categories)
    query[:sort] = sort_by if sort_by

    query
  end

  def fields_from_models(klasses)
    fields = Set.new
    klasses.each do |klass|
      klass::SEARCHABLE_FIELDS.map do |key, value|
        if value and value[:weight]
          fields.add "#{key}^#{value[:weight]}"
        else
          fields.add "#{key}"
        end
      end
    end
    fields.to_a
  end

end