Class: Mebla::Context

Inherits:
Object
  • Object
show all
Defined in:
lib/mebla/context.rb

Overview

Handles indexing and reindexing

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeContext

Creates a new context object



10
11
12
13
14
15
# File 'lib/mebla/context.rb', line 10

def initialize            
  @indexed_models = []
  @mappings = {}
  @slingshot_index = Slingshot::Index.new(Mebla::Configuration.instance.index)
  @slingshot_index_name = Mebla::Configuration.instance.index
end

Instance Attribute Details

#indexed_modelsObject (readonly)

Returns the value of attribute indexed_models.



5
6
7
# File 'lib/mebla/context.rb', line 5

def indexed_models
  @indexed_models
end

#mappingsObject (readonly)

Returns the value of attribute mappings.



6
7
8
# File 'lib/mebla/context.rb', line 6

def mappings
  @mappings
end

#slingshot_indexObject (readonly)

Returns the value of attribute slingshot_index.



5
6
7
# File 'lib/mebla/context.rb', line 5

def slingshot_index
  @slingshot_index
end

#slingshot_index_nameObject (readonly)

Returns the value of attribute slingshot_index_name.



5
6
7
# File 'lib/mebla/context.rb', line 5

def slingshot_index_name
  @slingshot_index_name
end

Instance Method Details

#add_indexed_model(model, mappings = {}) ⇒ Object

Adds a model to the list of indexed models



19
20
21
22
23
24
25
26
27
# File 'lib/mebla/context.rb', line 19

def add_indexed_model(model, mappings = {})
  model = model.name if model.is_a?(Class)
  
  @indexed_models << model
  @indexed_models.uniq!
  @indexed_models.sort!
  
  @mappings.merge!(mappings)
end

#create_indexBoolean

Note:

Doesn’t index the data, use Mebla::Context#index_data to create the index and index the data

Creates and indexes the document

Returns:

  • (Boolean)

    true if operation is successful

Raises:



48
49
50
51
52
53
54
55
56
# File 'lib/mebla/context.rb', line 48

def create_index
  # Only create the index if it doesn't exist
  raise Mebla::Errors::MeblaIndexException.new("#{@slingshot_index_name} already exists !! use #rebuild_index to rebuild the index.") if index_exists?
  
  Mebla.log("Creating index")
  
  # Create the index
  build_index
end

#drop_indexBoolean

Deletes the index of the document

Returns:

  • (Boolean)

    true if operation is successful



60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/mebla/context.rb', line 60

def drop_index
  # Only drop the index if it exists
  return true unless index_exists?
  
  Mebla.log("Dropping index: #{self.slingshot_index_name}", :debug)
  
  # Drop the index
  result = @slingshot_index.delete
  
  Mebla.log("Dropped #{self.slingshot_index_name}: #{result.to_s}", :debug)
  
  # Check that the index doesn't exist
  !index_exists?
end

#index_data(*models) ⇒ nil

Creates the index and indexes the data for all models or a list of models given

Parameters:

  • *models

    a list of symbols each representing a model name to be indexed

Returns:

  • (nil)


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/mebla/context.rb', line 89

def index_data(*models)
  if models.nil? || models.empty?
    only_index = @indexed_models
  else
    only_index = models.collect{|m| m.to_s}
  end      
  
  Mebla.log("Indexing #{only_index.join(", ")}", :debug)
  
  # Build up a bulk query to save processing and time
  bulk_query = ""
  # Keep track of indexed documents
  indexed_count = {}
  
  # Create the index
  if create_index
    # Start collecting documents
    only_index.each do |model|
      Mebla.log("Indexing: #{model}")
      # Get the class
      to_index = model.camelize.constantize
      
      # Get the records    
      entries = []
      unless to_index.embedded?
        if to_index.sub_class?
          entries = to_index.any_in(:_type => [to_index.name])
        else              
          entries = to_index.any_in(:_type => [nil, to_index.name])
        end
      else
        parent = to_index.embedded_parent
        access_method = to_index.embedded_as
        
        parent.all.each do |parent_record|
          if to_index.sub_class?
            entries += parent_record.send(access_method.to_sym).any_in(:_type => [to_index.name])
          else
            entries += parent_record.send(access_method.to_sym).any_in(:_type => [nil, to_index.name])
          end
        end
      end
      
      # Save the number of entries to be indexed
      indexed_count[model] = entries.count          
      
      # Build the queries for this model          
      entries.each do |document|
        attrs = {} #document.attributes.dup # make sure we dont modify the document it self
        attrs[:id] = document.attributes["_id"] # the id is already added in the meta data of the action part of the query
        
        # only index search fields  and methods
        document.class.search_fields.each do |field|
          if document.attributes.keys.include?(field.to_s)
            attrs[field] = document.attributes[field.to_s]
          else
            attrs[field] = document.send(field)
          end
        end
        
        # index relational fields
        document.class.search_relations.each do |relation, fields|              
          items = document.send(relation.to_sym)
          
          next if items.nil?
          
          if items.is_a?(Array)
            next if items.empty?
            attrs[relation] = []
            items.each do |item|
              if fields.is_a?(Array)
                attrs[relation] << item.attributes.reject{|key, value| !fields.include?(key.to_sym)}
              else
                attrs[relation] << { fields => item.attributes[fields.to_s] }
              end
            end
          else
            attrs[relation] = {}
            if fields.is_a?(Array)
              attrs[relation].merge!(items.attributes.reject{|key, value| !fields.include?(key.to_sym)})
            else
              attrs[relation].merge!({ fields => items.attributes[fields.to_s] })
            end
          end
        end  
        
        # If embedded get the parent id
        if document.embedded?
          parent_id = document.send(document.class.embedded_parent_foreign_key.to_sym).id.to_s        
          attrs[(document.class.embedded_parent_foreign_key + "_id").to_sym] = parent_id
          
          # Build add to the bulk query
          bulk_query << build_bulk_query(@slingshot_index_name, to_index.slingshot_type_name, document.id.to_s, attrs, parent_id)
        else
          # Build add to the bulk query
          bulk_query << build_bulk_query(@slingshot_index_name, to_index.slingshot_type_name, document.id.to_s, attrs)
        end
      end
    end
  else
    raise Mebla::Errors::MeblaIndexException.new("Could not create #{@slingshot_index_name}!!!")
  end      
  
  Mebla.log("Bulk indexing:\n#{bulk_query}", :debug)      
  
  # Send the query
  response = Slingshot::Configuration.client.post "#{Mebla::Configuration.instance.url}/_bulk", bulk_query
  
  # Only refresh the index if no error ocurred
  unless response =~ /error/                              
    # Log results
    Mebla.log("Indexed #{only_index.count} model(s) to #{self.slingshot_index_name}: #{response}")
    Mebla.log("Indexing Report:")
    indexed_count.each do |model_name, count|
      Mebla.log("Indexed #{model_name}: #{count} document(s)")
    end
    
    # Refresh the index
    refresh_index
  else
    raise Mebla::Errors::MeblaIndexException.new("Indexing #{only_index.join(", ")} failed with the following response:\n #{response}")
  end
rescue RestClient::Exception => error
  raise Mebla::Errors::MeblaIndexException.new("Indexing #{only_index.join(", ")} failed with the following error: #{error.message}")
end

#index_exists?Boolean

Checks if the index exists and is available

Returns:

  • (Boolean)

    true if the index exists and is available, false otherwise



77
78
79
80
81
82
83
84
# File 'lib/mebla/context.rb', line 77

def index_exists?
  begin
    result = Slingshot::Configuration.client.get "#{Mebla::Configuration.instance.url}/#{@slingshot_index_name}/_status"
    return (result =~ /error/) ? false : true
  rescue RestClient::ResourceNotFound
    return false
  end
end

#rebuild_indexnil

Note:

Doesn’t index the data, use Mebla::Context#reindex_data to rebuild the index and index the data

Deletes and rebuilds the index

Returns:

  • (nil)

Raises:



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/mebla/context.rb', line 32

def rebuild_index
  # Only rebuild if the index exists
  raise Mebla::Errors::MeblaIndexException.new("#{@slingshot_index_name} does not exist !! use #create_index to create the index first.") unless index_exists?

  Mebla.log("Rebuilding index")      
  
  # Delete the index
  if drop_index
    # Create the index
    return build_index
  end
end

#refresh_indexnil

Refreshes the index

Returns:

  • (nil)


235
236
237
238
239
240
241
# File 'lib/mebla/context.rb', line 235

def refresh_index
  Mebla.log("Refreshing: #{self.slingshot_index_name}", :debug)
  
  result = @slingshot_index.refresh
  
  Mebla.log("Refreshed #{self.slingshot_index_name}: #{result}")
end

#reindex_data(*models) ⇒ nil

Rebuilds the index and indexes the data for all models or a list of models given

Parameters:

  • *models

    a list of symbols each representing a model name to rebuild it’s index

Returns:

  • (nil)


218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/mebla/context.rb', line 218

def reindex_data(*models)   
  Mebla.log("Rendexing: #{self.slingshot_index_name}")
  
  unless drop_index
    raise Mebla::Errors::MeblaIndexException.new("Could not drop #{@slingshot_index_name}!!!")
  end        
  
  # Create the index and index the data
  if models && !models.empty?
    index_data(models)
  else
    index_data
  end
end