lib/enygma/search.rb in sander6-enygma-0.1.0 vs lib/enygma/search.rb in sander6-enygma-0.1.1

- old
+ new

@@ -51,10 +51,22 @@ :date_asc => Sphinx::Client::SPH_SORT_ATTR_ASC, :time_segments => Sphinx::Client::SPH_SORT_TIME_SEGMENTS, :extended => Sphinx::Client::SPH_SORT_EXTENDED, :expression => Sphinx::Client::SPH_SORT_EXPR } + + class InvalidFragementMatchingScheme < StandardError; end + + frag_proc = Proc.new { |s| raise InvalidFragementMatchingScheme } + FRAGMENT_MODES = Hash.new(frag_proc).merge({ + :exact => Proc.new { |s| s }, + :start => Proc.new { |s| s.split(/\s+/).collect {|f| f + '*'}.join(' ') }, + :end => Proc.new { |s| s.split(/\s+/).collect {|f| '*' + f }.join(' ') }, + :fragment => Proc.new { |s| s.split(/\s+/).collect {|f| '*' + f + '*' }.join(' ') }, + :fuzzy => Proc.new { |s| '*' + s.delete(' ').split(//).join('*') + '*' }, + :textmate => Proc.new { |s| '*' + s.delete(' ').split(//).join('*') + '*' } + }) def initialize(*args, &block) overrides = args.last.is_a?(Hash) ? args.pop : {} config = if args.first.is_a?(Enygma::Configuration) @@ -69,24 +81,32 @@ :adapter => config.adapter, :table => config.table } @sphinx = Sphinx::Client.new - @indexes = config.indexes - @term = overrides[:term] || "" - @target_attr = config.target_attr - @match_mode = MATCH_MODES[config.match_mode] - @key_prefix = config.key_prefix || '' + @indexes = config.indexes + @term = overrides[:term] || "" + @target_attr = config.target_attr + @match_mode = MATCH_MODES[config.match_mode] + @fragment_mode = config.fragment_mode + @key_prefix = config.key_prefix || '' @latitude = config.latitude @longitude = config.longitude @limit = @sphinx.instance_variable_get(:@limit) @offset = @sphinx.instance_variable_get(:@offset) @max = @sphinx.instance_variable_get(:@maxmatches) @cutoff = @sphinx.instance_variable_get(:@cutoff) + @weights = config.weights.inject({}) { |weights, (attr, weight)| weights.merge({ attr.to_s => weight })} || {} + @index_weights = config.index_weights.inject({}) { |weights, (index, weight)| weights.merge({ Enygma.indexify(index) => weight })} || {} + @sphinx.SetFieldWeights(@weights) + @sphinx.SetIndexWeights(@index_weights) + + @fields = [] + @return_attributes = [] @sphinx.SetServer(config.sphinx[:host], config.sphinx[:port]) @sphinx.SetMatchMode(@match_mode) end @@ -111,10 +131,15 @@ def in(table) @database[:table] = table self end + def in_fields(*fields) + @fields = fields + self + end + def using_match_mode(match_mode) @match_mode = MATCH_MODES[match_mode] @sphinx.SetMatchMode(@match_mode) self end @@ -122,11 +147,16 @@ def using_indexes(*indexes) @indexes = indexes.collect { |idx| Enygma.indexify(idx) } self end alias_method :using_index, :using_indexes - + + def using_fragment_matching(mode) + @fragment_mode = mode + self + end + def filter(attribute, values, exclude = false) attribute = attribute.to_s case values when Array @sphinx.SetFilter(attribute, values, exclude) @@ -201,10 +231,22 @@ def cutoff(value) @cutoff = value set_limits self end + + def weight(weights = {}) + @weights.merge!(weights.inject({}) { |weights, (attr, weight)| weights.merge({ attr.to_s => weight })}) + @sphinx.SetFieldWeights(@weights) + self + end + + def weight_index(weights = {}) + @index_weights.merge!(weights.inject({}) { |weights, (index, weight)| weights.merge({ Enygma.indexify(index) => weight })}) + @sphinx.SetIndexWeights(@index_weights) + self + end def within(distance) Enygma::GeoDistanceProxy.new(self, distance) end @@ -235,16 +277,25 @@ def set_limits @sphinx.SetLimits(@offset, @limit, @max, @cutoff) end def query_sphinx - sphinx_response = @sphinx.Query(@term, @indexes.join(', ')) + query_string = mutate_query_for_field_searching(@term) + query_string = FRAGMENT_MODES[@fragment_mode][query_string] + query_indexes = @indexes.join(', ') + sphinx_response = @sphinx.Query(query_string, query_indexes) raise InvalidSphinxQuery unless sphinx_response sphinx_response end def query_database(results) ids = results['matches'].collect { |match| match['attrs'][@target_attr] }.uniq @database[:adapter].query(:table => @database[:table], :ids => ids, :key_prefix => @key_prefix) + end + + def mutate_query_for_field_searching(query) + return query if @fields.empty? + self.using_match_mode(:extended2) + "@(#{@fields.collect {|f| f.to_s}.join(',')}) #{query}" end end end \ No newline at end of file