solrizer 2.2.0 → 3.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/History.txt +12 -0
- data/lib/solrizer/common.rb +3 -18
- data/lib/solrizer/default_descriptors.rb +93 -0
- data/lib/solrizer/descriptor.rb +68 -0
- data/lib/solrizer/field_mapper.rb +107 -288
- data/lib/solrizer/version.rb +1 -1
- data/lib/solrizer/xml/extractor.rb +5 -5
- data/lib/solrizer/xml/terminology_based_solrizer.rb +4 -20
- data/lib/solrizer.rb +1 -1
- data/solrizer.gemspec +1 -1
- data/spec/fixtures/mods_article.rb +0 -1
- data/spec/spec_helper.rb +0 -1
- data/spec/units/common_spec.rb +8 -12
- data/spec/units/extractor_spec.rb +3 -2
- data/spec/units/field_mapper_spec.rb +177 -141
- data/spec/units/xml_extractor_spec.rb +13 -14
- data/spec/units/xml_terminology_based_solrizer_spec.rb +13 -22
- metadata +56 -33
- checksums.yaml +0 -7
- data/lib/solrizer/field_name_mapper.rb +0 -51
- data/spec/units/field_name_mapper_spec.rb +0 -28
@@ -1,58 +1,41 @@
|
|
1
1
|
require "loggable"
|
2
|
-
require 'active_support'
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
3
4
|
module Solrizer
|
4
|
-
|
5
|
+
|
6
|
+
class SolrizerError < RuntimeError; end #nodoc#
|
7
|
+
class InvalidIndexDescriptor < SolrizerError; end #nodoc#
|
8
|
+
class UnknownIndexMacro < SolrizerError; end #nodoc#
|
5
9
|
# Maps Term names and values to Solr fields, based on the Term's data type and any index_as options.
|
6
10
|
#
|
7
11
|
# The basic structure of a mapper is:
|
8
12
|
#
|
9
13
|
# == Mapping on Index Type
|
10
14
|
#
|
11
|
-
# To
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# # t.dish_name :index_as => [:searchable] -maps to-> dish_name_search
|
19
|
-
# # t.ingredients :index_as => [:searchable, :edible] -maps to-> ingredients_search, ingredients_food
|
20
|
-
#
|
21
|
-
# (See Solrizer::XML::TerminologyBasedSolrizer for instructions on applying a custom mapping once you have defined it.)
|
22
|
-
#
|
23
|
-
# == Default Index Types
|
24
|
-
#
|
25
|
-
# You can mark a particular index type as a default. It will then always be included unless terms explicity
|
26
|
-
# exclude it with the "not_" prefix:
|
27
|
-
#
|
28
|
-
# class CustomMapper < Solrizer::FieldMapper
|
29
|
-
# index_as :searchable, :suffix => '_search', :default => true
|
30
|
-
# index_as :edible, :suffix => '_food'
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# # t.dish_name -maps to-> dish_name_search
|
34
|
-
# # t.ingredients :index_as => [:edible] -maps to-> ingredients_search, ingredients_food
|
35
|
-
# # t.secret_ingredients :index_as => [:not_searchable, :edible] -maps to-> secret_ingredients_food
|
36
|
-
#
|
37
|
-
# == Mapping on Data Type
|
15
|
+
# To add a custom mapper to the default mapper
|
16
|
+
#
|
17
|
+
# module Solrizer::DefaultDescriptors
|
18
|
+
# def self.some_field_type
|
19
|
+
# @some_field_type ||= Descriptor.new(:string, :stored, :indexed, :multivalued)
|
20
|
+
# end
|
38
21
|
#
|
39
|
-
#
|
22
|
+
# # Or some totally different field:
|
23
|
+
# def self.edible
|
24
|
+
# @some_field_type ||= EdibleDescriptor.new()
|
25
|
+
# end
|
40
26
|
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# type.float :suffix => '_numeric'
|
27
|
+
# class EdibleDescriptor < Solrizer::Descriptor
|
28
|
+
# def name_and_converter(field_name, field_type)
|
29
|
+
# [field_name + '_food']
|
30
|
+
# end
|
46
31
|
# end
|
47
|
-
# index_as :edible, :suffix => '_food'
|
48
32
|
# end
|
49
33
|
#
|
50
|
-
# # t.
|
51
|
-
# # t.
|
34
|
+
# # t.dish_name :index_as => [:some_field_type] -maps to-> dish_name_ssim
|
35
|
+
# # t.ingredients :index_as => [:some_field_type, :edible] -maps to-> ingredients_ssim, ingredients_food
|
52
36
|
#
|
53
|
-
#
|
37
|
+
# (See Solrizer::XML::TerminologyBasedSolrizer for instructions on applying a custom mapping once you have defined it.)
|
54
38
|
#
|
55
|
-
# # t.description :type => :text, :index_as => [:searchable] -maps to-> description_search
|
56
39
|
#
|
57
40
|
# == Custom Value Converters
|
58
41
|
#
|
@@ -60,185 +43,130 @@ module Solrizer
|
|
60
43
|
# generation of Solr values by attaching a custom value converter block to a data type:
|
61
44
|
#
|
62
45
|
# require 'time'
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
# type.date do |value|
|
67
|
-
# Time.parse(value).utc.to_i
|
68
|
-
# end
|
46
|
+
# module Solrizer::DefaultDescriptors
|
47
|
+
# def self.searchable
|
48
|
+
# @searchable ||= SearchableDescriptor.new(:string, :stored, :indexed, :multivalued, converter: my_converter)
|
69
49
|
# end
|
70
|
-
# end
|
71
|
-
#
|
72
|
-
# Note that the nesting order is always:
|
73
|
-
#
|
74
|
-
# FieldMapper definition
|
75
|
-
# index_as
|
76
|
-
# data type
|
77
|
-
# value converter
|
78
|
-
#
|
79
|
-
# You can use the special data type "default" to apply custom value conversion to any data type:
|
80
50
|
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
# value.to_s.strip
|
51
|
+
# def self.my_converter
|
52
|
+
# lambda do |type|
|
53
|
+
# case type
|
54
|
+
# when :date
|
55
|
+
# lambda { |value| Time.parse(value).utc.to_i }
|
56
|
+
# else
|
57
|
+
# lambda { |value| value.to_s.strip }
|
58
|
+
# end
|
90
59
|
# end
|
91
60
|
# end
|
92
61
|
# end
|
93
62
|
#
|
94
63
|
# This example converts searchable dates to milliseconds, and strips extra whitespace from all other searchable data types.
|
95
64
|
#
|
96
|
-
# Note that the :suffix option may appear on the data types and the index_as. The search order for the suffix on a field
|
97
|
-
# of type foo is:
|
98
|
-
# 1. type.foo
|
99
|
-
# 2. type.default
|
100
|
-
# 3. index_as
|
101
|
-
# The suffix is optional in all three places.
|
102
|
-
#
|
103
|
-
# Note that a single Term with multiple index types can translate into multiple Solr fields, because we may want Solr to
|
104
|
-
# index a single field in multiple ways. However, if two different mappings generate both the same solr field name
|
105
|
-
# _and_ the same value, the mapper will only emit a single field.
|
106
65
|
#
|
107
66
|
# == ID Field
|
108
67
|
#
|
109
68
|
# In addition to the normal field mappings, Solrizer gives special treatment to an ID field. If you want that
|
110
69
|
# logic (and you probably do), specify a name for this field:
|
111
70
|
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
# end
|
71
|
+
# Solrizer::FieldMapper.id_field = 'id'
|
72
|
+
#
|
115
73
|
#
|
116
74
|
# == Extending the Default
|
117
75
|
#
|
118
|
-
# The default mapper is Solrizer::FieldMapper
|
76
|
+
# The default mapper is Solrizer::FieldMapper. You can customize the default mapping by subclassing it.
|
119
77
|
# For example, to override the ID field name and the default suffix for sortable, and inherit everything else:
|
120
78
|
#
|
121
|
-
# class CustomMapperBasedOnDefault < Solrizer::FieldMapper
|
122
|
-
# id_field 'guid'
|
123
|
-
#
|
79
|
+
# class CustomMapperBasedOnDefault < Solrizer::FieldMapper
|
80
|
+
# self.id_field = 'guid'
|
81
|
+
#
|
82
|
+
# module MyCustomIndexDescriptors
|
83
|
+
# def self.my_converter
|
84
|
+
# @my_converter ||= Descriptor.new(:string, :stored, :indexed, :multivalued)
|
85
|
+
# end
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# self.descriptors = [MyCustomIndexDescriptors, DefaultDescriptors]
|
124
89
|
# end
|
125
90
|
|
126
91
|
class FieldMapper
|
127
92
|
|
128
93
|
include Loggable
|
129
94
|
|
130
|
-
# ------
|
95
|
+
# ------ Instance methods ------
|
131
96
|
|
132
|
-
|
97
|
+
attr_reader :id_field, :default_index_types
|
98
|
+
class_attribute :id_field
|
99
|
+
class_attribute :descriptors
|
100
|
+
# set defaults
|
101
|
+
self.descriptors = [DefaultDescriptors]
|
102
|
+
self.id_field = 'id'
|
103
|
+
|
133
104
|
|
134
|
-
def
|
135
|
-
|
136
|
-
@id_field = field_name
|
137
|
-
end
|
105
|
+
def initialize
|
106
|
+
self.id_field = self.class.id_field
|
138
107
|
end
|
108
|
+
|
109
|
+
# Given a specific field name, data type, and index type, returns the corresponding solr name.
|
139
110
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
111
|
+
# TODO field type is the input format, maybe we could just detect that?
|
112
|
+
# @param index_type is a FieldDescriptor
|
113
|
+
def solr_name(field_name, *opts)
|
114
|
+
index_type, args = if opts.first.kind_of? Hash
|
115
|
+
[:searchable, opts.first]
|
116
|
+
elsif opts.empty?
|
117
|
+
[:searchable, {type: :text}]
|
118
|
+
else
|
119
|
+
[opts[0], opts[1] || {}]
|
145
120
|
end
|
146
|
-
end
|
147
|
-
|
148
|
-
# Loads solr mappings from yml file.
|
149
|
-
# Assumes that string values are solr field name suffixes.
|
150
|
-
# 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
|
-
# @param [String] config_path This is the path to the directory where your mappings file is stored. Defaults to "Rails.root/config/solr_mappings.yml"
|
152
|
-
def self.load_mappings( config_path=nil )
|
153
121
|
|
154
|
-
|
155
|
-
|
156
|
-
config_path = File.join(Rails.root, "config", "solr_mappings.yml")
|
157
|
-
end
|
158
|
-
# Default to using the config file within the gem
|
159
|
-
if !File.exist?(config_path.to_s)
|
160
|
-
config_path = File.join(File.dirname(__FILE__), "..", "..", "config", "solr_mappings.yml")
|
161
|
-
end
|
162
|
-
end
|
122
|
+
indexer(index_type).name_and_converter(field_name, args).first
|
123
|
+
end
|
163
124
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
self.
|
168
|
-
|
169
|
-
|
170
|
-
id_field_from_file = mappings_from_file.delete("id")
|
171
|
-
if id_field_from_file.nil?
|
172
|
-
id_field "id"
|
125
|
+
# @param index_type [Symbol]
|
126
|
+
# search through the descriptors (class attribute) until a module is found that responds to index_type, then call it.
|
127
|
+
def index_type_macro(index_type)
|
128
|
+
klass = self.class.descriptors.find { |klass| klass.respond_to? index_type}
|
129
|
+
if klass
|
130
|
+
klass.send(index_type)
|
173
131
|
else
|
174
|
-
|
132
|
+
raise UnknownIndexMacro, "Unable to find `#{index_type}' in #{self.class.descriptors}"
|
175
133
|
end
|
176
|
-
|
177
|
-
default_index_type = mappings_from_file.delete("default")
|
178
|
-
mappings_from_file.each_pair do |index_type, type_settings|
|
179
|
-
if type_settings.kind_of?(Hash)
|
180
|
-
index_as index_type.to_sym, :default => index_type == default_index_type do |t|
|
181
|
-
type_settings.each_pair do |field_type, suffix|
|
182
|
-
eval("t.#{field_type} :suffix=>\"#{suffix}\"")
|
183
|
-
end
|
184
|
-
end
|
185
|
-
else
|
186
|
-
index_as index_type.to_sym, :default => index_type == default_index_type, :suffix=>type_settings
|
187
|
-
end
|
188
|
-
end
|
189
134
|
end
|
190
135
|
|
191
|
-
#
|
192
|
-
def
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
mapper.instance_eval &block
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def self.apply_instance_init_actions(instance)
|
206
|
-
if self.superclass.respond_to? :apply_instance_init_actions
|
207
|
-
self.superclass.apply_instance_init_actions(instance)
|
208
|
-
end
|
209
|
-
@@instance_init_actions[self].each do |action|
|
210
|
-
action.call(instance)
|
136
|
+
# # @param index_type is a FieldDescriptor or a symbol that points to a method that returns a field descriptor
|
137
|
+
def indexer(index_type)
|
138
|
+
index_type = case index_type
|
139
|
+
when Symbol
|
140
|
+
index_type_macro(index_type)
|
141
|
+
when Array
|
142
|
+
raise "It's not yet supposed to be an array"
|
143
|
+
#IndexDescriptors::Descriptor.new(*index_type)
|
144
|
+
else
|
145
|
+
index_type
|
211
146
|
end
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
public
|
216
|
-
|
217
|
-
# ------ Instance methods ------
|
218
|
-
|
219
|
-
attr_reader :id_field, :default_index_types, :mappings
|
220
|
-
|
221
|
-
def initialize
|
222
|
-
@mappings = {}
|
223
|
-
self.class.apply_instance_init_actions(self)
|
224
|
-
@default_index_types = @mappings.select { |ix_type, mapping| mapping.opts[:default] }.map(&:first)
|
147
|
+
|
148
|
+
raise InvalidIndexDescriptor, "index type should be an IndexDescriptor, you passed: #{index_type}" unless index_type.kind_of? Descriptor
|
149
|
+
index_type
|
225
150
|
end
|
226
151
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
152
|
+
def extract_type(value)
|
153
|
+
case value
|
154
|
+
when NilClass
|
155
|
+
when Fixnum
|
156
|
+
:integer
|
157
|
+
else
|
158
|
+
value.class.to_s.underscore.to_sym
|
159
|
+
end
|
232
160
|
end
|
233
161
|
|
234
162
|
# Given a field name-value pair, a data type, and an array of index types, returns a hash of
|
235
163
|
# mapped names and values. The values in the hash are _arrays_, and may contain multiple values.
|
236
164
|
|
237
|
-
def solr_names_and_values(field_name, field_value,
|
238
|
-
|
165
|
+
def solr_names_and_values(field_name, field_value, index_types)
|
166
|
+
return {} unless field_value
|
239
167
|
|
168
|
+
# Determine the set of index types, adding defaults and removing not_xyz
|
240
169
|
index_types ||= []
|
241
|
-
index_types += default_index_types
|
242
170
|
index_types.uniq!
|
243
171
|
index_types.dup.each do |index_type|
|
244
172
|
if index_type.to_s =~ /^not_(.*)/
|
@@ -253,19 +181,21 @@ module Solrizer
|
|
253
181
|
|
254
182
|
index_types.each do |index_type|
|
255
183
|
# Get mapping for field
|
256
|
-
name,
|
184
|
+
name, converter = indexer(index_type).name_and_converter(field_name, type: extract_type(field_value))
|
185
|
+
#name, converter = solr_name_and_converter(field_name, index_type, field_type)
|
257
186
|
next unless name
|
258
187
|
|
259
188
|
# Is there a custom converter?
|
260
|
-
|
261
|
-
|
189
|
+
# TODO instead of a custom converter, look for input data type and output data type. Create a few methods that can do that cast.
|
190
|
+
|
191
|
+
value = if converter
|
262
192
|
if converter.arity == 1
|
263
193
|
converter.call(field_value)
|
264
194
|
else
|
265
195
|
converter.call(field_value, field_name)
|
266
196
|
end
|
267
197
|
else
|
268
|
-
field_value
|
198
|
+
field_value.to_s
|
269
199
|
end
|
270
200
|
|
271
201
|
# Add mapped name & value, unless it's a duplicate
|
@@ -275,116 +205,5 @@ module Solrizer
|
|
275
205
|
|
276
206
|
results
|
277
207
|
end
|
278
|
-
|
279
|
-
private
|
280
|
-
|
281
|
-
def solr_name_and_mappings(field_name, field_type, index_type)
|
282
|
-
field_name = field_name.to_s
|
283
|
-
mapping = @mappings[index_type]
|
284
|
-
unless mapping
|
285
|
-
logger.debug "Unknown index type '#{index_type}' for field #{field_name}"
|
286
|
-
return nil
|
287
|
-
end
|
288
|
-
|
289
|
-
data_type_mapping = mapping.data_types[field_type] || mapping.data_types[:default]
|
290
|
-
|
291
|
-
suffix = data_type_mapping.opts[:suffix] if data_type_mapping
|
292
|
-
suffix ||= mapping.opts[:suffix]
|
293
|
-
name = field_name + suffix
|
294
|
-
|
295
|
-
[name, mapping, data_type_mapping]
|
296
|
-
end
|
297
|
-
|
298
|
-
class IndexTypeMapping
|
299
|
-
attr_accessor :opts, :data_types
|
300
|
-
|
301
|
-
def initialize
|
302
|
-
@opts = {}
|
303
|
-
@data_types = {}
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
class DataTypeMapping
|
308
|
-
attr_accessor :opts, :converter
|
309
|
-
|
310
|
-
def initialize
|
311
|
-
@opts = {}
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
class DataTypeMappingBuilder
|
316
|
-
def initialize(index_type_mapping)
|
317
|
-
@index_type_mapping = index_type_mapping
|
318
|
-
end
|
319
|
-
|
320
|
-
def method_missing(method, *args, &block)
|
321
|
-
data_type_mapping = (@index_type_mapping.data_types[method] ||= DataTypeMapping.new)
|
322
|
-
data_type_mapping.opts.merge! args[0] if args.length > 0
|
323
|
-
data_type_mapping.converter = block if block_given?
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
# ------ Default mapper ------
|
328
|
-
|
329
|
-
public
|
330
|
-
|
331
|
-
module Defaults
|
332
|
-
extend ActiveSupport::Concern
|
333
|
-
included do
|
334
|
-
id_field 'id'
|
335
|
-
index_as :searchable do |t|
|
336
|
-
t.default :suffix => '_t'
|
337
|
-
t.date :suffix => '_dt' do |value|
|
338
|
-
iso8601_date(value)
|
339
|
-
end
|
340
|
-
t.string :suffix => '_t'
|
341
|
-
t.text :suffix => '_t'
|
342
|
-
t.symbol :suffix => '_s'
|
343
|
-
t.integer :suffix => '_i'
|
344
|
-
t.long :suffix => '_l'
|
345
|
-
t.boolean :suffix => '_b'
|
346
|
-
t.float :suffix => '_f'
|
347
|
-
t.double :suffix => '_d'
|
348
|
-
end
|
349
|
-
index_as :displayable, :suffix => '_display' do |t|
|
350
|
-
t.date do |value|
|
351
|
-
value.to_s
|
352
|
-
end
|
353
|
-
end
|
354
|
-
index_as :facetable, :suffix => '_facet' do |t|
|
355
|
-
t.date do |value|
|
356
|
-
value.to_s
|
357
|
-
end
|
358
|
-
end
|
359
|
-
|
360
|
-
index_as :sortable, :suffix => '_sort' do |t|
|
361
|
-
t.date do |value|
|
362
|
-
value.to_s
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
index_as :unstemmed_searchable, :suffix => '_unstem_search'
|
367
|
-
end
|
368
|
-
end
|
369
|
-
|
370
|
-
class Default < FieldMapper
|
371
|
-
include Defaults
|
372
|
-
end
|
373
|
-
|
374
|
-
protected
|
375
|
-
|
376
|
-
def self.iso8601_date(value)
|
377
|
-
begin
|
378
|
-
if value.is_a?(Date)
|
379
|
-
DateTime.parse(value.to_s).to_time.utc.iso8601
|
380
|
-
elsif !value.empty?
|
381
|
-
DateTime.parse(value).to_time.utc.iso8601
|
382
|
-
end
|
383
|
-
rescue ArgumentError => e
|
384
|
-
raise ArgumentError, "Unable to parse `#{value}' as a date-time object"
|
385
|
-
end
|
386
|
-
end
|
387
|
-
|
388
208
|
end
|
389
|
-
|
390
209
|
end
|
data/lib/solrizer/version.rb
CHANGED
@@ -8,21 +8,21 @@ module Solrizer::XML::Extractor
|
|
8
8
|
#
|
9
9
|
# @param [xml] text xml content to index
|
10
10
|
# @param [Hash] solr_doc
|
11
|
-
def xml_to_solr( text, solr_doc=Hash.new )
|
11
|
+
def xml_to_solr( text, solr_doc=Hash.new, mapper = Solrizer.default_field_mapper )
|
12
12
|
doc = XmlSimple.xml_in( text )
|
13
13
|
|
14
14
|
doc.each_pair do |name, value|
|
15
15
|
if value.kind_of?(Array)
|
16
16
|
if value.first.kind_of?(Hash)
|
17
17
|
# This deals with the way xml-simple handles nodes with attributes
|
18
|
-
solr_doc.merge!({
|
18
|
+
solr_doc.merge!({mapper.solr_name(name, :searchable, :type=>:text).to_sym => "#{value.first["content"]}"})
|
19
19
|
elsif value.length > 1
|
20
|
-
solr_doc.merge!({
|
20
|
+
solr_doc.merge!({mapper.solr_name(name, :searchable, :type=>:text).to_sym => value})
|
21
21
|
else
|
22
|
-
solr_doc.merge!({
|
22
|
+
solr_doc.merge!({mapper.solr_name(name, :searchable, :type=>:text).to_sym => "#{value.first}"})
|
23
23
|
end
|
24
24
|
else
|
25
|
-
solr_doc.merge!({
|
25
|
+
solr_doc.merge!({mapper.solr_name(name, :searchable, :type=>:text).to_sym => "#{value}"})
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -35,17 +35,10 @@ module Solrizer::XML::TerminologyBasedSolrizer
|
|
35
35
|
nodeset = doc.term_values(*term_pointer)
|
36
36
|
|
37
37
|
nodeset.each do |n|
|
38
|
-
|
39
|
-
# TODO: Solrizer::FieldMapper::Default is supposed to translate dates into full ISO 8601 formatted strings.
|
40
|
-
# However, there an integration issue with ActiveFedora using OM: it ignores the default field mapper given
|
41
|
-
# in this gem that does this. So, the following is a workaround until it is fixed.
|
42
|
-
node = n.is_a?(Date) ? DateTime.parse(n.to_s).to_time.utc.iso8601 : n.to_s
|
43
|
-
|
44
|
-
doc.solrize_node(node.to_s, term_pointer, term, solr_doc, field_mapper)
|
38
|
+
doc.solrize_node(n, term_pointer, term, solr_doc, field_mapper)
|
45
39
|
unless term.kind_of? OM::XML::NamedTermProxy
|
46
40
|
term.children.each_pair do |child_term_name, child_term|
|
47
|
-
|
48
|
-
doc.solrize_term(child_term, solr_doc, field_mapper, opts={:parents=>parents+[{term.name=>nodeset.index(node.to_s)}]})
|
41
|
+
doc.solrize_term(child_term, solr_doc, field_mapper, opts={:parents=>parents+[{term.name=>nodeset.index(n)}]})
|
49
42
|
end
|
50
43
|
end
|
51
44
|
end
|
@@ -63,26 +56,17 @@ module Solrizer::XML::TerminologyBasedSolrizer
|
|
63
56
|
# @return [Hash] the solr doc
|
64
57
|
def solrize_node(node_value, doc, term_pointer, term, solr_doc = Hash.new, field_mapper = nil, opts = {})
|
65
58
|
return solr_doc unless term.index_as && !term.index_as.empty?
|
66
|
-
|
67
|
-
directive = term_to_solrizer_directive(term)
|
68
59
|
|
69
60
|
generic_field_name_base = OM::XML::Terminology.term_generic_name(*term_pointer)
|
70
|
-
create_and_insert_terms(generic_field_name_base, node_value,
|
71
|
-
|
61
|
+
create_and_insert_terms(generic_field_name_base, node_value, term.index_as, solr_doc)
|
72
62
|
|
73
63
|
if term_pointer.length > 1
|
74
64
|
hierarchical_field_name_base = OM::XML::Terminology.term_hierarchical_name(*term_pointer)
|
75
|
-
create_and_insert_terms(hierarchical_field_name_base, node_value,
|
65
|
+
create_and_insert_terms(hierarchical_field_name_base, node_value, term.index_as, solr_doc)
|
76
66
|
end
|
77
67
|
solr_doc
|
78
68
|
end
|
79
69
|
|
80
|
-
private
|
81
|
-
|
82
|
-
def term_to_solrizer_directive(term)
|
83
|
-
Solrizer::Directive.new(term.type, term.index_as)
|
84
|
-
end
|
85
|
-
|
86
70
|
end
|
87
71
|
|
88
72
|
|
data/lib/solrizer.rb
CHANGED
data/solrizer.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.add_dependency "stomp"
|
20
20
|
s.add_dependency "daemons"
|
21
21
|
s.add_dependency "activesupport"
|
22
|
-
s.add_development_dependency 'rspec'
|
22
|
+
s.add_development_dependency 'rspec'
|
23
23
|
s.add_development_dependency 'rake'
|
24
24
|
s.add_development_dependency 'yard'
|
25
25
|
s.add_development_dependency 'RedCloth' # yard depends on redcloth
|
@@ -76,7 +76,6 @@ module Samples
|
|
76
76
|
t.url(:path=>"url")
|
77
77
|
}
|
78
78
|
t.publication_url(:proxy=>[:location,:url])
|
79
|
-
t.root_title(:proxy => [:mods, :title_info, :main_title], :index_as => [:searchable])
|
80
79
|
t.title(:proxy=>[:title_info, :main_title])
|
81
80
|
t.journal_title(:proxy=>[:journal, :title_info, :main_title])
|
82
81
|
t.pub_date(:proxy=>[:journal, :issue, :publication_date])
|
data/spec/spec_helper.rb
CHANGED
data/spec/units/common_spec.rb
CHANGED
@@ -12,28 +12,24 @@ describe Solrizer::Common do
|
|
12
12
|
|
13
13
|
it "should handle many field types" do
|
14
14
|
solr_doc = {}
|
15
|
-
|
16
|
-
|
17
|
-
solr_doc.should == {'my_name_t' => ['value'], 'my_name_sort' => ['value'], 'my_name_display' => ['value']}
|
15
|
+
Foo.create_and_insert_terms('my_name', 'value', [:displayable, :searchable, :sortable], solr_doc)
|
16
|
+
solr_doc.should == {'my_name_ssm' => ['value'], 'my_name_ssi' => ['value'], 'my_name_tesim' => ['value']}
|
18
17
|
end
|
19
18
|
it "should handle dates that are searchable" do
|
20
19
|
solr_doc = {}
|
21
|
-
|
22
|
-
|
23
|
-
solr_doc.should == {'my_name_dt' => ['2013-01-10T00:00:00Z']}
|
20
|
+
Foo.create_and_insert_terms('my_name', Date.parse('2013-01-10'), [:searchable], solr_doc)
|
21
|
+
solr_doc.should == {'my_name_dtsi' => ['2013-01-10T00:00:00Z']}
|
24
22
|
end
|
25
23
|
|
26
24
|
it "should handle dates that are displayable" do
|
27
25
|
solr_doc = {}
|
28
|
-
|
29
|
-
|
30
|
-
solr_doc.should == {'my_name_display' => ['2013-01-10']}
|
26
|
+
Foo.create_and_insert_terms('my_name', Date.parse('2013-01-10'), [:displayable], solr_doc)
|
27
|
+
solr_doc.should == {'my_name_ssm' => ['2013-01-10']}
|
31
28
|
end
|
32
29
|
|
33
30
|
it "should handle dates that are sortable" do
|
34
31
|
solr_doc = {}
|
35
|
-
|
36
|
-
|
37
|
-
solr_doc.should == {'my_name_sort' => ['2013-01-10']}
|
32
|
+
Foo.create_and_insert_terms('my_name', Date.parse('2013-01-10'), [:sortable], solr_doc)
|
33
|
+
solr_doc.should == {'my_name_ssi' => ['2013-01-10']}
|
38
34
|
end
|
39
35
|
end
|
@@ -22,8 +22,9 @@ describe Solrizer::Extractor do
|
|
22
22
|
|
23
23
|
describe "#insert_solr_field_value" do
|
24
24
|
it "should initialize a solr doc list if it is nil" do
|
25
|
-
solr_doc = {'
|
26
|
-
Solrizer::Extractor.insert_solr_field_value(solr_doc, '
|
25
|
+
solr_doc = {'title_tesim' => nil }
|
26
|
+
Solrizer::Extractor.insert_solr_field_value(solr_doc, 'title_tesim', 'Frank')
|
27
|
+
solr_doc.should == {"title_tesim"=>["Frank"]}
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|