Class: ActsAsFerret::LocalIndex

Inherits:
AbstractIndex show all
Includes:
MoreLikeThis::IndexMethods
Defined in:
lib/acts_as_ferret/local_index.rb

Instance Attribute Summary

Attributes inherited from AbstractIndex

#index_definition, #index_name, #logger, #registered_models_config

Instance Method Summary (collapse)

Methods included from MoreLikeThis::IndexMethods

#build_more_like_this_query

Methods inherited from AbstractIndex

#change_index_dir, #register_class, #shared?

Methods included from FerretFindMethods

#ar_find, #count_records, #find_id_model_arrays, #find_ids, #find_records, #lazy_find, #scope_query_to_models

Constructor Details

- (LocalIndex) initialize(index_name)

A new instance of LocalIndex



5
6
7
8
# File 'lib/acts_as_ferret/local_index.rb', line 5

def initialize(index_name)
  super
  ensure_index_exists
end

Instance Method Details

- (Object) add(record, analyzer = nil) Also known as: <<

add record to index record may be the full AR object, a Ferret document instance or a Hash



100
101
102
103
104
105
106
# File 'lib/acts_as_ferret/local_index.rb', line 100

def add(record, analyzer = nil)
  unless Hash === record || Ferret::Document === record
    analyzer = record.ferret_analyzer
    record = record.to_doc 
  end
  ferret_index.add_document(record, analyzer)
end

- (Object) bulk_index(class_name, ids, options)



58
59
60
# File 'lib/acts_as_ferret/local_index.rb', line 58

def bulk_index(class_name, ids, options)
  ferret_index.bulk_index(class_name.constantize, ids, options)
end

- (Object) close

Closes the underlying index instance



36
37
38
39
40
41
42
# File 'lib/acts_as_ferret/local_index.rb', line 36

def close
  @ferret_index.close if @ferret_index
rescue StandardError 
  # is raised when index already closed
ensure
  @ferret_index = nil
end

- (Object) determine_stored_fields(options = {})

retrieves stored fields from index definition in case the fields to retrieve haven't been specified with the :lazy option



163
164
165
166
167
168
169
170
# File 'lib/acts_as_ferret/local_index.rb', line 163

def determine_stored_fields(options = {})
  stored_fields = options[:lazy]
  if stored_fields && !(Array === stored_fields)
    stored_fields = index_definition[:ferret_fields].select { |field, config| config[:store] == :yes }.map(&:first)
  end
  logger.debug "stored_fields: #{stored_fields.inspect}"
  return stored_fields
end

- (Object) document_number(key)

retrieves the ferret document number of the record with the given key.



137
138
139
140
141
142
143
# File 'lib/acts_as_ferret/local_index.rb', line 137

def document_number(key)
  docnum = ferret_index.doc_number(key)
  # hits = ferret_index.search query_for_record(key)
  # return hits.hits.first.doc if hits.total_hits == 1
  raise "cannot determine document number for record #{key}" if docnum.nil?
  docnum
end

- (Object) ensure_index_exists

Checks for the presence of a segments file in the index directory Rebuilds the index if none exists.



27
28
29
30
31
32
33
# File 'lib/acts_as_ferret/local_index.rb', line 27

def ensure_index_exists
  #logger.debug "LocalIndex: ensure_index_exists at #{index_definition[:index_dir]}"
  unless File.file? "#{index_definition[:index_dir]}/segments"
    ActsAsFerret::ensure_directory(index_definition[:index_dir])
    rebuild_index 
  end
end

- (Object) extract_stored_fields(doc, stored_fields)

loads data for fields declared as :lazy from the Ferret document



173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/acts_as_ferret/local_index.rb', line 173

def extract_stored_fields(doc, stored_fields) 
  data = {} 
  unless stored_fields.nil?
    logger.debug "extracting stored fields #{stored_fields.inspect} from document #{doc[:class_name]} / #{doc[:id]}"
    fields = index_definition[:ferret_fields] 
    stored_fields.each do |field|
      if field_cfg = fields[field]
        data[field_cfg[:via]] = doc[field]
      end
    end
    logger.debug "done: #{data.inspect}"
  end
  return data 
end

- (Object) ferret_index

The 'real' Ferret Index instance



17
18
19
20
21
22
23
# File 'lib/acts_as_ferret/local_index.rb', line 17

def ferret_index
  ensure_index_exists
  (@ferret_index ||= Ferret::Index::Index.new(index_definition[:ferret])).tap do |idx|
    idx.batch_size = index_definition[:reindex_batch_size]
    idx.logger = logger
  end
end

- (Object) highlight(key, query, options = {})

highlight search terms for the record with the given id.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/acts_as_ferret/local_index.rb', line 115

def highlight(key, query, options = {})
  logger.debug("highlight: #{key} query: #{query}")
  options.reverse_merge! :num_excerpts => 2, :pre_tag => '<em>', :post_tag => '</em>'
  highlights = []
  ferret_index.synchronize do
    doc_num = document_number(key)

    if options[:field]
      highlights << ferret_index.highlight(query, doc_num, options)
    else
      query = process_query(query) # process only once
      index_definition[:ferret_fields].each_pair do |field, config|
        next if config[:store] == :no || config[:highlight] == :no
        options[:field] = field
        highlights << ferret_index.highlight(query, doc_num, options)
      end
    end
  end
  return highlights.compact.flatten[0..options[:num_excerpts]-1]
end

- (Object) process_query(query, options = {})

Parses the given query string into a Ferret Query object.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/acts_as_ferret/local_index.rb', line 63

def process_query(query, options = {})
  return query unless String === query
  ferret_index.synchronize do
    if options[:analyzer]
      # use per-query analyzer if present
      qp = Ferret::QueryParser.new ferret_index.instance_variable_get('@options').merge(options)
      reader = ferret_index.reader
      qp.fields =
          reader.fields unless options[:all_fields] || options[:fields]
      qp.tokenized_fields =
          reader.tokenized_fields unless options[:tokenized_fields]
      return qp.parse query
    else
      return ferret_index.process_query(query)
    end
  end
end

- (Object) query_for_record(key)

build a ferret query matching only the record with the given id the class name only needs to be given in case of a shared index configuration



147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/acts_as_ferret/local_index.rb', line 147

def query_for_record(key)
  return Ferret::Search::TermQuery.new(:key, key.to_s)
  # if shared?
  #   raise InvalidArgumentError.new("shared index needs class_name argument") if class_name.nil?
  #   Ferret::Search::BooleanQuery.new.tap do |bq|
  #     bq.add_query(Ferret::Search::TermQuery.new(:id,         id.to_s),    :must)
  #     bq.add_query(Ferret::Search::TermQuery.new(:class_name, class_name), :must)
  #   end
  # else
  #   Ferret::Search::TermQuery.new(:id, id.to_s)
  # end
end

- (Object) rebuild_index

rebuilds the index from all records of the model classes associated with this index



45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/acts_as_ferret/local_index.rb', line 45

def rebuild_index
  models = index_definition[:registered_models]
  logger.debug "rebuild index with models: #{models.inspect}"
  close
  index = Ferret::Index::Index.new(index_definition[:ferret].dup.update(:auto_flush  => false, 
                                                                        :field_infos => ActsAsFerret::field_infos(index_definition),
                                                                        :create      => true))
  index.batch_size = index_definition[:reindex_batch_size]
  index.logger = logger
  index.index_models models
  reopen!
end

- (Object) remove(key)

delete record from index



110
111
112
# File 'lib/acts_as_ferret/local_index.rb', line 110

def remove(key)
  ferret_index.delete key
end

- (Object) reopen!



10
11
12
13
14
# File 'lib/acts_as_ferret/local_index.rb', line 10

def reopen!
  logger.debug "reopening index at #{index_definition[:ferret][:path]}"
  close
  ferret_index
end

- (Object) searcher



86
87
88
# File 'lib/acts_as_ferret/local_index.rb', line 86

def searcher
  ferret_index
end

- (Object) total_hits(query, options = {})

Total number of hits for the given query.



82
83
84
# File 'lib/acts_as_ferret/local_index.rb', line 82

def total_hits(query, options = {})
  ferret_index.search(process_query(query, options), options).total_hits
end