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

Changeset 9

Show
Ignore:
Timestamp:
03/08/06 23:21:04 (3 years ago)
Author:
jk
Message:

- use Ferret::Index::Index instance for searching as well, as the check for

external index changes (that was the reason for the complex searcher
initialization and closing code) is implemented there, too.

- search and index all attributes when no :fields option is given
- add :handle_parse_errors=true default option for ferret,

so find_by_contents behaves well on invalid query strings

- wildcard query-test

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/plugin/acts_as_ferret/lib/acts_as_ferret.rb

    r8 r9  
    120120          def ferret_indexes; @@ferret_indexes end 
    121121 
    122           @@index_searchers = Hash.new 
    123           def index_searchers; @@index_searchers end 
    124  
    125122          # declares a class as ferret-searchable.  
    126123          # 
    127124          # options are: 
    128           # The mandatory :fields property names all fields to include in the index. 
    129           # :index_dir declares the directory where to put the index for this class. 
    130           # The default is RAILS_ROOT/index/RAILS_ENV/CLASSNAME.  
    131           # The index directory will be created if it doesn't exist. 
    132           # 
    133           # parser_options: 
    134           # occur_default - declares whether query terms are required by 
     125          # 
     126          # fields:: names all fields to include in the index. If not given, 
     127          #   all attributes of the class will be indexed. 
     128          # 
     129          # index_dir:: declares the directory where to put the index for this class. 
     130          #   The default is RAILS_ROOT/index/RAILS_ENV/CLASSNAME.  
     131          #   The index directory will be created if it doesn't exist. 
     132          # 
     133          # ferret_options may be: 
     134          # occur_default:: - whether query terms are required by 
    135135          #   default (the default), or not. Specify one of  
    136136          #   Ferret::Search::BooleanClause::Occur::MUST or  
    137           #   Ferret::Search::BooleanClause::Occur::SHOULD  
    138           # analyzer - the analyzer to use for query parsing (default: nil, 
    139           # wihch means the ferret default Analyzer gets used) 
    140           def acts_as_ferret(options={}, parser_options={}) 
    141             configuration = { :index_dir => "#{FerretMixin::Acts::ARFerret::index_dir}/#{self.name}" } 
     137          #   Ferret::Search::BooleanClause::Occur::SHOULD 
     138          #  
     139          # analyzer:: the analyzer to use for query parsing (default: nil, 
     140          #   wihch means the ferret default Analyzer gets used) 
     141          # 
     142          def acts_as_ferret(options={}, ferret_options={}) 
     143            configuration = {  
     144              :fields => nil, 
     145              :index_dir => "#{FerretMixin::Acts::ARFerret::index_dir}/#{self.name}"  
     146            } 
     147            ferret_configuration = { 
     148              :occur_default => Search::BooleanClause::Occur::MUST, 
     149              :handle_parse_errors => true, 
     150              :default_search_field => '*', 
     151              # :analyzer => Analysis::StandardAnalyzer.new, 
     152              # :wild_lower => true 
     153            } 
    142154            configuration.update(options) if options.is_a?(Hash) 
    143  
    144             parser_configuration = { 
    145               :occur_default => Search::BooleanClause::Occur::MUST, 
    146               :analyzer => nil 
    147             } 
    148             parser_configuration.update(parser_options) if parser_options.is_a? Hash 
     155            ferret_configuration.update(ferret_options) if ferret_options.is_a?(Hash) 
     156            # these properties are somewhat vital to the plugin and shouldn't 
     157            # be overwritten by the user: 
     158            ferret_configuration.update( 
     159              :key               => :id, 
     160              :path              => configuration[:index_dir], 
     161              :auto_flush        => true, 
     162              :create_if_missing => true 
     163            ) 
    149164 
    150165            class_eval <<-EOV 
     
    157172              cattr_accessor :fields_for_ferret    
    158173              cattr_accessor :class_index_dir 
    159               cattr_accessor :parser_configuration 
     174              cattr_accessor :ferret_configuration 
    160175               
    161176              @@fields_for_ferret = Array.new 
    162177              @@class_index_dir = configuration[:index_dir] 
    163               @@parser_configuration = parser_configuration 
    164  
    165               # TODO: make occur_default configurable  
    166               def self.query_parser 
    167                 @@query_parser ||=  
    168                   QueryParser.new( fields_for_ferret,  
    169                                    parser_configuration ) 
    170               end 
     178              @@ferret_configuration = ferret_configuration 
    171179 
    172180              # private 
     
    177185              elsif configuration[:fields].respond_to?(:each) 
    178186                configuration[:fields].each do |field|  
    179                         define_to_field_method(field) 
     187                  define_to_field_method(field) 
    180188                end                 
    181189              else 
    182                 #need to handle :all case 
     190                @@fields_for_ferret = nil 
    183191              end 
    184192            EOV 
     
    188196 
    189197          def rebuild_index 
    190             index = Ferret::Index::Index.new(:path => class_index_dir, :create => true) 
     198            index = Index::Index.new(:path => class_index_dir, :create => true) 
    191199            self.find_all.each { |content| index << content.to_doc } 
    192200            logger.debug("Created Ferret index in: #{class_index_dir}") 
     
    199207          # as the key. 
    200208          def ferret_index 
    201             ferret_indexes[class_index_dir] ||=  
    202               Index::Index.new(:key               => :id, 
    203                                :path              => class_index_dir, 
    204                                :auto_flush        => true, 
    205                                :create_if_missing => true) 
     209            ferret_indexes[class_index_dir] ||= Index::Index.new(ferret_configuration) 
    206210          end  
    207211 
    208           # returns the searcher for the index that is used for this class. A 
    209           # new searcher will be opened if the segments file is newer than 
    210           # the existing searcher instance. That way modifications of the index 
    211           # will always be reflected by the searcher. 
    212           # Searcher instances are stored in a hash, where the index directory 
    213           # a searcher is working on is the key. 
    214           def index_searcher 
    215             if searcher = index_searchers[class_index_dir] 
    216               last_index_modification = File.mtime "#{class_index_dir}/segments" 
    217               if last_index_modification > searcher.creation_time 
    218                 searcher.close 
    219                 index_searchers.delete class_index_dir  
    220               end 
    221             end 
    222             index_searchers[class_index_dir] ||= new_index_searcher 
    223           end 
    224  
    225           def new_index_searcher 
    226             searcher = Search::IndexSearcher.new(class_index_dir) 
    227             searcher.creation_time = Time.now 
    228             searcher 
    229           end 
    230    
    231212          # Finds instances by contents. Terms are ANDed by default, can be circumvented  
    232213          # by using OR between terms.  
     
    235216          # :num_docs - number of hits to retrieve 
    236217          def find_by_contents(q, options = {}) 
    237             if q.is_a? Search::Query 
    238               query = q 
    239             else   
    240               query = query_parser.parse(q) 
    241             end 
    242             logger.debug "parsed query for <#{q}> : <#{query}>"  
    243218            id_array = [] 
    244             hits = index_searcher.search(query, options) 
     219            hits = ferret_index.search(q, options) 
    245220            hits.each do |hit, score| 
    246               id_array << index_searcher.reader.get_document(hit)[:id] 
     221              id_array << ferret_index[hit][:id] 
    247222            end 
    248223            begin 
     
    287262                                        Document::Field::Index::UNTOKENIZED ) 
    288263            # iterate through the fields and add them to the document 
    289             fields_for_ferret.each do |field| 
     264            if fields_for_ferret 
     265              # have user defined fields 
     266              fields_for_ferret.each do |field| 
    290267                doc << self.send("#{field}_to_ferret") 
     268              end 
     269            else 
     270              # take all fields 
     271              self.attributes.each_pair do |key,val| 
     272                unless key == :id 
     273                  logger.debug "add field #{key} with value #{val}" 
     274                  doc << Document::Field.new( 
     275                                    key,  
     276                                    val.to_s,  
     277                                    Ferret::Document::Field::Store::NO,  
     278                                    Ferret::Document::Field::Index::TOKENIZED) 
     279                end 
     280              end 
    291281            end 
    292282            return doc 
     
    304294end 
    305295 
    306 # add creation time attribute to the IndexSearcher class 
    307 Ferret::Search::IndexSearcher.class_eval do 
    308   attr_accessor :creation_time 
    309 end 
    310  
    311296# END acts_as_ferret.rb 
    312297 

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