# Solr-Suchanfrage # Diese enthält einmal die möglichen Suchfilter und die konkreten Such-Werte # sowie andere Suchparameter (Paginierung etc.) class MultiSolr::SearchRequest # Array(String) mit den Feldnamen zu denen eine Facet gebildet werden soll attr_accessor :facets # Hash mit optionalen Parametern zur Facet-Bildung # z.B. {:lagerort_h => {:limit => 1000, :sort => :index}, # :mdate => {:range => true, :start => 'NOW/DAY-5Day', :end => 'NOW/DAY', :gap => '+1DAY'}, # :saison => {:stats_field => 'volumen'}} attr_accessor :facet_params attr_accessor :facet_prefix # optinaler Facet-Prefix bei Facetsuche. Wird als facet.prefix an Solr weitergegeben attr_accessor :sorts # Array(String) mit den Feldnamen für die Sortierung (optional mit Sortierrichtung) attr_accessor :stats_fields # Array(String) mit den Feldnamen für die Gesamt-Statistiken berechnet werden sollen (Summe, min, max,...) attr_accessor :group_field # Name des Feldes nach dem gruppiert werden soll. Wenn nil, dann erfolgt keine Gruppierung(default) attr_accessor :group_size # Anzahl der Ergebnisse je Gruppe, wenn nil so ist laut SOLR default=1 attr_accessor :group_truncate # wenn true, dann werden Facets auf Basis der Gruppierung gebildet attr_reader :filter_values # Hash(Symbol => String,Hash) mit den konkreten Filter-Werten attr_writer :page_size # angeforderte Anzahl Einträge je Seite attr_accessor :active_filters # Array mit den Namen der aktiven Filter (als Symbole) @default_page_size = 25 BASE_FILTER_MAP = { :simple => MultiSolr::SolrFilterSimple, :collection => MultiSolr::SolrFilterCollection, :date_range => MultiSolr::SolrFilterDateRange, :date => MultiSolr::SolrFilterDate, :free_query => MultiSolr::SolrFilterFreeQuery } class << self # Definieren eines Filters # Erzeugt für den Filter entsprechende Attribut-Methoden # Dies vereinfacht die Nutzung in Formularen # Z.B. für einen Filter mit den Namen :firma_nr werden die Methoden # filter_firma_nr und filter_firma_nr=(value) generiert # # Params: # filter_name: Name des Filters als Symbol # options: optionale Hash mit: # :type Typ des Filters, entweder Typ-Bezeichner ein Symbol oder die Klasse des Filters # Der Typ-Bezeichner muss in MultiSolr::SearchRequest::BASE_FILTER_MAP definiert sein. # Ist kein Type angegeben so wird # andere: Alle anderen Angaben in den Options werden an den Filter weitergereicht. # Siehe also dazu die Beschreibungen am Constructor der einzelnen Filtertypen # def define_filter filter_name, options={} @possible_filters ||= {} filter_type = options.delete(:type) || :simple if filter_type.is_a?(Symbol) # Zum Symbol die konkrete Filterklasse holen filter_type = BASE_FILTER_MAP[filter_type] raise "Unknown type: #{filter_type}" if filter_type.nil? end filter = filter_type.new filter_name, options @possible_filters[filter_name] = filter # Definieren der Methode zum Lesen des Values dieses Filters define_method "filter_#{filter_name}" do @filter_values[filter_name] end # # Definieren der Methode zum zuweisen des Wertes dieses Filters define_method "filter_#{filter_name}=" do |value| if value.blank? || (value.is_a?(Array) && (value.empty? || value.all?(&:blank?)) ) || (value.is_a?(Hash) && value.values.all?(&:blank?)) @active_filters.delete(filter_name) return end @filter_values[filter_name] = value @active_filters << filter_name unless @active_filters.include?(filter_name) end end # mögliche Filter (Hash Filtername(Smybol) => Filter(SolrFilterSimple-Instance)) def possible_filters @possible_filters || {} end def set_default_page_size size @default_page_size = size end def default_page_size @default_page_size end end # of Class-Methods # Create new SolrSearch-Instance # @param attributes mit den Attributewerten als Hash (optional) def initialize attributes=nil @filter_values = {} @active_filters = [] @sorts = [] @facets = [] if attributes.is_a? Hash attributes.each do |aname, value| m_name = "#{aname}=" send(m_name, value) if self.respond_to?(m_name) end end end # Erzeugen ein FilterValue-Composite-Object welches # aus dem Filter und den in @filter_values hinterlegten Wert erzeugt wird # params: # filter_name: Name des Filters als Symbol # returns: MultiSolr::FilterValueComposite-Instance mit dem Filter und den zugehörigen Wert def build_filter_value_composite filter_name, value=nil filter = self.class.possible_filters[filter_name] raise "Unknown filter: #{filter_name}" if filter.nil? value ||= @filter_values[filter_name] MultiSolr::FilterValueComposite.new filter, value end # Erzeugt aus den filter_values die Solr-Query # liefert die Query als String def build_query solr_queries = [] @filter_values.each do |fname, value| fa_composite = build_filter_value_composite fname, value solr_query = fa_composite.build_solr_query solr_queries << solr_query unless solr_query.blank? end solr_queries.join(' ') end def render_filter_description descriptions = [] @filter_values.each do |fname, value| filter = self.class.possible_filters[fname] raise "Unknown filter: #{fname}" if filter.nil? value = filter.render_value value descriptions << "#{filter.label} = #{value}" end descriptions end # Filter mit konkreten Wert belegen def set_filter filter_name, value filter_name = filter_name.to_sym raise "Unbekannter Filter'#{filter_name}'" unless self.class.possible_filters.has_key?(filter_name) @filter_values[filter_name] = value @active_filters << filter_name unless @active_filters.include?(filter_name) end def remove_facet facet_name @facets.delete(facet_name.to_s) if @facets end def page= page_nr @page = [1, page_nr.to_i].max end def page @page || 1 end def page_size @page_size || self.class.default_page_size end def possible_filter_keys self.class.possible_filters.keys end # liefert Liste der möglichen Filternamen incl. der Labels # sortiert nach Labels # als Array aus Tuples # z.B. [ [:firma_nr, 'Bestandsfirma'], [:lkz, 'LKZ'] ] def possible_filter_keys_sorted_with_labels keys = self.class.possible_filters.keys result = keys.map{|k| [k, I18n.t("solr_search.#{k}")]} result.sort!{|e1,e2| e1.last <=> e2.last} result end # Liefert die Liste der inactiven Filter # (possible-filters - active-filters) # returns Array of Symbols def inactive_filters self.class.possible_filters.keys - @active_filters end # Abbilden von 3 Sortiermöglichkeiten als sort1 ... sort3 (1..3).each do |i| define_method "sort#{i}" do @sorts[i-1] end define_method "sort#{i}=" do |value| @sorts[i-1] = value end end end