elastic_searchable 0.3.1 → 0.4.0
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.rdoc +26 -1
- data/VERSION +1 -1
- data/elastic_searchable.gemspec +3 -3
- data/lib/elastic_searchable/active_record.rb +12 -41
- data/lib/elastic_searchable/callbacks.rb +14 -23
- data/lib/elastic_searchable/index.rb +61 -14
- data/lib/elastic_searchable.rb +5 -3
- data/test/helper.rb +3 -0
- data/test/test_elastic_searchable.rb +91 -53
- metadata +6 -6
data/README.rdoc
CHANGED
@@ -1,6 +1,31 @@
|
|
1
1
|
= elastic_searchable
|
2
2
|
|
3
|
-
|
3
|
+
Integrate the elasticsearch library into Rails.
|
4
|
+
|
5
|
+
== Usage
|
6
|
+
class Blog < ActiveRecord::Base
|
7
|
+
elastic_searchable
|
8
|
+
end
|
9
|
+
|
10
|
+
results = Blog.search 'foo'
|
11
|
+
|
12
|
+
== Features
|
13
|
+
|
14
|
+
* fast. fast! FAST! 30% faster than rubberband on average.
|
15
|
+
* active record callbacks automatically keep search index up to date as your data changes
|
16
|
+
* out of the box background indexing of data using backgrounded. Don't lock up a foreground process waiting on a background job!
|
17
|
+
* integrates with will_paginate library for easy pagination of search results
|
18
|
+
|
19
|
+
== Installation
|
20
|
+
#Gemfile
|
21
|
+
gem 'elastic_searchable'
|
22
|
+
|
23
|
+
== Configuration
|
24
|
+
|
25
|
+
#config/initializers/elastic_searchable.rb
|
26
|
+
#customize elasticsearch host
|
27
|
+
#defaults to localhost:9200
|
28
|
+
ElasticSearchable.base_uri = 'server:9200'
|
4
29
|
|
5
30
|
== Contributing to elastic_searchable
|
6
31
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/elastic_searchable.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{elastic_searchable}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ryan Sonnek"]
|
12
|
-
s.date = %q{2011-02-
|
12
|
+
s.date = %q{2011-02-22}
|
13
13
|
s.description = %q{integrate the elastic search engine with rails}
|
14
14
|
s.email = %q{ryan@codecrate.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -36,7 +36,7 @@ Gem::Specification.new do |s|
|
|
36
36
|
s.homepage = %q{http://github.com/wireframe/elastic_searchable}
|
37
37
|
s.licenses = ["MIT"]
|
38
38
|
s.require_paths = ["lib"]
|
39
|
-
s.rubygems_version = %q{1.5.
|
39
|
+
s.rubygems_version = %q{1.5.2}
|
40
40
|
s.summary = %q{elastic search for activerecord}
|
41
41
|
s.test_files = [
|
42
42
|
"test/helper.rb",
|
@@ -26,51 +26,22 @@ module ElasticSearchable
|
|
26
26
|
options.symbolize_keys!
|
27
27
|
self.elastic_options = options
|
28
28
|
|
29
|
-
extend ElasticSearchable::
|
29
|
+
extend ElasticSearchable::Indexing::ClassMethods
|
30
30
|
extend ElasticSearchable::Queries
|
31
31
|
|
32
|
-
include ElasticSearchable::
|
33
|
-
include ElasticSearchable::Callbacks
|
32
|
+
include ElasticSearchable::Indexing::InstanceMethods
|
33
|
+
include ElasticSearchable::Callbacks::InstanceMethods
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
module InstanceMethods
|
40
|
-
def indexed_json_document
|
41
|
-
self.as_json self.class.elastic_options[:json]
|
42
|
-
end
|
43
|
-
def index_in_elastic_search(lifecycle = nil)
|
44
|
-
ElasticSearchable.request :put, self.class.index_type_path(self.id), :body => self.indexed_json_document.to_json
|
45
|
-
|
46
|
-
self.run_callbacks("after_index_on_#{lifecycle}".to_sym) if lifecycle
|
47
|
-
self.run_callbacks(:after_index)
|
48
|
-
end
|
49
|
-
def should_index?
|
50
|
-
[self.class.elastic_options[:if]].flatten.compact.all? { |m| evaluate_elastic_condition(m) } &&
|
51
|
-
![self.class.elastic_options[:unless]].flatten.compact.any? { |m| evaluate_elastic_condition(m) }
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
#ripped from activesupport
|
56
|
-
def evaluate_elastic_condition(method)
|
57
|
-
case method
|
58
|
-
when Symbol
|
59
|
-
self.send method
|
60
|
-
when String
|
61
|
-
eval(method, self.instance_eval { binding })
|
62
|
-
when Proc, Method
|
63
|
-
method.call
|
64
|
-
else
|
65
|
-
if method.respond_to?(kind)
|
66
|
-
method.send kind
|
67
|
-
else
|
68
|
-
raise ArgumentError,
|
69
|
-
"Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
|
70
|
-
"a block to be invoked, or an object responding to the callback method."
|
71
|
-
end
|
35
|
+
backgrounded :update_index_on_create => ElasticSearchable::Callbacks.backgrounded_options, :update_index_on_update => ElasticSearchable::Callbacks.backgrounded_options
|
36
|
+
class << self
|
37
|
+
backgrounded :delete_id_from_index => ElasticSearchable::Callbacks.backgrounded_options
|
72
38
|
end
|
39
|
+
|
40
|
+
define_callbacks :after_index_on_create, :after_index_on_update, :after_index
|
41
|
+
after_commit_on_create :update_index_on_create_backgrounded, :if => :should_index?
|
42
|
+
after_commit_on_update :update_index_on_update_backgrounded, :if => :should_index?
|
43
|
+
after_commit_on_destroy :delete_from_index
|
73
44
|
end
|
74
45
|
end
|
75
46
|
end
|
76
|
-
end
|
47
|
+
end
|
@@ -1,31 +1,22 @@
|
|
1
1
|
module ElasticSearchable
|
2
2
|
module Callbacks
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def self.backgrounded_options
|
7
|
-
{:queue => 'elasticsearch'}
|
8
|
-
end
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
def add_indexing_callbacks
|
12
|
-
backgrounded :update_index_on_create => ElasticSearchable::Callbacks.backgrounded_options, :update_index_on_update => ElasticSearchable::Callbacks.backgrounded_options
|
13
|
-
class << self
|
14
|
-
backgrounded :delete_id_from_index => ElasticSearchable::Callbacks.backgrounded_options
|
15
|
-
end
|
16
|
-
|
17
|
-
define_callbacks :after_index_on_create, :after_index_on_update, :after_index
|
18
|
-
after_commit_on_create :update_index_on_create_backgrounded, :if => :should_index?
|
19
|
-
after_commit_on_update :update_index_on_update_backgrounded, :if => :should_index?
|
20
|
-
after_commit_on_destroy Proc.new {|o| o.class.delete_id_from_index_backgrounded(o.id) }
|
3
|
+
class << self
|
4
|
+
def backgrounded_options
|
5
|
+
{:queue => 'elasticsearch'}
|
21
6
|
end
|
22
7
|
end
|
23
8
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
9
|
+
module InstanceMethods
|
10
|
+
private
|
11
|
+
def delete_from_index
|
12
|
+
self.class.delete_id_from_index_backgrounded self.id
|
13
|
+
end
|
14
|
+
def update_index_on_create
|
15
|
+
index_in_elastic_search :create
|
16
|
+
end
|
17
|
+
def update_index_on_update
|
18
|
+
index_in_elastic_search :update
|
19
|
+
end
|
29
20
|
end
|
30
21
|
end
|
31
22
|
end
|
@@ -1,17 +1,6 @@
|
|
1
1
|
module ElasticSearchable
|
2
|
-
module
|
3
|
-
module
|
4
|
-
|
5
|
-
# helper method to clean out existing index and reindex all objects
|
6
|
-
def rebuild_index
|
7
|
-
self.clean_index
|
8
|
-
self.update_index_mapping
|
9
|
-
self.find_each do |record|
|
10
|
-
record.index_in_elastic_search if record.should_index?
|
11
|
-
end
|
12
|
-
self.refresh_index
|
13
|
-
end
|
14
|
-
|
2
|
+
module Indexing
|
3
|
+
module ClassMethods
|
15
4
|
# delete all documents of this type in the index
|
16
5
|
# http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/delete_mapping/
|
17
6
|
def clean_index
|
@@ -29,7 +18,9 @@ module ElasticSearchable
|
|
29
18
|
# create the index
|
30
19
|
# http://www.elasticsearch.com/docs/elasticsearch/rest_api/admin/indices/create_index/
|
31
20
|
def create_index
|
32
|
-
|
21
|
+
options = self.elastic_options[:index_options] ? self.elastic_options[:index_options].to_json : ''
|
22
|
+
ElasticSearchable.request :put, index_path, :body => options
|
23
|
+
self.update_index_mapping
|
33
24
|
end
|
34
25
|
|
35
26
|
# explicitly refresh the index, making all operations performed since the last refresh
|
@@ -70,5 +61,61 @@ module ElasticSearchable
|
|
70
61
|
self.elastic_options[:type] || self.table_name
|
71
62
|
end
|
72
63
|
end
|
64
|
+
|
65
|
+
module InstanceMethods
|
66
|
+
# index the object in elasticsearch
|
67
|
+
# fire after_index callbacks after operation is complete
|
68
|
+
# see http://www.elasticsearch.org/guide/reference/api/index_.html
|
69
|
+
def index_in_elastic_search(lifecycle = nil)
|
70
|
+
query = {}
|
71
|
+
query.merge! :percolate => "*" if self.class.elastic_options[:percolate]
|
72
|
+
response = ElasticSearchable.request :put, self.class.index_type_path(self.id), :query => query, :body => self.indexed_json_document.to_json
|
73
|
+
|
74
|
+
self.run_callbacks("after_index_on_#{lifecycle}".to_sym) if lifecycle
|
75
|
+
self.run_callbacks(:after_index)
|
76
|
+
|
77
|
+
if percolate_callback = self.class.elastic_options[:percolate]
|
78
|
+
matches = response['matches']
|
79
|
+
self.send percolate_callback, matches if matches.any?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# document to index in elasticsearch
|
83
|
+
def indexed_json_document
|
84
|
+
self.as_json self.class.elastic_options[:json]
|
85
|
+
end
|
86
|
+
def should_index?
|
87
|
+
[self.class.elastic_options[:if]].flatten.compact.all? { |m| evaluate_elastic_condition(m) } &&
|
88
|
+
![self.class.elastic_options[:unless]].flatten.compact.any? { |m| evaluate_elastic_condition(m) }
|
89
|
+
end
|
90
|
+
# percolate this object to see what registered searches match
|
91
|
+
# can be done on transient/non-persisted objects!
|
92
|
+
# can be done automatically when indexing using :percolate => true config option
|
93
|
+
# http://www.elasticsearch.org/blog/2011/02/08/percolator.html
|
94
|
+
def percolate
|
95
|
+
response = ElasticSearchable.request :get, self.class.index_type_path('_percolate'), :body => {:doc => self.indexed_json_document}.to_json
|
96
|
+
response['matches']
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
# ripped from activesupport
|
101
|
+
def evaluate_elastic_condition(method)
|
102
|
+
case method
|
103
|
+
when Symbol
|
104
|
+
self.send method
|
105
|
+
when String
|
106
|
+
eval(method, self.instance_eval { binding })
|
107
|
+
when Proc, Method
|
108
|
+
method.call
|
109
|
+
else
|
110
|
+
if method.respond_to?(kind)
|
111
|
+
method.send kind
|
112
|
+
else
|
113
|
+
raise ArgumentError,
|
114
|
+
"Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
|
115
|
+
"a block to be invoked, or an object responding to the callback method."
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
73
120
|
end
|
74
121
|
end
|
data/lib/elastic_searchable.rb
CHANGED
@@ -23,14 +23,16 @@ module ElasticSearchable
|
|
23
23
|
def request(method, url, options = {})
|
24
24
|
response = self.send(method, url, options)
|
25
25
|
#puts "elasticsearch request: #{method} #{url} #{" finished in #{response['took']}ms" if response['took']}"
|
26
|
-
|
26
|
+
validate_response response
|
27
27
|
response
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
31
|
-
|
31
|
+
# all elasticsearch rest calls return a json response when an error occurs. ex:
|
32
|
+
# {error: 'an error occurred' }
|
33
|
+
def validate_response(response)
|
32
34
|
error = response['error'] || "Error executing request: #{response.inspect}"
|
33
|
-
raise ElasticSearchable::ElasticError.new(error) if response['error'] || !response.response.
|
35
|
+
raise ElasticSearchable::ElasticError.new(error) if response['error'] || ![Net::HTTPOK, Net::HTTPCreated].include?(response.response.class)
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
data/test/helper.rb
CHANGED
@@ -20,4 +20,7 @@ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
|
20
20
|
ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite'])
|
21
21
|
|
22
22
|
class Test::Unit::TestCase
|
23
|
+
def delete_index
|
24
|
+
ElasticSearchable.delete '/elastic_searchable' rescue nil
|
25
|
+
end
|
23
26
|
end
|
@@ -1,24 +1,5 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'helper')
|
2
2
|
|
3
|
-
module ElasticSearch
|
4
|
-
class Client
|
5
|
-
def index_mapping(*args)
|
6
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
7
|
-
indices = args.empty? ? [(default_index || :all)] : args.flatten
|
8
|
-
indices.collect! { |i| [:all].include?(i) ? "_#{i}" : i }
|
9
|
-
execute(:index_mapping, indices, options)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
module Transport
|
13
|
-
class HTTP
|
14
|
-
def index_mapping(index_list, options={})
|
15
|
-
standard_request(:get, {:index => index_list, :op => "_mapping"})
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
3
|
class TestElasticSearchable < Test::Unit::TestCase
|
23
4
|
ActiveRecord::Schema.define(:version => 1) do
|
24
5
|
create_table :posts, :force => true do |t|
|
@@ -36,10 +17,19 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
36
17
|
t.column :name, :string
|
37
18
|
t.column :favorite_color, :string
|
38
19
|
end
|
20
|
+
create_table :books, :force => true do |t|
|
21
|
+
t.column :title, :string
|
22
|
+
end
|
39
23
|
end
|
40
24
|
|
25
|
+
def setup
|
26
|
+
delete_index
|
27
|
+
end
|
28
|
+
def teardown
|
29
|
+
delete_index
|
30
|
+
end
|
41
31
|
class Post < ActiveRecord::Base
|
42
|
-
elastic_searchable
|
32
|
+
elastic_searchable :index_options => { "analysis.analyzer.default.tokenizer" => 'standard', "analysis.analyzer.default.filter" => ["standard", "lowercase", 'porterStem'] }
|
43
33
|
after_index :indexed
|
44
34
|
after_index_on_create :indexed_on_create
|
45
35
|
def indexed
|
@@ -67,7 +57,7 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
67
57
|
end
|
68
58
|
end
|
69
59
|
|
70
|
-
context '
|
60
|
+
context 'ElasticSearchable.request with invalid url' do
|
71
61
|
should 'raise error' do
|
72
62
|
assert_raises ElasticSearchable::ElasticError do
|
73
63
|
ElasticSearchable.request :get, '/elastic_searchable/foobar/notfound'
|
@@ -75,22 +65,31 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
75
65
|
end
|
76
66
|
end
|
77
67
|
|
78
|
-
context '
|
68
|
+
context 'Post.create_index' do
|
79
69
|
setup do
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
70
|
+
Post.create_index
|
71
|
+
@status = ElasticSearchable.request :get, '/elastic_searchable/_status'
|
72
|
+
end
|
73
|
+
should 'have created index' do
|
74
|
+
assert @status['ok']
|
75
|
+
end
|
76
|
+
should 'have used custom index_options' do
|
77
|
+
expected = {
|
78
|
+
"index.number_of_replicas" => "1",
|
79
|
+
"index.number_of_shards" => "5",
|
80
|
+
"index.analysis.analyzer.default.tokenizer" => "standard",
|
81
|
+
"index.analysis.analyzer.default.filter.0" => "standard",
|
82
|
+
"index.analysis.analyzer.default.filter.1" => "lowercase",
|
83
|
+
"index.analysis.analyzer.default.filter.2" => "porterStem"
|
84
|
+
}
|
85
|
+
assert_equal expected, @status['indices']['elastic_searchable']['settings'], @status.inspect
|
85
86
|
end
|
87
|
+
end
|
86
88
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
92
|
-
should 'have created index' do
|
93
|
-
assert @status['ok']
|
89
|
+
context 'deleting object that does not exist in search index' do
|
90
|
+
should 'raise error' do
|
91
|
+
assert_raises ElasticSearchable::ElasticError do
|
92
|
+
Post.delete_id_from_index 123
|
94
93
|
end
|
95
94
|
end
|
96
95
|
end
|
@@ -109,10 +108,9 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
109
108
|
|
110
109
|
context 'with index containing multiple results' do
|
111
110
|
setup do
|
112
|
-
Post.
|
111
|
+
Post.create_index
|
113
112
|
@first_post = Post.create :title => 'foo', :body => "first bar"
|
114
113
|
@second_post = Post.create :title => 'foo', :body => "second bar"
|
115
|
-
Post.rebuild_index
|
116
114
|
Post.refresh_index
|
117
115
|
end
|
118
116
|
|
@@ -121,7 +119,7 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
121
119
|
@results = Post.search 'first'
|
122
120
|
end
|
123
121
|
should 'find created object' do
|
124
|
-
|
122
|
+
assert_contains @results, @first_post
|
125
123
|
end
|
126
124
|
should 'be paginated' do
|
127
125
|
assert_equal 1, @results.current_page
|
@@ -135,8 +133,11 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
135
133
|
setup do
|
136
134
|
@results = Post.search 'foo', :page => 2, :per_page => 1, :sort => 'id'
|
137
135
|
end
|
138
|
-
should 'find
|
139
|
-
|
136
|
+
should 'not find objects from first page' do
|
137
|
+
assert_does_not_contain @results, @first_post
|
138
|
+
end
|
139
|
+
should 'find second object' do
|
140
|
+
assert_contains @results, @second_post
|
140
141
|
end
|
141
142
|
should 'be paginated' do
|
142
143
|
assert_equal 2, @results.current_page
|
@@ -152,6 +153,7 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
152
153
|
end
|
153
154
|
should 'sort results correctly' do
|
154
155
|
assert_equal @second_post, @results.first
|
156
|
+
assert_equal @first_post, @results.last
|
155
157
|
end
|
156
158
|
end
|
157
159
|
|
@@ -174,21 +176,17 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
174
176
|
false
|
175
177
|
end
|
176
178
|
end
|
177
|
-
context 'activerecord class with :if=>proc' do
|
179
|
+
context 'activerecord class with optional :if=>proc configuration' do
|
178
180
|
context 'when creating new instance' do
|
179
181
|
setup do
|
180
182
|
Blog.any_instance.expects(:index_in_elastic_search).never
|
181
|
-
Blog.create! :title => 'foo'
|
183
|
+
@blog = Blog.create! :title => 'foo'
|
182
184
|
end
|
183
185
|
should 'not index record' do end #see expectations
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
Blog.any_instance.expects(:index_in_elastic_search).never
|
188
|
-
Blog.create! :title => 'foo'
|
189
|
-
Blog.rebuild_index
|
186
|
+
should 'not be found in elasticsearch' do
|
187
|
+
@request = ElasticSearchable.get "/elastic_searchable/blogs/#{@blog.id}"
|
188
|
+
assert @request.response.is_a?(Net::HTTPNotFound), @request.inspect
|
190
189
|
end
|
191
|
-
should 'not index record' do end #see expectations
|
192
190
|
end
|
193
191
|
end
|
194
192
|
|
@@ -198,7 +196,7 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
198
196
|
context 'activerecord class with :mapping=>{}' do
|
199
197
|
context 'creating index' do
|
200
198
|
setup do
|
201
|
-
User.
|
199
|
+
User.create_index
|
202
200
|
@status = ElasticSearchable.request :get, '/elastic_searchable/users/_mapping'
|
203
201
|
end
|
204
202
|
should 'have set mapping' do
|
@@ -217,15 +215,15 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
217
215
|
class Friend < ActiveRecord::Base
|
218
216
|
elastic_searchable :json => {:only => [:name]}
|
219
217
|
end
|
220
|
-
context 'activerecord class with :json
|
218
|
+
context 'activerecord class with optiona :json config' do
|
221
219
|
context 'creating index' do
|
222
220
|
setup do
|
223
|
-
Friend.
|
221
|
+
Friend.create_index
|
224
222
|
@friend = Friend.create! :name => 'bob', :favorite_color => 'red'
|
225
|
-
Friend.
|
223
|
+
Friend.refresh_index
|
226
224
|
end
|
227
225
|
should 'index json with configuration' do
|
228
|
-
@response = ElasticSearchable.request :get, "/
|
226
|
+
@response = ElasticSearchable.request :get, "/elastic_searchable/friends/#{@friend.id}"
|
229
227
|
expected = {
|
230
228
|
"name" => 'bob' #favorite_color should not be indexed
|
231
229
|
}
|
@@ -245,4 +243,44 @@ class TestElasticSearchable < Test::Unit::TestCase
|
|
245
243
|
assert_equal 'my_new_index', ElasticSearchable.default_index
|
246
244
|
end
|
247
245
|
end
|
246
|
+
|
247
|
+
class Book < ActiveRecord::Base
|
248
|
+
elastic_searchable :percolate => :on_percolated
|
249
|
+
def on_percolated(percolated)
|
250
|
+
@percolated = percolated
|
251
|
+
end
|
252
|
+
def percolated
|
253
|
+
@percolated
|
254
|
+
end
|
255
|
+
end
|
256
|
+
context 'Book class with percolate=true' do
|
257
|
+
context 'with created index' do
|
258
|
+
setup do
|
259
|
+
Book.create_index
|
260
|
+
end
|
261
|
+
context "when index has configured percolation" do
|
262
|
+
setup do
|
263
|
+
ElasticSearchable.request :put, '/_percolator/elastic_searchable/myfilter', :body => {:query => {:query_string => {:query => 'foo' }}}.to_json
|
264
|
+
ElasticSearchable.request :post, '/_percolator/_refresh'
|
265
|
+
end
|
266
|
+
context 'creating an object that matches the percolation' do
|
267
|
+
setup do
|
268
|
+
@book = Book.create :title => "foo"
|
269
|
+
end
|
270
|
+
should 'return percolated matches in the callback' do
|
271
|
+
assert_equal ['myfilter'], @book.percolated
|
272
|
+
end
|
273
|
+
end
|
274
|
+
context 'percolating a non-persisted object' do
|
275
|
+
setup do
|
276
|
+
@matches = Book.new(:title => 'foo').percolate
|
277
|
+
end
|
278
|
+
should 'return percolated matches' do
|
279
|
+
assert_equal ['myfilter'], @matches
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
248
285
|
end
|
286
|
+
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elastic_searchable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ryan Sonnek
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-22 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -243,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
243
243
|
requirements: []
|
244
244
|
|
245
245
|
rubyforge_project:
|
246
|
-
rubygems_version: 1.5.
|
246
|
+
rubygems_version: 1.5.2
|
247
247
|
signing_key:
|
248
248
|
specification_version: 3
|
249
249
|
summary: elastic search for activerecord
|