tire 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|