Class: Solrizer::FieldMapper
- Inherits:
-
Object
- Object
- Solrizer::FieldMapper
- Includes:
- Loggable
- Defined in:
- lib/solrizer/field_mapper.rb
Overview
Maps Term names and values to Solr fields, based on the Term’s data type and any index_as options.
The basic structure of a mapper is:
Mapping on Index Type
To define a custom mapper:
class CustomMapper < Solrizer::FieldMapper
index_as :searchable, :suffix => '_search'
index_as :edible, :suffix => '_food'
end
# t.dish_name :index_as => [:searchable] -maps to-> dish_name_search
# t.ingredients :index_as => [:searchable, :edible] -maps to-> ingredients_search, ingredients_food
(See Solrizer::XML::TerminologyBasedSolrizer for instructions on applying a custom mapping once you have defined it.)
Default Index Types
You can mark a particular index type as a default. It will then always be included unless terms explicity exclude it with the “not_” prefix:
class CustomMapper < Solrizer::FieldMapper
index_as :searchable, :suffix => '_search', :default => true
index_as :edible, :suffix => '_food'
end
# t.dish_name -maps to-> dish_name_search
# t.ingredients :index_as => [:edible] -maps to-> ingredients_search, ingredients_food
# t.secret_ingredients :index_as => [:not_searchable, :edible] -maps to-> secret_ingredients_food
Mapping on Data Type
A mapper can apply different suffixes based on a term’s data type:
class CustomMapper < Solrizer::FieldMapper
index_as :searchable, :suffix => '_search' do |type|
type.date :suffix => '_date'
type.integer :suffix => '_numeric'
type.float :suffix => '_numeric'
end
index_as :edible, :suffix => '_food'
end
# t.published :type => :date, :index_as => [:searchable] -maps to-> published_date
# t.votes :type => :integer, :index_as => [:searchable] -maps to-> votes_numeric
If a specific data type doesn’t appear in the list, the mapper falls back to the index_as:
# t.description :type => :text, :index_as => [:searchable] -maps to-> description_search
Custom Value Converters
All of the above applies to the generation of Solr names. Mappers can also provide custom conversion logic for the generation of Solr values by attaching a custom value converter block to a data type:
require 'time'
class CustomMapper < Solrizer::FieldMapper
index_as :searchable, :suffix => '_search' do |type|
type.date do |value|
Time.parse(value).utc.to_i
end
end
end
Note that the nesting order is always:
FieldMapper definition
index_as
data type
value converter
You can use the special data type “default” to apply custom value conversion to any data type:
require 'time'
class CustomMapper < Solrizer::FieldMapper
index_as :searchable do |type|
type.date :suffix => '_date' do |value|
Time.parse(value).utc.to_i
end
type.default :suffix => '_search' do |value|
value.to_s.strip
end
end
end
This example converts searchable dates to milliseconds, and strips extra whitespace from all other searchable data types.
Note that the :suffix option may appear on the data types and the index_as. The search order for the suffix on a field of type foo is:
-
type.foo
-
type.default
-
index_as
The suffix is optional in all three places.
Note that a single Term with multiple index types can translate into multiple Solr fields, because we may want Solr to index a single field in multiple ways. However, if two different mappings generate both the same solr field name and the same value, the mapper will only emit a single field.
ID Field
In addition to the normal field mappings, Solrizer gives special treatment to an ID field. If you want that logic (and you probably do), specify a name for this field:
class CustomMapper < Solrizer::FieldMapper
id_field 'id'
end
Extending the Default
The default mapper is Solrizer::FieldMapper::Default. You can customize the default mapping by subclassing it. For example, to override the ID field name and the default suffix for sortable, and inherit everything else:
class CustomMapperBasedOnDefault < Solrizer::FieldMapper::Default
id_field 'guid'
index_as :sortable, :suffix => '_xsort'
end
Direct Known Subclasses
Defined Under Namespace
Classes: DataTypeMapping, DataTypeMappingBuilder, Default, IndexTypeMapping
Constant Summary collapse
- @@instance_init_actions =
—— Class methods ——
Hash.new { |h,k| h[k] = [] }
Instance Attribute Summary collapse
-
#default_index_types ⇒ Object
readonly
—— Instance methods ——.
-
#id_field ⇒ Object
readonly
—— Instance methods ——.
-
#mappings ⇒ Object
readonly
—— Instance methods ——.
Class Method Summary collapse
- .id_field(field_name) ⇒ Object
- .index_as(index_type, opts = {}, &block) ⇒ Object
-
.load_mappings(config_path = nil) ⇒ Object
Loads solr mappings from yml file.
Instance Method Summary collapse
-
#initialize ⇒ FieldMapper
constructor
A new instance of FieldMapper.
-
#solr_name(field_name, field_type, index_type = :searchable) ⇒ Object
Given a specific field name, data type, and index type, returns the corresponding solr name.
-
#solr_names_and_values(field_name, field_value, field_type, index_types) ⇒ Object
Given a field name-value pair, a data type, and an array of index types, returns a hash of mapped names and values.
Constructor Details
#initialize ⇒ FieldMapper
Returns a new instance of FieldMapper.
219 220 221 222 223 |
# File 'lib/solrizer/field_mapper.rb', line 219 def initialize @mappings = {} self.class.apply_instance_init_actions(self) @default_index_types = @mappings.select { |ix_type, mapping| mapping.opts[:default] }.map(&:first) end |
Instance Attribute Details
#default_index_types ⇒ Object (readonly)
—— Instance methods ——
217 218 219 |
# File 'lib/solrizer/field_mapper.rb', line 217 def default_index_types @default_index_types end |
#id_field ⇒ Object (readonly)
—— Instance methods ——
217 218 219 |
# File 'lib/solrizer/field_mapper.rb', line 217 def id_field @id_field end |
#mappings ⇒ Object (readonly)
—— Instance methods ——
217 218 219 |
# File 'lib/solrizer/field_mapper.rb', line 217 def mappings @mappings end |
Class Method Details
.id_field(field_name) ⇒ Object
133 134 135 136 137 |
# File 'lib/solrizer/field_mapper.rb', line 133 def self.id_field(field_name) add_instance_init_action do @id_field = field_name end end |
.index_as(index_type, opts = {}, &block) ⇒ Object
139 140 141 142 143 144 145 |
# File 'lib/solrizer/field_mapper.rb', line 139 def self.index_as(index_type, opts = {}, &block) add_instance_init_action do mapping = (@mappings[index_type] ||= IndexTypeMapping.new) mapping.opts.merge! opts yield DataTypeMappingBuilder.new(mapping) if block_given? end end |
.load_mappings(config_path = nil) ⇒ Object
Loads solr mappings from yml file. Assumes that string values are solr field name suffixes.
This is meant as a simple entry point for working with solr mappings. For more powerful control over solr mappings, create your own subclasses of FieldMapper instead of using a yml file.
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 |
# File 'lib/solrizer/field_mapper.rb', line 151 def self.load_mappings( config_path=nil ) if config_path.nil? if defined?(Rails.root) && !Rails.root.nil? config_path = File.join(Rails.root, "config", "solr_mappings.yml") end # Default to using the config file within the gem if !File.exist?(config_path.to_s) config_path = File.join(File.dirname(__FILE__), "..", "..", "config", "solr_mappings.yml") end end logger.debug("SOLRIZER: loading field name mappings from #{File.(config_path)}") mappings_from_file = YAML::load(File.open(config_path)) self.clear_mappings # Set id_field from file if it is available id_field_from_file = mappings_from_file.delete("id") if id_field_from_file.nil? id_field "id" else id_field id_field_from_file end default_index_type = mappings_from_file.delete("default") mappings_from_file.each_pair do |index_type, type_settings| if type_settings.kind_of?(Hash) index_as index_type.to_sym, :default => index_type == default_index_type do |t| type_settings.each_pair do |field_type, suffix| eval("t.#{field_type} :suffix=>\"#{suffix}\"") end end else index_as index_type.to_sym, :default => index_type == default_index_type, :suffix=>type_settings end end end |
Instance Method Details
#solr_name(field_name, field_type, index_type = :searchable) ⇒ Object
Given a specific field name, data type, and index type, returns the corresponding solr name.
227 228 229 230 |
# File 'lib/solrizer/field_mapper.rb', line 227 def solr_name(field_name, field_type, index_type = :searchable) name, mapping, data_type_mapping = solr_name_and_mappings(field_name, field_type, index_type) name end |
#solr_names_and_values(field_name, field_value, field_type, index_types) ⇒ Object
Given a field name-value pair, a data type, and an array of index types, returns a hash of mapped names and values. The values in the hash are arrays, and may contain multiple values.
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/solrizer/field_mapper.rb', line 235 def solr_names_and_values(field_name, field_value, field_type, index_types) # Determine the set of index types, adding defaults and removing not_xyz index_types ||= [] index_types += default_index_types index_types.uniq! index_types.dup.each do |index_type| if index_type.to_s =~ /^not_(.*)/ index_types.delete index_type # not_foo index_types.delete $1.to_sym # foo end end # Map names and values results = {} index_types.each do |index_type| # Get mapping for field name, mapping, data_type_mapping = solr_name_and_mappings(field_name, field_type, index_type) next unless name # Is there a custom converter? value = if data_type_mapping && data_type_mapping.converter converter = data_type_mapping.converter if converter.arity == 1 converter.call(field_value) else converter.call(field_value, field_name) end else field_value end # Add mapped name & value, unless it's a duplicate values = (results[name] ||= []) values << value unless value.nil? || values.include?(value) end results end |