tire 0.5.5 → 0.5.6
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/README.markdown +15 -32
- data/lib/tire/http/clients/curb.rb +26 -22
- data/lib/tire/index.rb +5 -4
- data/lib/tire/model/import.rb +97 -10
- data/lib/tire/model/persistence/attributes.rb +4 -3
- data/lib/tire/search/query.rb +27 -0
- data/lib/tire/tasks.rb +134 -81
- data/lib/tire/version.rb +4 -7
- data/test/integration/active_record_searchable_test.rb +1 -0
- data/test/integration/boosting_queries_test.rb +45 -8
- data/test/integration/constant_score_queries_test.rb +66 -0
- data/test/integration/dsl_search_test.rb +9 -2
- data/test/integration/percolator_test.rb +1 -1
- data/test/integration/persistent_model_test.rb +1 -0
- data/test/unit/http_client_test.rb +12 -0
- data/test/unit/index_test.rb +8 -6
- data/test/unit/search_query_test.rb +22 -0
- data/test/unit/tire_test.rb +19 -5
- data/tire.gemspec +1 -0
- metadata +58 -47
data/README.markdown
CHANGED
@@ -11,8 +11,7 @@ communicating by JSON over RESTful HTTP, based on [Lucene](http://lucene.apache.
|
|
11
11
|
|
12
12
|
This Readme provides a brief overview of _Tire's_ features. The more detailed documentation is at <http://karmi.github.com/tire/>.
|
13
13
|
|
14
|
-
Both of these documents contain a lot of information. Please set aside some time to read them thoroughly, before you blindly dive into „somehow making it work“. Just skimming through it **won't work** for you. For more information, please refer to the [integration test suite](https://github.com/karmi/tire/tree/master/test/integration)
|
15
|
-
and [issues](https://github.com/karmi/tire/issues).
|
14
|
+
Both of these documents contain a lot of information. Please set aside some time to read them thoroughly, before you blindly dive into „somehow making it work“. Just skimming through it **won't work** for you. For more information, please see the project [Wiki](https://github.com/karmi/tire/wiki/_pages), search the [issues](https://github.com/karmi/tire/issues), and refer to the [integration test suite](https://github.com/karmi/tire/tree/master/test/integration).
|
16
15
|
|
17
16
|
Installation
|
18
17
|
------------
|
@@ -632,8 +631,9 @@ in addition to model instance, use the `each_with_hit` method:
|
|
632
631
|
# One (score: 0.300123)
|
633
632
|
```
|
634
633
|
|
635
|
-
Note that _Tire_ search results are fully compatible with [
|
636
|
-
so you can pass all the usual parameters to the
|
634
|
+
Note that _Tire_ search results are fully compatible with [_WillPaginate_](https://github.com/mislav/will_paginate)
|
635
|
+
and [_Kaminari_](https://github.com/amatsuda/kaminari), so you can pass all the usual parameters to the
|
636
|
+
`search` method in the controller:
|
637
637
|
|
638
638
|
```ruby
|
639
639
|
@articles = Article.search params[:q], :page => (params[:page] || 1)
|
@@ -648,20 +648,15 @@ OK. Chances are, you have lots of records stored in your database. How will you
|
|
648
648
|
This way, however, all your records are loaded into memory, serialized into JSON,
|
649
649
|
and sent down the wire to _Elasticsearch_. Not practical, you say? You're right.
|
650
650
|
|
651
|
-
|
651
|
+
When your model is an `ActiveRecord::Base` or `Mongoid::Document` one, or when it implements
|
652
|
+
some sort of pagination, you can just run:
|
652
653
|
|
653
654
|
```ruby
|
654
655
|
Article.import
|
655
656
|
```
|
656
657
|
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
```ruby
|
661
|
-
Article.import :per_page => 100
|
662
|
-
```
|
663
|
-
|
664
|
-
Any other parameters you provide to the `import` method are passed down to the `paginate` method.
|
658
|
+
Depending on the setup of your model, either `find_in_batches`, `limit..skip` or pagination is used
|
659
|
+
to import your data.
|
665
660
|
|
666
661
|
Are we saying you have to fiddle with this thing in a `rails console` or silly Ruby scripts? No.
|
667
662
|
Just call the included _Rake_ task on the command line:
|
@@ -677,13 +672,6 @@ provided by the `mapping` block in your model):
|
|
677
672
|
$ rake environment tire:import CLASS='Article' FORCE=true
|
678
673
|
```
|
679
674
|
|
680
|
-
When importing records from multiple tables, you can fight the n+1 queries problem by passing
|
681
|
-
`include` parameters to the `paginate` method:
|
682
|
-
|
683
|
-
```bash
|
684
|
-
rake environment tire:import PARAMS='{:include => ["comments"]}' CLASS=Article FORCE=true
|
685
|
-
```
|
686
|
-
|
687
675
|
When you'll spend more time with _Elasticsearch_, you'll notice how
|
688
676
|
[index aliases](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases.html)
|
689
677
|
are the best idea since the invention of inverted index.
|
@@ -695,21 +683,16 @@ You can index your data into a fresh index (and possibly update an alias once ev
|
|
695
683
|
|
696
684
|
Finally, consider the Rake importing task just a convenient starting point. If you're loading
|
697
685
|
substantial amounts of data, want better control on which data will be indexed, etc., use the
|
698
|
-
lower-level Tire API with eg. `ActiveRecordBase#find_in_batches
|
686
|
+
lower-level Tire API with eg. `ActiveRecordBase#find_in_batches` directly:
|
699
687
|
|
700
688
|
```ruby
|
701
|
-
Article.where("published_on > ?", Time.parse("2012-10-01")).find_in_batches do |
|
702
|
-
Tire.index("articles").import
|
689
|
+
Article.where("published_on > ?", Time.parse("2012-10-01")).find_in_batches(include: authors) do |batch|
|
690
|
+
Tire.index("articles").import batch
|
703
691
|
end
|
704
692
|
```
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
But what if you use another database such as [MongoDB](http://www.mongodb.org/),
|
710
|
-
another object mapping library, such as [Mongoid](http://mongoid.org/) or [MongoMapper](http://mongomapper.com/)?
|
711
|
-
|
712
|
-
Well, things stay mostly the same:
|
693
|
+
If you're using a different database, such as [MongoDB](http://www.mongodb.org/),
|
694
|
+
another object mapping library, such as [Mongoid](http://mongoid.org/) or [MongoMapper](http://mongomapper.com/),
|
695
|
+
things stay mostly the same:
|
713
696
|
|
714
697
|
```ruby
|
715
698
|
class Article
|
@@ -779,7 +762,7 @@ and extensions to the core _Tire_ functionality — be sure to check them out.
|
|
779
762
|
Other Clients
|
780
763
|
-------------
|
781
764
|
|
782
|
-
Check out [other _Elasticsearch_ clients](http://www.elasticsearch.org/guide/
|
765
|
+
Check out [other _Elasticsearch_ clients](http://www.elasticsearch.org/guide/clients/).
|
783
766
|
|
784
767
|
|
785
768
|
Feedback
|
@@ -7,49 +7,53 @@ module Tire
|
|
7
7
|
module Client
|
8
8
|
|
9
9
|
class Curb
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def self.client
|
11
|
+
Thread.current[:client] ||= begin
|
12
|
+
client = ::Curl::Easy.new
|
13
|
+
client.resolve_mode = :ipv4
|
14
|
+
# client.verbose = true
|
15
|
+
client
|
16
|
+
end
|
17
|
+
end
|
14
18
|
|
15
19
|
def self.get(url, data=nil)
|
16
|
-
|
20
|
+
client.url = url
|
17
21
|
|
18
22
|
# FIXME: Curb cannot post bodies with GET requests?
|
19
23
|
# Roy Fielding seems to approve:
|
20
24
|
# <http://tech.groups.yahoo.com/group/rest-discuss/message/9962>
|
21
25
|
if data
|
22
|
-
|
23
|
-
|
26
|
+
client.post_body = data
|
27
|
+
client.http_post
|
24
28
|
else
|
25
|
-
|
29
|
+
client.http_get
|
26
30
|
end
|
27
|
-
Response.new
|
31
|
+
Response.new client.body_str, client.response_code
|
28
32
|
end
|
29
33
|
|
30
34
|
def self.post(url, data)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
Response.new
|
35
|
+
client.url = url
|
36
|
+
client.post_body = data
|
37
|
+
client.http_post
|
38
|
+
Response.new client.body_str, client.response_code
|
35
39
|
end
|
36
40
|
|
37
41
|
def self.put(url, data)
|
38
|
-
|
39
|
-
|
40
|
-
Response.new
|
42
|
+
client.url = url
|
43
|
+
client.http_put data
|
44
|
+
Response.new client.body_str, client.response_code
|
41
45
|
end
|
42
46
|
|
43
47
|
def self.delete(url)
|
44
|
-
|
45
|
-
|
46
|
-
Response.new
|
48
|
+
client.url = url
|
49
|
+
client.http_delete
|
50
|
+
Response.new client.body_str, client.response_code
|
47
51
|
end
|
48
52
|
|
49
53
|
def self.head(url)
|
50
|
-
|
51
|
-
|
52
|
-
Response.new
|
54
|
+
client.url = url
|
55
|
+
client.http_head
|
56
|
+
Response.new client.body_str, client.response_code
|
53
57
|
end
|
54
58
|
|
55
59
|
end
|
data/lib/tire/index.rb
CHANGED
@@ -245,12 +245,13 @@ module Tire
|
|
245
245
|
case
|
246
246
|
when method = options.delete(:method)
|
247
247
|
options = {:page => 1, :per_page => 1000}.merge options
|
248
|
-
while documents = klass_or_collection.send(method.to_sym, options.merge(:page => options[:page])) \
|
249
|
-
|
248
|
+
while (documents = klass_or_collection.send(method.to_sym, options.merge(:page => options[:page]))) \
|
249
|
+
&& documents.to_a.length > 0
|
250
250
|
|
251
251
|
documents = yield documents if block_given?
|
252
252
|
|
253
253
|
bulk_store documents, options
|
254
|
+
GC.start
|
254
255
|
options[:page] += 1
|
255
256
|
end
|
256
257
|
|
@@ -259,8 +260,8 @@ module Tire
|
|
259
260
|
bulk_store documents, options
|
260
261
|
|
261
262
|
else
|
262
|
-
raise ArgumentError, "Please pass either an Enumerable compatible class, or a collection object" +
|
263
|
-
"with a method for fetching records in batches (such as 'paginate')"
|
263
|
+
raise ArgumentError, "Please pass either an Enumerable compatible class, or a collection object " +
|
264
|
+
"with a method for fetching records in batches (such as 'paginate')."
|
264
265
|
end
|
265
266
|
end
|
266
267
|
|
data/lib/tire/model/import.rb
CHANGED
@@ -1,27 +1,114 @@
|
|
1
|
-
|
2
1
|
module Tire
|
3
2
|
module Model
|
4
3
|
|
5
|
-
# Provides support for
|
6
|
-
#
|
4
|
+
# Provides support for efficient and effective importing of large recordsets into Elasticsearch.
|
5
|
+
#
|
6
|
+
# Tire will use dedicated strategies for fetching records in batches when ActiveRecord or Mongoid models are detected.
|
7
|
+
#
|
8
|
+
# Two dedicated strategies for popular pagination libraries are also provided: WillPaginate and Kaminari.
|
9
|
+
# These could be used in situations where your model is neither ActiveRecord nor Mongoid based.
|
7
10
|
#
|
8
|
-
#
|
11
|
+
# Note, that it's always possible to use the `Tire::Index#import` method directly.
|
9
12
|
#
|
10
|
-
#
|
13
|
+
# @note See `Tire::Import::Strategy`.
|
11
14
|
#
|
12
15
|
module Import
|
13
16
|
|
14
17
|
module ClassMethods
|
15
|
-
|
16
18
|
def import options={}, &block
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
strategy = Strategy.from_class(klass, options)
|
20
|
+
strategy.import &block
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Importing strategies for common persistence frameworks (ActiveModel, Mongoid), as well as
|
25
|
+
# pagination libraries (WillPaginate, Kaminari).
|
26
|
+
#
|
27
|
+
module Strategy
|
28
|
+
def self.from_class(klass, options={})
|
29
|
+
case
|
30
|
+
when defined?(::ActiveRecord) && klass.ancestors.include?(::ActiveRecord::Base)
|
31
|
+
ActiveRecord.new klass, options
|
32
|
+
when defined?(::Mongoid::Document) && klass.ancestors.include?(::Mongoid::Document)
|
33
|
+
Mongoid.new klass, options
|
34
|
+
when defined?(Kaminari) && klass.respond_to?(:page)
|
35
|
+
Kaminari.new klass, options
|
36
|
+
when defined?(WillPaginate) && klass.respond_to?(:paginate)
|
37
|
+
WillPaginate.new klass, options
|
38
|
+
else
|
39
|
+
Default.new klass, options
|
40
|
+
end
|
20
41
|
end
|
21
42
|
|
43
|
+
module Base
|
44
|
+
attr_reader :klass, :options, :index
|
45
|
+
def initialize(klass, options={})
|
46
|
+
@klass = klass
|
47
|
+
@options = {:per_page => 1000}.update(options)
|
48
|
+
@index = options[:index] ? Tire::Index.new(options.delete(:index)) : klass.tire.index
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class ActiveRecord
|
53
|
+
include Base
|
54
|
+
def import &block
|
55
|
+
klass.find_in_batches(:batch_size => options[:per_page]) do |batch|
|
56
|
+
index.import batch, options, &block
|
57
|
+
end
|
58
|
+
self
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Mongoid
|
63
|
+
include Base
|
64
|
+
def import &block
|
65
|
+
0.step(klass.count, options[:per_page]) do |offset|
|
66
|
+
items = klass.limit(options[:per_page]).skip(offset)
|
67
|
+
index.import items.to_a, options, &block
|
68
|
+
end
|
69
|
+
self
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Kaminari
|
74
|
+
include Base
|
75
|
+
def import &block
|
76
|
+
current = 0
|
77
|
+
page = 1
|
78
|
+
while current < klass.count
|
79
|
+
items = klass.page(page).per(options[:per_page])
|
80
|
+
index.import items, options, &block
|
81
|
+
current = current + items.size
|
82
|
+
page += 1
|
83
|
+
end
|
84
|
+
self
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class WillPaginate
|
89
|
+
include Base
|
90
|
+
def import &block
|
91
|
+
current = 0
|
92
|
+
page = 1
|
93
|
+
while current < klass.count
|
94
|
+
items = klass.paginate(:page => page, :per_page => options[:per_page])
|
95
|
+
index.import items, options, &block
|
96
|
+
current += items.size
|
97
|
+
page += 1
|
98
|
+
end
|
99
|
+
self
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class Default
|
104
|
+
include Base
|
105
|
+
def import &block
|
106
|
+
index.import klass, options.update(:method => 'paginate'), &block
|
107
|
+
self
|
108
|
+
end
|
109
|
+
end
|
22
110
|
end
|
23
111
|
|
24
112
|
end
|
25
|
-
|
26
113
|
end
|
27
114
|
end
|
@@ -87,13 +87,14 @@ module Tire
|
|
87
87
|
attr_accessor :id
|
88
88
|
|
89
89
|
def initialize(attributes={})
|
90
|
-
# Make a copy of objects in the property defaults hash, so default values
|
90
|
+
# Make a copy of objects in the property defaults hash, so default values
|
91
|
+
# such as `[]` or `{ foo: [] }` are preserved.
|
92
|
+
#
|
91
93
|
property_defaults = self.class.property_defaults.inject({}) do |hash, item|
|
92
94
|
key, value = item
|
93
|
-
hash[key.
|
95
|
+
hash[key.to_sym] = value.class.respond_to?(:new) ? value.clone : value
|
94
96
|
hash
|
95
97
|
end
|
96
|
-
|
97
98
|
__update_attributes(property_defaults.merge(attributes))
|
98
99
|
end
|
99
100
|
|
data/lib/tire/search/query.rb
CHANGED
@@ -56,6 +56,10 @@ module Tire
|
|
56
56
|
@value
|
57
57
|
end
|
58
58
|
|
59
|
+
def constant_score(&block)
|
60
|
+
@value.update( { :constant_score => ConstantScoreQuery.new(&block).to_hash } ) if block_given?
|
61
|
+
end
|
62
|
+
|
59
63
|
def fuzzy(field, value, options={})
|
60
64
|
query = { field => { :term => value }.update(options) }
|
61
65
|
@value = { :fuzzy => query }
|
@@ -182,6 +186,29 @@ module Tire
|
|
182
186
|
end
|
183
187
|
end
|
184
188
|
|
189
|
+
class ConstantScoreQuery
|
190
|
+
def initialize(&block)
|
191
|
+
@value = {}
|
192
|
+
block.arity < 1 ? self.instance_eval(&block) : block.call(self) if block_given?
|
193
|
+
end
|
194
|
+
|
195
|
+
def filter(type, *options)
|
196
|
+
@value.update(:filter => Filter.new(type, *options).to_hash)
|
197
|
+
end
|
198
|
+
|
199
|
+
def query(&block)
|
200
|
+
@value.update(:query => Query.new(&block).to_hash)
|
201
|
+
end
|
202
|
+
|
203
|
+
def boost(boost)
|
204
|
+
@value.update(:boost => boost)
|
205
|
+
end
|
206
|
+
|
207
|
+
def to_hash
|
208
|
+
@value
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
185
212
|
class DisMaxQuery
|
186
213
|
def initialize(options={}, &block)
|
187
214
|
@options = options
|
data/lib/tire/tasks.rb
CHANGED
@@ -1,116 +1,169 @@
|
|
1
1
|
require 'rake'
|
2
|
-
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
module Tasks
|
5
|
+
|
6
|
+
module Import
|
7
|
+
HRULE = '='*90
|
8
|
+
|
9
|
+
def delete_index(index)
|
10
|
+
puts "[IMPORT] Deleting index '#{index.name}'"
|
11
|
+
index.delete
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_index(index, klass)
|
15
|
+
unless index.exists?
|
16
|
+
mapping = MultiJson.encode(klass.tire.mapping_to_hash, :pretty => Tire::Configuration.pretty)
|
17
|
+
puts "[IMPORT] Creating index '#{index.name}' with mapping:", mapping
|
18
|
+
unless index.create(:mappings => klass.tire.mapping_to_hash, :settings => klass.tire.settings)
|
19
|
+
puts "[ERROR] There has been an error when creating the index -- Elasticsearch returned:",
|
20
|
+
index.response
|
21
|
+
exit(1)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_pagination_to_klass(klass)
|
27
|
+
if defined?(Kaminari) && klass.respond_to?(:page)
|
28
|
+
klass.instance_eval do
|
29
|
+
def paginate(options = {})
|
30
|
+
page(options[:page]).per(options[:per_page])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end unless klass.respond_to?(:paginate)
|
34
|
+
end
|
35
|
+
|
36
|
+
def progress_bar(klass, total=nil)
|
37
|
+
@progress_bars ||= {}
|
38
|
+
|
39
|
+
if total
|
40
|
+
@progress_bars[klass.to_s] ||= ANSI::Progressbar.new(klass.to_s, total)
|
41
|
+
else
|
42
|
+
@progress_bars[klass.to_s]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def import_model(index, klass, params)
|
47
|
+
unless progress_bar(klass)
|
48
|
+
puts "[IMPORT] Importing '#{klass.to_s}'"
|
49
|
+
end
|
50
|
+
klass.tire.import(params) do |documents|
|
51
|
+
progress_bar(klass).inc documents.size if progress_bar(klass)
|
52
|
+
documents
|
53
|
+
end
|
54
|
+
progress_bar(klass).finish if progress_bar(klass)
|
55
|
+
end
|
56
|
+
|
57
|
+
extend self
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
3
62
|
|
4
63
|
namespace :tire do
|
5
64
|
|
6
|
-
|
7
|
-
Import data from your model
|
65
|
+
import_model_desc = <<-DESC.gsub(/ /, '')
|
66
|
+
Import data from your model (pass name as CLASS environment variable).
|
67
|
+
|
68
|
+
$ rake environment tire:import:model CLASS='MyModel'
|
8
69
|
|
9
|
-
Pass params for the `
|
10
|
-
$ rake environment tire:import CLASS='Article' PARAMS='{:page => 1}'
|
70
|
+
Pass params for the `import` method:
|
71
|
+
$ rake environment tire:import:model CLASS='Article' PARAMS='{:page => 1}'
|
11
72
|
|
12
73
|
Force rebuilding the index (delete and create):
|
13
|
-
$ rake environment tire:import CLASS='Article'
|
74
|
+
$ rake environment tire:import:model CLASS='Article' FORCE=1
|
14
75
|
|
15
76
|
Set target index name:
|
16
|
-
$ rake environment tire:import CLASS='Article' INDEX='articles-new'
|
77
|
+
$ rake environment tire:import:model CLASS='Article' INDEX='articles-new'
|
17
78
|
DESC
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
"
|
32
|
-
|
33
|
-
"#{(elapsed/hour).round} hours"
|
79
|
+
|
80
|
+
import_all_desc = <<-DESC.gsub(/ /, '')
|
81
|
+
Import all indices from `app/models` (or use DIR environment variable).
|
82
|
+
|
83
|
+
$ rake environment tire:import:all DIR=app/models
|
84
|
+
DESC
|
85
|
+
|
86
|
+
task :import => 'import:model'
|
87
|
+
|
88
|
+
namespace :import do
|
89
|
+
desc import_model_desc
|
90
|
+
task :model do
|
91
|
+
if defined?(Rails)
|
92
|
+
puts "[IMPORT] Rails detected, loading environment..."
|
93
|
+
Rake::Task["environment"].invoke
|
34
94
|
end
|
35
|
-
end
|
36
95
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
96
|
+
if ENV['CLASS'].to_s == ''
|
97
|
+
puts HRULE, 'USAGE', HRULE, import_model_desc, ""
|
98
|
+
exit(1)
|
99
|
+
end
|
100
|
+
|
101
|
+
klass = eval(ENV['CLASS'].to_s)
|
102
|
+
params = eval(ENV['PARAMS'].to_s) || {}
|
103
|
+
total = klass.count rescue nil
|
104
|
+
|
105
|
+
if ENV['INDEX']
|
106
|
+
index = Tire::Index.new(ENV['INDEX'])
|
107
|
+
params[:index] = index.name
|
108
|
+
else
|
109
|
+
index = klass.tire.index
|
110
|
+
end
|
41
111
|
|
42
|
-
|
43
|
-
|
112
|
+
Tire::Tasks::Import.add_pagination_to_klass(klass)
|
113
|
+
Tire::Tasks::Import.progress_bar(klass, total) if total
|
44
114
|
|
45
|
-
|
115
|
+
Tire::Tasks::Import.delete_index(index) if ENV['FORCE']
|
116
|
+
Tire::Tasks::Import.create_index(index, klass)
|
46
117
|
|
47
|
-
|
118
|
+
Tire::Tasks::Import.import_model(index, klass, params)
|
48
119
|
|
49
|
-
|
50
|
-
puts "[IMPORT] Deleting index '#{index.name}'"
|
51
|
-
index.delete
|
120
|
+
puts '[IMPORT] Done.'
|
52
121
|
end
|
53
122
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
index.response
|
60
|
-
exit(1)
|
123
|
+
desc import_all_desc
|
124
|
+
task :all do
|
125
|
+
if defined?(Rails)
|
126
|
+
puts "[IMPORT] Rails detected, loading environment..."
|
127
|
+
Rake::Task["environment"].invoke
|
61
128
|
end
|
62
|
-
end
|
63
129
|
|
64
|
-
|
65
|
-
|
66
|
-
tty_cols = 80
|
67
|
-
total = klass.count rescue nil
|
68
|
-
offset = (total.to_s.size*2)+8
|
69
|
-
done = 0
|
70
|
-
|
71
|
-
STDOUT.puts '-'*tty_cols
|
72
|
-
elapsed = Benchmark.realtime do
|
73
|
-
|
74
|
-
# Add Kaminari-powered "paginate" method
|
75
|
-
#
|
76
|
-
if defined?(Kaminari) && klass.respond_to?(:page)
|
77
|
-
klass.instance_eval do
|
78
|
-
def paginate(options = {})
|
79
|
-
page(options[:page]).per(options[:per_page])
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end unless klass.respond_to?(:paginate)
|
130
|
+
dir = ENV['DIR'].to_s != '' ? ENV['DIR'] : Rails.root.join("app/models")
|
131
|
+
params = eval(ENV['PARAMS'].to_s) || {}
|
83
132
|
|
84
|
-
|
85
|
-
#
|
86
|
-
|
133
|
+
puts "[IMPORT] Loading models from: #{dir}"
|
134
|
+
Dir.glob(File.join("#{dir}/**/*.rb")).each do |path|
|
135
|
+
require path
|
87
136
|
|
88
|
-
|
89
|
-
|
90
|
-
# I CAN HAZ PROGREZ BAR LIEK HOMEBRU!
|
91
|
-
percent = ( (done.to_f / total) * 100 ).to_i
|
92
|
-
glyphs = ( percent * ( (tty_cols-offset).to_f/100 ) ).to_i
|
93
|
-
STDOUT.print( "#" * glyphs )
|
94
|
-
STDOUT.print( "\r"*tty_cols+"#{done}/#{total} | \e[1m#{percent}%\e[0m " )
|
95
|
-
end
|
137
|
+
model_filename = path[/#{Regexp.escape(dir.to_s)}\/([^\.]+).rb/, 1]
|
138
|
+
klass = model_filename.classify.constantize
|
96
139
|
|
97
|
-
#
|
98
|
-
|
140
|
+
# Skip if the class doesn't have Tire integration
|
141
|
+
next unless klass.respond_to?(:tire)
|
142
|
+
|
143
|
+
total = klass.count rescue nil
|
144
|
+
|
145
|
+
Tire::Tasks::Import.add_pagination_to_klass(klass)
|
146
|
+
Tire::Tasks::Import.progress_bar(klass, total) if total
|
147
|
+
|
148
|
+
index = klass.tire.index
|
149
|
+
Tire::Tasks::Import.delete_index(index) if ENV['FORCE']
|
150
|
+
Tire::Tasks::Import.create_index(index, klass)
|
151
|
+
|
152
|
+
Tire::Tasks::Import.import_model(index, klass, params)
|
153
|
+
puts
|
99
154
|
end
|
155
|
+
|
156
|
+
puts '[Import] Done.'
|
100
157
|
end
|
101
158
|
|
102
|
-
puts "", '='*80, "Import finished in #{elapsed_to_human(elapsed)}"
|
103
159
|
end
|
104
160
|
|
105
161
|
namespace :index do
|
106
162
|
|
107
163
|
full_comment_drop = <<-DESC.gsub(/ /, '')
|
108
|
-
Delete indices passed in the INDEX environment variable; separate multiple indices by comma.
|
164
|
+
Delete indices passed in the INDEX/INDICES environment variable; separate multiple indices by comma.
|
109
165
|
|
110
|
-
Pass name of a single index to drop in the INDEX environmnet variable:
|
111
166
|
$ rake environment tire:index:drop INDEX=articles
|
112
|
-
|
113
|
-
Pass names of multiple indices to drop in the INDEX or INDICES environmnet variable:
|
114
167
|
$ rake environment tire:index:drop INDICES=articles-2011-01,articles-2011-02
|
115
168
|
|
116
169
|
DESC
|
@@ -126,7 +179,7 @@ namespace :tire do
|
|
126
179
|
index_names.each do |name|
|
127
180
|
index = Tire::Index.new(name)
|
128
181
|
print "* Deleting index \e[1m#{index.name}\e[0m... "
|
129
|
-
puts
|
182
|
+
puts index.delete ? "\e[32mOK\e[0m" : "\e[31mFAILED\e[0m | #{index.response.body}"
|
130
183
|
end
|
131
184
|
|
132
185
|
puts ""
|