ssickles-tire 0.4.2.7 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/tire.rb +18 -3
- data/lib/tire/alias.rb +11 -35
- data/lib/tire/index.rb +34 -76
- data/lib/tire/model/callbacks.rb +40 -0
- data/lib/tire/model/import.rb +26 -0
- data/lib/tire/model/indexing.rb +128 -0
- data/lib/tire/model/naming.rb +100 -0
- data/lib/tire/model/percolate.rb +99 -0
- data/lib/tire/model/persistence.rb +72 -0
- data/lib/tire/model/persistence/attributes.rb +143 -0
- data/lib/tire/model/persistence/finders.rb +66 -0
- data/lib/tire/model/persistence/storage.rb +71 -0
- data/lib/tire/model/search.rb +305 -0
- data/lib/tire/results/collection.rb +38 -13
- data/lib/tire/results/item.rb +19 -0
- data/lib/tire/rubyext/hash.rb +8 -0
- data/lib/tire/rubyext/ruby_1_8.rb +54 -0
- data/lib/tire/rubyext/symbol.rb +11 -0
- data/lib/tire/search.rb +7 -8
- data/lib/tire/search/scan.rb +8 -8
- data/lib/tire/search/sort.rb +1 -1
- data/lib/tire/utils.rb +17 -0
- data/lib/tire/version.rb +7 -38
- data/test/integration/active_model_indexing_test.rb +51 -0
- data/test/integration/active_model_searchable_test.rb +114 -0
- data/test/integration/active_record_searchable_test.rb +446 -0
- data/test/integration/mongoid_searchable_test.rb +309 -0
- data/test/integration/persistent_model_test.rb +117 -0
- data/test/integration/reindex_test.rb +2 -2
- data/test/integration/scan_test.rb +1 -1
- data/test/models/active_model_article.rb +31 -0
- data/test/models/active_model_article_with_callbacks.rb +49 -0
- data/test/models/active_model_article_with_custom_document_type.rb +7 -0
- data/test/models/active_model_article_with_custom_index_name.rb +7 -0
- data/test/models/active_record_models.rb +122 -0
- data/test/models/mongoid_models.rb +97 -0
- data/test/models/persistent_article.rb +11 -0
- data/test/models/persistent_article_in_namespace.rb +12 -0
- data/test/models/persistent_article_with_casting.rb +28 -0
- data/test/models/persistent_article_with_defaults.rb +11 -0
- data/test/models/persistent_articles_with_custom_index_name.rb +10 -0
- data/test/models/supermodel_article.rb +17 -0
- data/test/models/validated_model.rb +11 -0
- data/test/test_helper.rb +27 -3
- data/test/unit/active_model_lint_test.rb +17 -0
- data/test/unit/index_alias_test.rb +3 -17
- data/test/unit/index_test.rb +30 -18
- data/test/unit/model_callbacks_test.rb +116 -0
- data/test/unit/model_import_test.rb +71 -0
- data/test/unit/model_persistence_test.rb +516 -0
- data/test/unit/model_search_test.rb +899 -0
- data/test/unit/results_collection_test.rb +60 -0
- data/test/unit/results_item_test.rb +37 -0
- data/test/unit/rubyext_test.rb +3 -3
- data/test/unit/search_test.rb +1 -6
- data/test/unit/tire_test.rb +15 -0
- data/tire.gemspec +30 -13
- metadata +153 -41
- data/lib/tire/rubyext/to_json.rb +0 -21
data/lib/tire.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
require 'rest_client'
|
2
2
|
require 'multi_json'
|
3
|
+
#require 'active_model'
|
3
4
|
require 'hashr'
|
4
5
|
require 'cgi'
|
5
|
-
require 'escape_utils'
|
6
6
|
|
7
|
-
require 'active_support
|
7
|
+
require 'active_support'
|
8
8
|
|
9
|
-
|
9
|
+
# Ruby 1.8 compatibility
|
10
|
+
require 'tire/rubyext/ruby_1_8' if defined?(RUBY_VERSION) && RUBY_VERSION < '1.9'
|
11
|
+
|
12
|
+
require 'tire/rubyext/hash'
|
13
|
+
require 'tire/rubyext/symbol'
|
14
|
+
require 'tire/utils'
|
10
15
|
require 'tire/logger'
|
11
16
|
require 'tire/configuration'
|
12
17
|
require 'tire/http/response'
|
@@ -24,6 +29,16 @@ require 'tire/results/item'
|
|
24
29
|
require 'tire/index'
|
25
30
|
require 'tire/alias'
|
26
31
|
require 'tire/dsl'
|
32
|
+
require 'tire/model/naming'
|
33
|
+
require 'tire/model/callbacks'
|
34
|
+
require 'tire/model/percolate'
|
35
|
+
require 'tire/model/indexing'
|
36
|
+
require 'tire/model/import'
|
37
|
+
require 'tire/model/search'
|
38
|
+
require 'tire/model/persistence/finders'
|
39
|
+
require 'tire/model/persistence/attributes'
|
40
|
+
require 'tire/model/persistence/storage'
|
41
|
+
require 'tire/model/persistence'
|
27
42
|
require 'tire/tasks'
|
28
43
|
|
29
44
|
module Tire
|
data/lib/tire/alias.rb
CHANGED
@@ -74,7 +74,6 @@ module Tire
|
|
74
74
|
def initialize(attributes={}, &block)
|
75
75
|
raise ArgumentError, "Please pass a Hash-like object" unless attributes.respond_to?(:each_pair)
|
76
76
|
|
77
|
-
@url = attributes.delete(:url) || Configuration.url
|
78
77
|
@attributes = { :indices => IndexCollection.new([]) }
|
79
78
|
|
80
79
|
attributes.each_pair do |key, value|
|
@@ -88,57 +87,34 @@ module Tire
|
|
88
87
|
block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
|
89
88
|
end
|
90
89
|
|
91
|
-
attr_accessor :url
|
92
|
-
|
93
90
|
# Returns a collection of Tire::Alias objects for all aliases defined in the cluster, or for a specific index.
|
94
91
|
#
|
95
|
-
def self.all(
|
96
|
-
|
97
|
-
index, url = url, Configuration.url
|
98
|
-
elsif url.nil?
|
99
|
-
url = Configuration.url
|
100
|
-
end
|
92
|
+
def self.all(index=nil)
|
93
|
+
@response = Configuration.client.get [Configuration.url, index, '_aliases'].compact.join('/')
|
101
94
|
|
102
|
-
|
103
|
-
|
104
|
-
aliases = MultiJson.decode(@response.body).inject({}) do |result, (name, value)|
|
95
|
+
aliases = MultiJson.decode(@response.body).inject({}) do |result, (index, value)|
|
105
96
|
# 1] Skip indices without aliases
|
106
97
|
next result if value['aliases'].empty?
|
107
98
|
|
108
99
|
# 2] Build a reverse map of hashes (alias => indices, config)
|
109
|
-
value['aliases'].each do |key,
|
100
|
+
value['aliases'].each do |key, value| (result[key] ||= { 'indices' => [] }).update(value)['indices'].push(index) end
|
110
101
|
result
|
111
102
|
end
|
112
103
|
|
113
104
|
# 3] Build a collection of Alias objects from hashes
|
114
105
|
aliases.map do |key, value|
|
115
|
-
self.new(value.update('name' => key
|
106
|
+
self.new(value.update('name' => key))
|
116
107
|
end
|
117
108
|
|
118
109
|
ensure
|
119
110
|
# FIXME: Extract the `logged` method
|
120
|
-
Alias.new.logged '_aliases', %Q|curl "#{url}/_aliases"|
|
111
|
+
Alias.new.logged '_aliases', %Q|curl "#{Configuration.url}/_aliases"|
|
121
112
|
end
|
122
113
|
|
123
114
|
# Returns an alias by name
|
124
115
|
#
|
125
|
-
|
126
|
-
|
127
|
-
# Alias.find( url, name )
|
128
|
-
# Alias.find( name )
|
129
|
-
#
|
130
|
-
def self.find(*args, &block)
|
131
|
-
case args.length
|
132
|
-
when 2
|
133
|
-
url, name = args
|
134
|
-
when 1
|
135
|
-
url = Configuration.url
|
136
|
-
name = args.first
|
137
|
-
else
|
138
|
-
raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
|
139
|
-
end
|
140
|
-
|
141
|
-
a = all(url).select { |b| b.name == name }.first
|
116
|
+
def self.find(name, &block)
|
117
|
+
a = all.select { |a| a.name == name }.first
|
142
118
|
block.call(a) if block_given?
|
143
119
|
return a
|
144
120
|
end
|
@@ -183,10 +159,10 @@ module Tire
|
|
183
159
|
# Save the alias in _ElasticSearch_
|
184
160
|
#
|
185
161
|
def save
|
186
|
-
@response = Configuration.client.post "#{url}/_aliases", to_json
|
162
|
+
@response = Configuration.client.post "#{Configuration.url}/_aliases", to_json
|
187
163
|
|
188
164
|
ensure
|
189
|
-
logged '_aliases', %Q|curl -X POST "#{url}/_aliases" -d '#{to_json}'|
|
165
|
+
logged '_aliases', %Q|curl -X POST "#{Configuration.url}/_aliases" -d '#{to_json}'|
|
190
166
|
end
|
191
167
|
|
192
168
|
# Return a Hash suitable for JSON serialization
|
@@ -211,7 +187,7 @@ module Tire
|
|
211
187
|
# Return alias serialized in JSON for _ElasticSearch_
|
212
188
|
#
|
213
189
|
def to_json(options=nil)
|
214
|
-
|
190
|
+
as_json.to_json
|
215
191
|
end
|
216
192
|
|
217
193
|
def inspect
|
data/lib/tire/index.rb
CHANGED
@@ -1,27 +1,15 @@
|
|
1
1
|
module Tire
|
2
2
|
class Index
|
3
3
|
|
4
|
-
attr_reader :name, :response
|
5
|
-
|
6
|
-
def initialize(*args, &block)
|
7
|
-
case args.length
|
8
|
-
when 2
|
9
|
-
@name = args.last
|
10
|
-
self.url = args.first
|
11
|
-
when 1
|
12
|
-
@name = args.first
|
13
|
-
self.url = Configuration.url
|
14
|
-
else
|
15
|
-
raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
|
16
|
-
end
|
4
|
+
attr_reader :name, :response
|
17
5
|
|
6
|
+
def initialize(name, &block)
|
7
|
+
@name = name
|
18
8
|
block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
|
19
9
|
end
|
20
10
|
|
21
|
-
def url
|
22
|
-
@
|
23
|
-
@url = "#@base_url/#@name"
|
24
|
-
@percolator_url = "#@base_url/_percolator/#@name"
|
11
|
+
def url
|
12
|
+
"#{Configuration.url}/#{@name}"
|
25
13
|
end
|
26
14
|
|
27
15
|
def exists?
|
@@ -53,15 +41,15 @@ module Tire
|
|
53
41
|
end
|
54
42
|
|
55
43
|
def add_alias(alias_name, configuration={})
|
56
|
-
Alias.create(configuration.merge( :name => alias_name, :index => @name
|
44
|
+
Alias.create(configuration.merge( :name => alias_name, :index => @name ) )
|
57
45
|
end
|
58
46
|
|
59
47
|
def remove_alias(alias_name)
|
60
|
-
Alias.find(
|
48
|
+
Alias.find(alias_name) { |a| a.indices.delete @name }.save
|
61
49
|
end
|
62
50
|
|
63
51
|
def aliases(alias_name=nil)
|
64
|
-
alias_name ? Alias.all(@
|
52
|
+
alias_name ? Alias.all(@name).select { |a| a.name == alias_name }.first : Alias.all(@name)
|
65
53
|
end
|
66
54
|
|
67
55
|
def mapping
|
@@ -75,24 +63,23 @@ module Tire
|
|
75
63
|
end
|
76
64
|
|
77
65
|
def store(*args)
|
78
|
-
document,
|
79
|
-
|
80
|
-
type = get_type_from_document(document)
|
81
|
-
routing = get_routing_from_document(document)
|
82
|
-
parent = get_parent_from_document(document)
|
83
|
-
|
84
|
-
params ||= {}
|
85
|
-
params[:routing] = routing if routing
|
86
|
-
params[:parent] = parent if parent
|
87
|
-
params[:percolate] = '*' if params[:percolate] === true
|
66
|
+
document, options = args
|
67
|
+
type = get_type_from_document(document)
|
88
68
|
|
89
|
-
|
90
|
-
|
69
|
+
if options
|
70
|
+
percolate = options[:percolate]
|
71
|
+
percolate = "*" if percolate === true
|
72
|
+
end
|
91
73
|
|
74
|
+
id = get_id_from_document(document)
|
92
75
|
document = convert_document_to_json(document)
|
93
76
|
|
77
|
+
url = id ? "#{self.url}/#{type}/#{id}" : "#{self.url}/#{type}/"
|
78
|
+
url += "?percolate=#{percolate}" if percolate
|
79
|
+
|
94
80
|
@response = Configuration.client.post url, document
|
95
81
|
MultiJson.decode(@response.body)
|
82
|
+
|
96
83
|
ensure
|
97
84
|
curl = %Q|curl -X POST "#{url}" -d '#{document}'|
|
98
85
|
logged([type, id].join('/'), curl)
|
@@ -172,7 +159,7 @@ module Tire
|
|
172
159
|
def remove(*args)
|
173
160
|
if args.size > 1
|
174
161
|
type, document = args
|
175
|
-
type =
|
162
|
+
type = Utils.escape(type)
|
176
163
|
id = get_id_from_document(document) || document
|
177
164
|
else
|
178
165
|
document = args.pop
|
@@ -181,25 +168,20 @@ module Tire
|
|
181
168
|
end
|
182
169
|
raise ArgumentError, "Please pass a document ID" unless id
|
183
170
|
|
184
|
-
|
185
|
-
|
186
|
-
url = "#{self.url}/#{type}/#{id}"
|
187
|
-
url << "?routing=#{EscapeUtils.escape_url(routing)}" if routing
|
188
|
-
|
171
|
+
url = "#{self.url}/#{type}/#{id}"
|
189
172
|
result = Configuration.client.delete url
|
190
173
|
MultiJson.decode(result.body) if result.success?
|
174
|
+
|
191
175
|
ensure
|
192
176
|
curl = %Q|curl -X DELETE "#{url}"|
|
193
177
|
logged(id, curl)
|
194
178
|
end
|
195
179
|
|
196
|
-
def retrieve(type, id
|
180
|
+
def retrieve(type, id)
|
197
181
|
raise ArgumentError, "Please pass a document ID" unless id
|
198
182
|
|
199
|
-
type
|
200
|
-
url
|
201
|
-
url << "?#{params.to_param}" unless params.empty?
|
202
|
-
|
183
|
+
type = Utils.escape(type)
|
184
|
+
url = "#{self.url}/#{type}/#{id}"
|
203
185
|
@response = Configuration.client.get url
|
204
186
|
|
205
187
|
h = MultiJson.decode(@response.body)
|
@@ -257,22 +239,20 @@ module Tire
|
|
257
239
|
def register_percolator_query(name, options={}, &block)
|
258
240
|
options[:query] = Search::Query.new(&block).to_hash if block_given?
|
259
241
|
|
260
|
-
|
261
|
-
@response = Configuration.client.put url, MultiJson.encode(options)
|
242
|
+
@response = Configuration.client.put "#{Configuration.url}/_percolator/#{@name}/#{name}", MultiJson.encode(options)
|
262
243
|
MultiJson.decode(@response.body)['ok']
|
263
244
|
|
264
245
|
ensure
|
265
|
-
curl = %Q|curl -X PUT "#{url}
|
246
|
+
curl = %Q|curl -X PUT "#{Configuration.url}/_percolator/#{@name}/?pretty=1" -d '#{MultiJson.encode(options)}'|
|
266
247
|
logged('_percolator', curl)
|
267
248
|
end
|
268
249
|
|
269
250
|
def unregister_percolator_query(name)
|
270
|
-
|
271
|
-
@response = Configuration.client.delete url
|
251
|
+
@response = Configuration.client.delete "#{Configuration.url}/_percolator/#{@name}/#{name}"
|
272
252
|
MultiJson.decode(@response.body)['ok']
|
273
253
|
|
274
254
|
ensure
|
275
|
-
curl = %Q|curl -X DELETE "#{url}"|
|
255
|
+
curl = %Q|curl -X DELETE "#{Configuration.url}/_percolator/#{@name}"|
|
276
256
|
logged('_percolator', curl)
|
277
257
|
end
|
278
258
|
|
@@ -322,10 +302,10 @@ module Tire
|
|
322
302
|
|
323
303
|
old_verbose, $VERBOSE = $VERBOSE, nil # Silence Object#type deprecation warnings
|
324
304
|
type = case
|
325
|
-
when document.is_a?(Hash)
|
326
|
-
document.delete(:_type) || document.delete('_type') || document[:type] || document['type']
|
327
305
|
when document.respond_to?(:document_type)
|
328
306
|
document.document_type
|
307
|
+
when document.is_a?(Hash)
|
308
|
+
document[:_type] || document['_type'] || document[:type] || document['type']
|
329
309
|
when document.respond_to?(:_type)
|
330
310
|
document._type
|
331
311
|
when document.respond_to?(:type) && document.type != document.class
|
@@ -333,15 +313,15 @@ module Tire
|
|
333
313
|
end
|
334
314
|
$VERBOSE = old_verbose
|
335
315
|
|
336
|
-
type
|
337
|
-
options[:escape] ?
|
316
|
+
type ||= 'document'
|
317
|
+
options[:escape] ? Utils.escape(type) : type
|
338
318
|
end
|
339
319
|
|
340
320
|
def get_id_from_document(document)
|
341
321
|
old_verbose, $VERBOSE = $VERBOSE, nil # Silence Object#id deprecation warnings
|
342
322
|
id = case
|
343
323
|
when document.is_a?(Hash)
|
344
|
-
document
|
324
|
+
document[:_id] || document['_id'] || document[:id] || document['id']
|
345
325
|
when document.respond_to?(:id) && document.id != document.object_id
|
346
326
|
document.id
|
347
327
|
end
|
@@ -349,28 +329,6 @@ module Tire
|
|
349
329
|
id
|
350
330
|
end
|
351
331
|
|
352
|
-
def get_routing_from_document(document)
|
353
|
-
case
|
354
|
-
when document.is_a?(Hash)
|
355
|
-
document.delete(:_routing) || document.delete('_routing')
|
356
|
-
when document.respond_to?(:routing)
|
357
|
-
document.routing
|
358
|
-
when document.respond_to?(:_routing)
|
359
|
-
document._routing
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
def get_parent_from_document(document)
|
364
|
-
case
|
365
|
-
when document.is_a?(Hash)
|
366
|
-
document.delete(:_parent) || document.delete('_parent')
|
367
|
-
when document.respond_to?(:parent)
|
368
|
-
document.parent
|
369
|
-
when document.respond_to?(:_parent)
|
370
|
-
document._parent
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
332
|
def convert_document_to_json(document)
|
375
333
|
document = case
|
376
334
|
when document.is_a?(String)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Tire
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Main module containing the infrastructure for automatic updating
|
5
|
+
# of the _ElasticSearch_ index on model instance create, update or delete.
|
6
|
+
#
|
7
|
+
# Include it in your model: `include Tire::Model::Callbacks`
|
8
|
+
#
|
9
|
+
# The model must respond to `after_save` and `after_destroy` callbacks
|
10
|
+
# (ActiveModel and ActiveRecord models do so, by default).
|
11
|
+
#
|
12
|
+
module Callbacks
|
13
|
+
|
14
|
+
# A hook triggered by the `include Tire::Model::Callbacks` statement in the model.
|
15
|
+
#
|
16
|
+
def self.included(base)
|
17
|
+
# Update index on model instance change or destroy.
|
18
|
+
#
|
19
|
+
if base.respond_to?(:after_save) && base.respond_to?(:after_destroy)
|
20
|
+
base.class_eval do
|
21
|
+
after_save lambda { tire.update_index }
|
22
|
+
after_destroy lambda { tire.update_index }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Add neccessary infrastructure for the model, when missing in
|
27
|
+
# some half-baked ActiveModel implementations.
|
28
|
+
#
|
29
|
+
if base.respond_to?(:before_destroy) && !base.instance_methods.map(&:to_sym).include?(:destroyed?)
|
30
|
+
base.class_eval do
|
31
|
+
before_destroy { @destroyed = true }
|
32
|
+
def destroyed?; !!@destroyed; end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
module Tire
|
3
|
+
module Model
|
4
|
+
|
5
|
+
# Provides support for easy importing of large ActiveRecord- and ActiveModel-bound
|
6
|
+
# recordsets into model index.
|
7
|
+
#
|
8
|
+
# Relies on pagination support in your model, namely the `paginate` class method.
|
9
|
+
#
|
10
|
+
# Please refer to the relevant of the README for more information.
|
11
|
+
#
|
12
|
+
module Import
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
def import options={}, &block
|
17
|
+
options = { :method => 'paginate' }.update options
|
18
|
+
index.import klass, options, &block
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Tire
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Contains logic for definition of index settings and mappings.
|
5
|
+
#
|
6
|
+
module Indexing
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
# Define [_settings_](http://www.elasticsearch.org/guide/reference/api/admin-indices-create-index.html)
|
11
|
+
# for the corresponding index, such as number of shards and replicas, custom analyzers, etc.
|
12
|
+
#
|
13
|
+
# Usage:
|
14
|
+
#
|
15
|
+
# class Article
|
16
|
+
# # ...
|
17
|
+
# settings :number_of_shards => 1 do
|
18
|
+
# mapping do
|
19
|
+
# # ...
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
def settings(*args)
|
25
|
+
@settings ||= {}
|
26
|
+
args.empty? ? (return @settings) : @settings = args.pop
|
27
|
+
yield if block_given?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Define the [_mapping_](http://www.elasticsearch.org/guide/reference/mapping/index.html)
|
31
|
+
# for the corresponding index, telling _ElasticSearch_ how to understand your documents:
|
32
|
+
# what type is which property, whether it is analyzed or no, which analyzer to use, etc.
|
33
|
+
#
|
34
|
+
# You may pass the top level mapping properties (such as `_source` or `_all`) as a Hash.
|
35
|
+
#
|
36
|
+
# Usage:
|
37
|
+
#
|
38
|
+
# class Article
|
39
|
+
# # ...
|
40
|
+
# mapping :_source => { :compress => true } do
|
41
|
+
# indexes :id, :index => :not_analyzed
|
42
|
+
# indexes :title, :analyzer => 'snowball', :boost => 100
|
43
|
+
# indexes :words, :as => 'content.split(/\W/).length'
|
44
|
+
#
|
45
|
+
# indexes :comments do
|
46
|
+
# indexes :body
|
47
|
+
# indexes :author do
|
48
|
+
# indexes :name
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# # ...
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
def mapping(*args)
|
57
|
+
@mapping ||= {}
|
58
|
+
if block_given?
|
59
|
+
@mapping_options = args.pop
|
60
|
+
yield
|
61
|
+
create_elasticsearch_index
|
62
|
+
else
|
63
|
+
@mapping
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Define mapping for the property passed as the first argument (`name`)
|
68
|
+
# using definition from the second argument (`options`).
|
69
|
+
#
|
70
|
+
# `:type` is optional and defaults to `'string'`.
|
71
|
+
#
|
72
|
+
# Usage:
|
73
|
+
#
|
74
|
+
# * Index property but do not analyze it: `indexes :id, :index => :not_analyzed`
|
75
|
+
#
|
76
|
+
# * Use different analyzer for indexing a property: `indexes :title, :analyzer => 'snowball'`
|
77
|
+
#
|
78
|
+
# * Use the `:as` option to dynamically define the serialized property value, eg:
|
79
|
+
#
|
80
|
+
# :as => 'content.split(/\W/).length'
|
81
|
+
#
|
82
|
+
# Please refer to the
|
83
|
+
# [_mapping_ documentation](http://www.elasticsearch.org/guide/reference/mapping/index.html)
|
84
|
+
# for more information.
|
85
|
+
#
|
86
|
+
def indexes(name, options = {}, &block)
|
87
|
+
mapping[name] = options
|
88
|
+
|
89
|
+
if block_given?
|
90
|
+
mapping[name][:type] ||= 'object'
|
91
|
+
mapping[name][:properties] ||= {}
|
92
|
+
|
93
|
+
previous = @mapping
|
94
|
+
@mapping = mapping[name][:properties]
|
95
|
+
yield
|
96
|
+
@mapping = previous
|
97
|
+
end
|
98
|
+
|
99
|
+
mapping[name][:type] ||= 'string'
|
100
|
+
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
# Creates the corresponding index with desired settings and mappings, when it does not exists yet.
|
105
|
+
#
|
106
|
+
def create_elasticsearch_index
|
107
|
+
unless index.exists?
|
108
|
+
index.create :mappings => mapping_to_hash, :settings => settings
|
109
|
+
end
|
110
|
+
rescue Errno::ECONNREFUSED => e
|
111
|
+
STDERR.puts "Skipping index creation, cannot connect to ElasticSearch",
|
112
|
+
"(The original exception was: #{e.inspect})"
|
113
|
+
end
|
114
|
+
|
115
|
+
def mapping_options
|
116
|
+
@mapping_options || {}
|
117
|
+
end
|
118
|
+
|
119
|
+
def mapping_to_hash
|
120
|
+
{ document_type.to_sym => mapping_options.merge({ :properties => mapping }) }
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|