To edit pages or tickets please login with username/password: aaf/aaf

Changeset 320

Show
Ignore:
Timestamp:
02/18/08 20:36:05 (8 months ago)
Author:
jk
Message:

local mode works

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/demo/test/unit/content_test.rb

    r319 r320  
    515515    assert_equal @another_content.id, contents_from_ferret.first.id  
    516516 
    517     # deprecated options, still supported 
    518     contents_from_ferret = Content.find_with_ferret('title', :num_docs => 1, :first_doc => 1) 
    519     assert_equal 1, contents_from_ferret.size 
    520     assert_equal @another_content.id, contents_from_ferret.first.id  
    521       
    522517  end 
    523518 
  • trunk/demo/test/unit/remote_index_test.rb

    r308 r320  
    88    @srv = ActsAsFerret::RemoteIndex.new :remote => 'druby://localhost:99999', :raise_drb_errors => true 
    99    assert_raise DRb::DRbConnError do 
    10       @srv.find_id_by_contents 'some query' 
     10      @srv.find_ids 'some query' 
    1111    end 
    1212  end 
     
    1414  def test_does_not_raise_drb_errors 
    1515    @srv = ActsAsFerret::RemoteIndex.new :remote => 'druby://localhost:99999', :raise_drb_errors => false 
    16     total_hits, results = @srv.find_id_by_contents( 'some query' ) 
     16    total_hits, results = @srv.find_ids( 'some query' ) 
    1717    assert_equal 0, total_hits 
    1818    assert results.empty? 
  • trunk/demo/test/unit/shared_index1_test.rb

    r319 r320  
    88  end 
    99 
    10   def test_lazy_loading_shared_index 
    11     results = SharedIndex1.find_with_ferret 'first', :lazy => [ :name ], :models => :all 
     10  def test_lazy_loading 
     11    results = ActsAsFerret::find 'first', 'shared', :lazy => [ :name ] 
    1212    assert_equal 2, results.size 
    1313    found_lazy_result = false 
     
    3333    assert_equal 1, result.size, result.inspect 
    3434    assert_equal shared_index1s(:first), result.first 
    35  
    36     result = SharedIndex1.find_with_ferret("name:first", :models => [SharedIndex1]) 
    37     assert_equal 1, result.size 
    38     assert_equal shared_index1s(:first), result.first 
    3935  end 
    4036 
     
    4541  end 
    4642 
    47   def test_find_with_ferret_all_classes 
    48     result = SharedIndex1.find_with_ferret("first", :models => :all
     43  def test_find_with_index_name 
     44    result = ActsAsFerret::find("first", 'shared'
    4945    assert_equal 2, result.size 
    5046    assert result.include?(shared_index1s(:first)) 
    5147    assert result.include?(shared_index2s(:first)) 
     48  end 
    5249 
    53     result = SharedIndex1.find_with_ferret("name:first", :models => [SharedIndex2]) 
     50  def test_find_with_class_list 
     51    result = ActsAsFerret::find("name:first", [SharedIndex1, SharedIndex2]) 
    5452    assert_equal 2, result.size 
    5553    assert result.include?(shared_index1s(:first)) 
    5654    assert result.include?(shared_index2s(:first)) 
    57  
    5855  end 
    5956 
     
    6360 
    6461  def test_destroy 
    65     result = SharedIndex1.find_with_ferret("first OR another", :models => :all
     62    result = ActsAsFerret::find("first OR another", 'shared'
    6663    assert_equal 4, result.size 
    6764    SharedIndex1.destroy(shared_index1s(:first)) 
    68     result = SharedIndex1.find_with_ferret("first OR another", :models => :all
     65    result = ActsAsFerret::find("first OR another", 'shared'
    6966    assert_equal 3, result.size 
    7067    shared_index2s(:first).destroy 
    71     result = SharedIndex1.find_with_ferret("first OR another", :models => :all
     68    result = ActsAsFerret::find("first OR another", 'shared'
    7269    assert_equal 2, result.size 
    7370  end 
  • trunk/plugin/acts_as_ferret/lib/act_methods.rb

    r318 r320  
    2626    #             The default is RAILS_ROOT/index/RAILS_ENV/CLASSNAME.  
    2727    #             The index directory will be created if it doesn't exist. 
    28     # 
    29     # single_index:: set this to true to let this class use a Ferret 
    30     #                index that is shared by all classes having :single_index set to true. 
    31     #                :store_class_name is set to true implicitly, as well as index_dir, so  
    32     #                don't bother setting these when using this option. the shared index 
    33     #                will be located in index/<RAILS_ENV>/shared . 
    34     # 
    35     # store_class_name:: to make search across multiple models (with either 
    36     #                    single_index or the multi_search method) useful, set 
    37     #                    this to true. the model class name will be stored in a keyword field  
    38     #                    named class_name 
    3928    # 
    4029    # reindex_batch_size:: reindexing is done in batches of this size, default is 1000 
  • trunk/plugin/acts_as_ferret/lib/acts_as_ferret.rb

    r319 r320  
    2525require 'ferret' 
    2626 
     27require 'ferret_find_methods' 
    2728require 'blank_slate' 
    2829require 'bulk_indexer' 
     
    118119    index_definition = { 
    119120      :index_dir => "#{ActsAsFerret::index_dir}/#{name}", 
    120       :store_class_name => false, 
    121121      :name => name, 
    122122      :single_index => false, 
     
    146146    # be overwritten by the user: 
    147147    index_definition[:ferret].update( 
    148       :key               => (index_definition[:store_class_name] ? [:id, :class_name] : :id)
     148      :key               => [:id, :class_name]
    149149      :path              => index_definition[:index_dir], 
    150150      :auto_flush        => true, # slower but more secure in terms of locking problems TODO disable when running in drb mode? 
     
    180180    end 
    181181    index.register_class(clazz, options) 
    182     if index.shared? 
    183       # make sure all models using this index get proper class methods 
    184       index.index_definition[:registered_models].each do |clazz| 
    185         clazz.extend SharedIndexClassMethods unless clazz.extended_by.include?(ActsAsFerret::SharedIndexClassMethods) 
    186       end 
    187     end 
    188182    return index 
    189183  end 
     
    197191  # count hits for a query with multiple models 
    198192  def self.total_hits(query, models, options = {}) 
    199     get_index_for(*models).total_hits query, options.merge( :models => models ) 
     193    find_index(models).total_hits query, options.merge( :models => models ) 
    200194  end 
    201195 
    202196  # find ids of records with multiple models 
    203   def self.find_ids(query, models, options = {}) 
    204     get_index_for(*models).find_ids query, options.merge( :models => models ) 
    205   end 
    206  
    207   def self.find(query, models, options = {}, ar_options = {}) 
     197  # TODO pagination logic? 
     198  def self.find_ids(query, models, options = {}, &block) 
     199    find_index(models).find_ids query, options.merge( :models => models ), &block 
     200  end 
     201 
     202  def self.find_index(models_or_index_name) 
     203    case models_or_index_name 
     204    when Symbol 
     205      get_index models_or_index_name 
     206    when String 
     207      get_index models_or_index_name.to_sym 
     208    #when Array 
     209    #  get_index_for models_or_index_name 
     210    else 
     211      get_index_for models_or_index_name 
     212    end 
     213  end 
     214 
     215  def self.find(query, models_or_index_name, options = {}, ar_options = {}) 
    208216    # TODO generalize local/remote index so we can remove the workaround below 
    209217    # (replace logic in class_methods#find_with_ferret) 
    210     if Class === models or models.size == 1 
    211       return (Class === models ? models : models.shift).find_with_ferret query, options, ar_options 
    212     end 
    213     index = get_index_for(*models) 
     218    # maybe put pagination stuff in a module to be included by all index 
     219    # implementations 
     220    models = [ models_or_index_name ] if Class === models_or_index_name 
     221    if models && models.size == 1 
     222      return models.shift.find_with_ferret query, options, ar_options 
     223    end 
     224    index = find_index(models_or_index_name) 
    214225    multi = (MultiIndex === index or index.shared?) 
    215226    if options[:per_page] 
     
    254265  # of all models, is returned. 
    255266  def self.get_index_for(*classes) 
     267    classes.flatten! 
    256268    raise ArgumentError.new("no class specified") unless classes.any? 
    257269    classes.map!(&:constantize) unless Class === classes.first 
     
    303315    key = indexes.map{ |i| i.index_name.to_s }.sort.join(",") 
    304316    ActsAsFerret::multi_indexes[key] ||= MultiIndex.new(indexes) 
     317  end 
     318 
     319  # check for per-model conditions and return these if provided 
     320  def self.conditions_for_model(model, conditions = {}) 
     321    if Hash === conditions 
     322      key = model.name.underscore.to_sym 
     323      conditions = conditions[key] 
     324    end 
     325    return conditions 
    305326  end 
    306327 
     
    328349    id_arrays.each do |model, id_array| 
    329350      next if id_array.empty? 
    330       model_class = begin 
    331         model.constantize 
    332       rescue 
    333         raise "Please use ':store_class_name => true' if you want to use multi_search.\n#{$!}" 
    334       end 
    335  
    336       # check for per-model conditions and take these if provided 
    337       if conditions = find_options[:conditions] 
    338         key = model.underscore.to_sym 
    339         conditions = conditions[key] if Hash === conditions 
    340       end 
     351      model_class = model.constantize 
    341352 
    342353      # merge conditions 
     354      conditions = conditions_for_model model_class, find_options[:conditions] 
    343355      conditions = combine_conditions([ "#{model_class.table_name}.#{model_class.primary_key} in (?)",  
    344356                                        id_array.keys ],  
    345357                                      conditions) 
    346  
    347358 
    348359      # check for include association that might only exist on some models in case of multi_search 
     
    358369      # fetch 
    359370      tmp_result = model_class.find(:all, find_options.merge(:conditions => conditions,  
    360                                                               :include    => filtered_include_options)) 
     371                                                             :include    => filtered_include_options)) 
    361372 
    362373      # set scores and rank 
     
    365376      end 
    366377      # merge with result array 
    367       result.concat tmp_result 
     378      result += tmp_result 
    368379    end 
    369380     
     
    428439    fi.add_field(:id, :store => :yes, :index => :untokenized)  
    429440    # class_name 
    430     fi.add_field(:class_name, :store => :yes, :index => :untokenized) if index_definition[:store_class_name] 
     441    fi.add_field(:class_name, :store => :yes, :index => :untokenized) 
    431442 
    432443    # other fields 
  • trunk/plugin/acts_as_ferret/lib/class_methods.rb

    r319 r320  
    177177      end 
    178178 
    179       total_hits, result = find_records_lazy_or_not q, options, find_options 
     179      total_hits, result = aaf_index.find_records q, options.merge(:models => [self]), find_options 
    180180      logger.debug "Query: #{q}\ntotal hits: #{total_hits}, results delivered: #{result.size}" 
    181181      SearchResults.new(result, total_hits, options[:page], options[:per_page]) 
     
    299299      id_arrays.each do |model, id_array| 
    300300        next if id_array.empty? 
    301         begin 
    302           model = model.constantize 
    303           # merge conditions 
    304           conditions = ActsAsFerret::combine_conditions([ "#{model.table_name}.#{model.primary_key} in (?)", id_array.keys ],  
    305                                           find_options[:conditions]) 
    306           opts = find_options.merge :conditions => conditions 
    307           opts.delete :limit; opts.delete :offset 
    308           count += model.count opts 
    309         rescue TypeError 
    310           raise "#{model} must use :store_class_name option if you want to use multi_search against it.\n#{$!}\n#{$!.backtrace.join("\n")}" 
    311         end 
     301        model = model.constantize 
     302        # merge conditions 
     303        conditions = ActsAsFerret::combine_conditions([ "#{model.table_name}.#{model.primary_key} in (?)", id_array.keys ],  
     304                                        find_options[:conditions]) 
     305        opts = find_options.merge :conditions => conditions 
     306        opts.delete :limit; opts.delete :offset 
     307        count += model.count opts 
    312308      end 
    313309      count 
  • trunk/plugin/acts_as_ferret/lib/index.rb

    r319 r320  
    3737      logger.info "register class #{clazz} with index #{index_name}" 
    3838      index_definition[:registered_models] << clazz 
    39       index_definition[:store_class_name] = true if shared? 
    4039 
    4140      # merge fields from this acts_as_ferret call with predefined fields 
  • trunk/plugin/acts_as_ferret/lib/instance_methods.rb

    r317 r320  
    123123      logger.debug "creating doc for class: #{self.class.name}, id: #{self.id}" 
    124124      returning Ferret::Document.new do |doc| 
    125         # store the id of each item 
     125        # store the id and class name of each item 
    126126        doc[:id] = self.id 
    127  
    128         # store the class name if configured to do so 
    129         doc[:class_name] = self.class.name if aaf_configuration[:store_class_name] 
     127        doc[:class_name] = self.class.name 
    130128       
    131129        # iterate through the fields and add them to the document 
  • trunk/plugin/acts_as_ferret/lib/local_index.rb

    r319 r320  
    11module ActsAsFerret 
    22  class LocalIndex < AbstractIndex 
    3     include MoreLikeThis::IndexMethods 
     3    include FerretFindMethods, MoreLikeThis::IndexMethods 
    44 
    55    def initialize(index_name) 
     
    7575    end 
    7676 
    77     # Queries the Ferret index to retrieve model class, id, score and the 
    78     # values of any fields stored in the index for each hit. 
    79     # If a block is given, these are yielded and the number of total hits is 
    80     # returned. Otherwise [total_hits, result_array] is returned. 
    81     def find_ids(query, options = {}) 
    82       result = [] 
    83       index = ferret_index 
    84       logger.debug "query: #{ferret_index.process_query query}" if logger.debug? 
    85       stored_fields = determine_stored_fields options 
    86  
    87       total_hits = index.search_each(query, options) do |hit, score| 
    88         doc = index[hit] 
    89         model = index_definition[:store_class_name] ? doc[:class_name] : index_definition[:class_name] 
    90         # fetch stored fields if lazy loading 
    91         data = extract_stored_fields(doc, stored_fields) 
    92         if block_given? 
    93           yield model, doc[:id], score, data 
    94         else 
    95           result << { :model => model, :id => doc[:id], :score => score, :data => data } 
    96         end 
    97       end 
    98       #logger.debug "id_score_model array: #{result.inspect}" 
    99       return block_given? ? total_hits : [total_hits, result] 
     77    def searcher 
     78      ferret_index 
    10079    end 
    10180 
  • trunk/plugin/acts_as_ferret/lib/multi_index.rb

    r319 r320  
    33      # This class can be used to search multiple physical indexes at once. 
    44      class MultiIndex 
     5        include FerretFindMethods 
    56        attr_accessor :logger 
    67         
     
    1819        end 
    1920 
    20         def find_records(query, options, ar_options) 
    21           result = [] 
    22  
    23           rank = 0 
    24           if options[:lazy] 
    25             logger.warn "ar_options #{ar_options} are ignored because :lazy => true" unless ar_options.empty? 
    26             total_hits = find_ids(query, options) do |model, id, score, data| 
    27               result << FerretResult.new(model, id, score, rank += 1, data) 
    28             end 
    29           else 
    30             id_arrays = {} 
    31  
    32             limit = options.delete(:limit) 
    33             offset = options.delete(:offset) || 0 
    34             options[:limit] = :all 
    35             total_hits = find_ids(query, options) do |model, id, score, data| 
    36               id_arrays[model] ||= {} 
    37               id_arrays[model][id] = [ rank += 1, score ] 
    38             end 
    39             result = ActsAsFerret::retrieve_records(id_arrays, ar_options) 
    40             total_hits = result.size if ar_options[:conditions] 
    41             if limit && limit != :all 
    42               result = result[offset..limit+offset-1] 
    43             end 
     21        def ar_find(query, options = {}, ar_options = {}) 
     22          limit = options.delete(:limit) 
     23          offset = options.delete(:offset) || 0 
     24          options[:limit] = :all 
     25          total_hits, result = super query, options, ar_options   
     26          total_hits = result.size if ar_options[:conditions] 
     27          if limit && limit != :all 
     28            result = result[offset..limit+offset-1] 
    4429          end 
    4530          [total_hits, result] 
    4631        end 
    4732         
    48         # Queries multiple Ferret indexes to retrieve model class, id and score for  
    49         # each hit. Use the models parameter to give the list of models to search. 
    50         # If a block is given, model, id and score are yielded and the number of  
    51         # total hits is returned. Otherwise [total_hits, result_array] is returned. 
    52         def find_ids(query, options = {}) 
    53           result = [] 
    54           stored_fields = determine_stored_fields options 
    55           total_hits = search_each(query, options) do |hit, score| 
    56             doc = searcher[hit] 
    57             raise "':store_class_name => true' is required to make searching across multiple models work!" if doc[:class_name].blank? 
    58             # fetch stored fields if lazy loading 
    59             data = extract_stored_fields(doc, stored_fields) 
    60             if block_given? 
    61               yield doc[:class_name], doc[:id], score, doc, data 
    62             else 
    63               result << { :model => doc[:class_name], :id => doc[:id], :score => score, :data => data } 
    64             end 
    65           end 
    66           return block_given? ? total_hits : [ total_hits, result ] 
    67         end 
    68  
    6933        def determine_stored_fields(options) 
    7034          return nil unless options.has_key?(:lazy) 
     
    10468          #end 
    10569          #true 
     70        end 
     71 
     72        def shared? 
     73          false 
    10674        end 
    10775          

To edit pages or tickets please login with username/password: aaf/aaf