tire 0.1.1 → 0.1.2
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 +17 -11
- data/examples/rails-application-template.rb +28 -8
- data/lib/tire/model/import.rb +1 -1
- data/lib/tire/model/indexing.rb +2 -2
- data/lib/tire/model/search.rb +14 -6
- data/lib/tire/tasks.rb +1 -1
- data/lib/tire/version.rb +1 -1
- data/test/integration/active_model_searchable_test.rb +2 -2
- data/test/integration/active_record_searchable_test.rb +3 -3
- data/test/unit/index_test.rb +1 -1
- data/test/unit/model_search_test.rb +19 -1
- metadata +4 -4
data/README.markdown
CHANGED
@@ -209,8 +209,13 @@ Fortunately, _Tire_ makes blending _ElasticSearch_ features into your models tri
|
|
209
209
|
ActiveModel Integration
|
210
210
|
-----------------------
|
211
211
|
|
212
|
-
|
213
|
-
|
212
|
+
If you're the type with no time for lengthy introductions, you can generate a fully working
|
213
|
+
example Rails application, with an `ActiveRecord` model and a search form, to play with:
|
214
|
+
|
215
|
+
$ rails new searchapp -m https://github.com/karmi/tire/raw/master/examples/rails-application-template.rb
|
216
|
+
|
217
|
+
For the rest, let's suppose you have an `Article` class in your Rails application.
|
218
|
+
To make it searchable with _Tire_, you just `include` it:
|
214
219
|
|
215
220
|
class Article < ActiveRecord::Base
|
216
221
|
include Tire::Model::Search
|
@@ -224,14 +229,18 @@ When you now save a record:
|
|
224
229
|
:author => "Captain Nemo",
|
225
230
|
:published_on => Time.now
|
226
231
|
|
227
|
-
it is automatically added into the index, because of the included callbacks.
|
228
|
-
|
232
|
+
it is automatically added into the index, because of the included callbacks.
|
233
|
+
(You may want to skip them in special cases, like when your records are indexed via some external
|
234
|
+
mechanism, let's say CouchDB or RabbitMQ [river](http://www.elasticsearch.org/blog/2010/09/28/the_river.html)
|
235
|
+
for _ElasticSearch_.)
|
236
|
+
|
237
|
+
The document attributes are indexed exactly as when you call the `Article#to_json` method.
|
229
238
|
|
230
239
|
Now you can search the records:
|
231
240
|
|
232
241
|
Article.search 'love'
|
233
242
|
|
234
|
-
OK.
|
243
|
+
OK. This is where the game stops, often. Not here.
|
235
244
|
|
236
245
|
First of all, you may use the full query DSL, as explained above, with filters, sorting,
|
237
246
|
advanced facet aggregation, highlighting, etc:
|
@@ -292,7 +301,7 @@ so you can pass any parameters to the `search` method in the controller, as usua
|
|
292
301
|
|
293
302
|
OK. Chances are, you have lots of records stored in the underlying database. How will you get them to _ElasticSearch_? Easy:
|
294
303
|
|
295
|
-
Article.
|
304
|
+
Article.elasticsearch_index.import Article.all
|
296
305
|
|
297
306
|
However, this way, all your records are loaded into memory, serialized into JSON,
|
298
307
|
and sent down the wire to _ElasticSearch_. Not practical, you say? You're right.
|
@@ -326,11 +335,6 @@ You can index your data into a fresh index (and possibly update an alias if ever
|
|
326
335
|
|
327
336
|
$ rake environment tire:import CLASS='Article' INDEX='articles-2011-05'
|
328
337
|
|
329
|
-
If you're the type who has no time for long introductions, you can generate a fully working
|
330
|
-
example Rails application, with an `ActiveRecord` model and a search form, to play with:
|
331
|
-
|
332
|
-
$ rails new searchapp -m https://github.com/karmi/tire/raw/master/examples/rails-application-template.rb
|
333
|
-
|
334
338
|
OK. All this time we have been talking about `ActiveRecord` models, since
|
335
339
|
it is a reasonable Rails' default for the storage layer.
|
336
340
|
|
@@ -408,6 +412,8 @@ _Tire_ is already used in production by its authors. Nevertheless, it's not cons
|
|
408
412
|
|
409
413
|
There are todos, plans and ideas, some of which are listed below, in the order of importance:
|
410
414
|
|
415
|
+
* Wrap all Tire functionality mixed into a model in a "forwardable" object, and proxy everything via this object. (The immediate problem: [Mongoid](http://mongoid.org/docs/indexing.html))
|
416
|
+
* If we're not stepping on other's toes, bring Tire methods like `index`, `search`, `mapping` also to the class/instance top-level namespace.
|
411
417
|
* Proper RDoc annotations for the source code
|
412
418
|
* [Histogram](http://www.elasticsearch.org/guide/reference/api/search/facets/histogram-facet.html) facets
|
413
419
|
* [Statistical](http://www.elasticsearch.org/guide/reference/api/search/facets/statistical-facet.html) facets
|
@@ -2,33 +2,53 @@
|
|
2
2
|
# Template for generating a no-frills Rails application with support for ElasticSearch full-text search via Tire
|
3
3
|
# ===================================================================================================================
|
4
4
|
#
|
5
|
-
# This file creates a basic, fully working Rails application
|
6
|
-
#
|
5
|
+
# This file creates a basic, fully working Rails application with support for ElasticSearch full-text search
|
6
|
+
# via the Tire gem [http://github.com/karmi/tire].
|
7
7
|
#
|
8
|
+
# You DON'T NEED ELASTICSEARCH INSTALLED, it is installed and launched automatically by this script.
|
8
9
|
#
|
9
10
|
# Requirements
|
10
11
|
# ------------
|
11
12
|
#
|
13
|
+
# * Git
|
12
14
|
# * Ruby >= 1.8.7
|
13
15
|
# * Rubygems
|
14
|
-
# * Rails 3
|
16
|
+
# * Rails >= 3.0.7
|
17
|
+
# * Sun Java 6 (for ElasticSearch)
|
15
18
|
#
|
16
19
|
#
|
17
20
|
# Usage
|
18
21
|
# -----
|
19
22
|
#
|
20
|
-
# $ rails new
|
23
|
+
# $ rails new tired -m https://github.com/karmi/tire/raw/master/examples/rails-application-template.rb
|
21
24
|
#
|
22
25
|
# ===================================================================================================================
|
23
26
|
|
24
27
|
require 'rubygems'
|
25
|
-
require 'restclient'
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
+
begin
|
30
|
+
require 'restclient'
|
31
|
+
rescue LoadError
|
32
|
+
puts "\n"
|
33
|
+
say_status "ERROR", "Rubygem 'rest-client' not installed\n", :red
|
34
|
+
puts '-'*80
|
35
|
+
say_status "", "gem install rest-client"
|
36
|
+
puts "\n"
|
29
37
|
|
38
|
+
if yes?("Should I install it for you?", :bold)
|
39
|
+
say_status "gem", "install rest-client", :yellow
|
40
|
+
system "gem install rest-client"
|
41
|
+
else
|
42
|
+
exit(1)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
at_exit do
|
30
47
|
pid = File.read("#{destination_root}/tmp/pids/elasticsearch.pid") rescue nil
|
31
|
-
|
48
|
+
if pid
|
49
|
+
say_status "Stop", "ElasticSearch", :yellow
|
50
|
+
run "kill #{pid}"
|
51
|
+
end
|
32
52
|
end
|
33
53
|
|
34
54
|
run "rm public/index.html"
|
data/lib/tire/model/import.rb
CHANGED
data/lib/tire/model/indexing.rb
CHANGED
@@ -28,8 +28,8 @@ module Tire
|
|
28
28
|
def create_index_or_update_mapping
|
29
29
|
# STDERR.puts "Creating index with mapping", mapping_to_hash.inspect
|
30
30
|
# STDERR.puts "Index exists?, #{index.exists?}"
|
31
|
-
unless
|
32
|
-
|
31
|
+
unless elasticsearch_index.exists?
|
32
|
+
elasticsearch_index.create :mappings => mapping_to_hash
|
33
33
|
else
|
34
34
|
# TODO: Update mapping
|
35
35
|
end
|
data/lib/tire/model/search.rb
CHANGED
@@ -31,7 +31,7 @@ module Tire
|
|
31
31
|
sort = options[:order] || options[:sort]
|
32
32
|
sort = Array(sort)
|
33
33
|
unless block_given?
|
34
|
-
s = Tire::Search::Search.new(
|
34
|
+
s = Tire::Search::Search.new(elasticsearch_index.name, options)
|
35
35
|
s.query { string query }
|
36
36
|
s.sort do
|
37
37
|
sort.each do |t|
|
@@ -43,7 +43,7 @@ module Tire
|
|
43
43
|
s.from( options[:page].to_i <= 1 ? 0 : (options[:per_page].to_i * (options[:page].to_i-1)) ) if options[:page] && options[:per_page]
|
44
44
|
s.perform.results
|
45
45
|
else
|
46
|
-
s = Tire::Search::Search.new(
|
46
|
+
s = Tire::Search::Search.new(elasticsearch_index.name, options)
|
47
47
|
block.arity < 1 ? s.instance_eval(&block) : block.call(s)
|
48
48
|
s.perform.results
|
49
49
|
end
|
@@ -51,7 +51,15 @@ module Tire
|
|
51
51
|
Tire::Configuration.wrapper old_wrapper
|
52
52
|
end
|
53
53
|
|
54
|
-
|
54
|
+
# Wrapper for the ES index for this class
|
55
|
+
#
|
56
|
+
# TODO: Implement some "forwardable" object named +tire+ for Tire mixins,
|
57
|
+
# and proxy everything via this object. If we're not stepping on
|
58
|
+
# other libs toes, extend/include also to the top level.
|
59
|
+
#
|
60
|
+
# The original culprit is Mongoid here, see https://github.com/karmi/tire/issues/7
|
61
|
+
#
|
62
|
+
def elasticsearch_index
|
55
63
|
@index = Index.new(index_name)
|
56
64
|
end
|
57
65
|
|
@@ -64,14 +72,14 @@ module Tire
|
|
64
72
|
end
|
65
73
|
|
66
74
|
def index
|
67
|
-
self.class.
|
75
|
+
self.class.elasticsearch_index
|
68
76
|
end
|
69
77
|
|
70
78
|
def update_elastic_search_index
|
71
79
|
if destroyed?
|
72
|
-
|
80
|
+
index.remove document_type, self
|
73
81
|
else
|
74
|
-
response =
|
82
|
+
response = index.store document_type, self
|
75
83
|
self.id ||= response['_id'] if self.respond_to?(:id=)
|
76
84
|
self
|
77
85
|
end
|
data/lib/tire/tasks.rb
CHANGED
@@ -44,7 +44,7 @@ namespace :tire do
|
|
44
44
|
klass = eval(ENV['CLASS'].to_s)
|
45
45
|
params = eval(ENV['PARAMS'].to_s) || {}
|
46
46
|
|
47
|
-
index = Tire::Index.new( ENV['INDEX'] || klass.
|
47
|
+
index = Tire::Index.new( ENV['INDEX'] || klass.elasticsearch_index.name )
|
48
48
|
|
49
49
|
if ENV['FORCE']
|
50
50
|
puts "[IMPORT] Deleting index '#{index.name}'"
|
data/lib/tire/version.rb
CHANGED
@@ -28,7 +28,7 @@ module Tire
|
|
28
28
|
assert_equal 'czech', SupermodelArticle.mapping[:title][:analyzer]
|
29
29
|
assert_equal 15, SupermodelArticle.mapping[:title][:boost]
|
30
30
|
|
31
|
-
assert_equal 'czech', SupermodelArticle.
|
31
|
+
assert_equal 'czech', SupermodelArticle.elasticsearch_index.mapping['supermodel_article']['properties']['title']['analyzer']
|
32
32
|
end
|
33
33
|
|
34
34
|
should "save document into index on save and find it with score" do
|
@@ -65,7 +65,7 @@ module Tire
|
|
65
65
|
SupermodelArticle.create! :title => 'foo'
|
66
66
|
SupermodelArticle.create! :title => 'bar'
|
67
67
|
|
68
|
-
SupermodelArticle.
|
68
|
+
SupermodelArticle.elasticsearch_index.refresh
|
69
69
|
results = SupermodelArticle.search 'foo OR bar^100'
|
70
70
|
|
71
71
|
assert_equal 2, results.count
|
@@ -37,7 +37,7 @@ module Tire
|
|
37
37
|
assert_equal 'snowball', ActiveRecordArticle.mapping[:title][:analyzer]
|
38
38
|
assert_equal 10, ActiveRecordArticle.mapping[:title][:boost]
|
39
39
|
|
40
|
-
assert_equal 'snowball', ActiveRecordArticle.
|
40
|
+
assert_equal 'snowball', ActiveRecordArticle.elasticsearch_index.mapping['active_record_article']['properties']['title']['analyzer']
|
41
41
|
end
|
42
42
|
|
43
43
|
should "save document into index on save and find it" do
|
@@ -75,7 +75,7 @@ module Tire
|
|
75
75
|
ActiveRecordArticle.create! :title => 'foo'
|
76
76
|
ActiveRecordArticle.create! :title => 'bar'
|
77
77
|
|
78
|
-
ActiveRecordArticle.
|
78
|
+
ActiveRecordArticle.elasticsearch_index.refresh
|
79
79
|
results = ActiveRecordArticle.search 'foo OR bar^100'
|
80
80
|
assert_equal 2, results.count
|
81
81
|
|
@@ -85,7 +85,7 @@ module Tire
|
|
85
85
|
context "with pagination" do
|
86
86
|
setup do
|
87
87
|
1.upto(9) { |number| ActiveRecordArticle.create :title => "Test#{number}" }
|
88
|
-
ActiveRecordArticle.
|
88
|
+
ActiveRecordArticle.elasticsearch_index.refresh
|
89
89
|
end
|
90
90
|
|
91
91
|
context "and parameter searches" do
|
data/test/unit/index_test.rb
CHANGED
@@ -253,7 +253,7 @@ module Tire
|
|
253
253
|
one = ActiveModelArticle.new 'title' => 'One'; one.id = '1'
|
254
254
|
two = ActiveModelArticle.new 'title' => 'Two'; two.id = '2'
|
255
255
|
|
256
|
-
ActiveModelArticle.
|
256
|
+
ActiveModelArticle.elasticsearch_index.bulk_store [ one, two ]
|
257
257
|
|
258
258
|
end
|
259
259
|
|
@@ -20,6 +20,21 @@ module Tire
|
|
20
20
|
assert_respond_to ActiveModelArticle, :search
|
21
21
|
end
|
22
22
|
|
23
|
+
should_eventually "contain all Tire class/instance methods in a proxy object" do
|
24
|
+
end
|
25
|
+
|
26
|
+
should_eventually "include Tire class methods in class top-level namespace when they do not exist" do
|
27
|
+
end
|
28
|
+
|
29
|
+
should_eventually "include Tire instance methods in instance top-level namespace when they do not exist" do
|
30
|
+
end
|
31
|
+
|
32
|
+
should_eventually "NOT overload existing top-level class methods" do
|
33
|
+
end
|
34
|
+
|
35
|
+
should_eventually "NOT overload existing top-level instance methods" do
|
36
|
+
end
|
37
|
+
|
23
38
|
should "search in index named after class name by default" do
|
24
39
|
i = 'active_model_articles'
|
25
40
|
Tire::Search::Search.expects(:new).with(i, {}).returns(@stub)
|
@@ -27,6 +42,9 @@ module Tire
|
|
27
42
|
ActiveModelArticle.search 'foo'
|
28
43
|
end
|
29
44
|
|
45
|
+
should_eventually "search only in document types for this class by default" do
|
46
|
+
end
|
47
|
+
|
30
48
|
should "search in custom name" do
|
31
49
|
first = 'custom-index-name'
|
32
50
|
second = 'another-custom-index-name'
|
@@ -47,7 +65,7 @@ module Tire
|
|
47
65
|
should "allow to refresh index" do
|
48
66
|
Index.any_instance.expects(:refresh)
|
49
67
|
|
50
|
-
ActiveModelArticle.
|
68
|
+
ActiveModelArticle.elasticsearch_index.refresh
|
51
69
|
end
|
52
70
|
|
53
71
|
should "wrap results in proper class with ID and score and not change the original wrapper" do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Karel Minarik
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-03 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|