mongoid-elasticsearch 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 227f98096d3f8725368150c8a275001d4b308fe8
4
- data.tar.gz: 5385ffd8dd90ca8397731a1ab73f0f63cda66a59
3
+ metadata.gz: 817468060649097bdc9d2087961b3c1e48a3f3bf
4
+ data.tar.gz: 11a922cfb895f5d0876148f98f69582ed267209a
5
5
  SHA512:
6
- metadata.gz: 86ae14cde369b32a520d6502af4a33b717f357c22cc7eaaf4c5cf2d585c93371dd38522588f447360f3ee3463b89da9264cebcea41531fe892de953793c7564a
7
- data.tar.gz: 696b7ba51d63adf247a37b5cd633985b2303a5914c838c0509f003197346d94eabc5933dd7ac64560610637aa5e1ba6ef1f834d775686dcc04e53a8f3d8b3641
6
+ metadata.gz: 8108f386fc0005c154d79cc7cf0b9e91d40545295880240781e62b9ec6a58f81e08d73fdfa7eabeaf19e6ed7418e7406f3971deee9d3b08c3bf9b655b4c4b972
7
+ data.tar.gz: 6c2cd84050776f09459cddb15c11526c13a55ed6f1719dba9183e869eed87f9e283de44c490ce9fcab9a3380e24585c5a572dd4272c4d7d19e08067dbea6cecc
data/.travis.yml CHANGED
@@ -10,10 +10,16 @@ rvm:
10
10
  - 1.9.3
11
11
  - 2.0.0
12
12
  - jruby-19mode
13
- # mongoid 4 has problems
14
- #- rbx-19mode
13
+ - ruby-head
15
14
 
16
15
  gemfile:
17
16
  - Gemfile
18
17
  - gemfiles/mongoid-4.0.gemfile
18
+ - gemfiles/es-git.gemfile
19
+ - gemfiles/es-0.4.0.gemfile
20
+ - gemfiles/es-0.4.1.gemfile
19
21
 
22
+ matrix:
23
+ allow_failures:
24
+ - rvm: ruby-head
25
+
data/README.md CHANGED
@@ -29,11 +29,12 @@ This gem is very simple and does not try hide any part of the ES REST api, it
29
29
  a model instance, ES 0.90.3 new completion suggester, etc (new features coming
30
30
  soon)
31
31
 
32
- ## Why use it (alternatives list):
32
+ ## Alternatives list:
33
33
 
34
- - [(re)Tire](https://github.com/karmi/retire) - retired
35
- - [RubberBand](https://github.com/grantr/rubberband) - EOL
36
- - [Elasticsearch gem](https://github.com/elasticsearch/elasticsearch-ruby) - too low-level and complex
34
+ - [Elasticsearch gem](https://github.com/elasticsearch/elasticsearch-ruby) - low-level and hard for simple use-cases
35
+ - [(re)Tire](https://github.com/karmi/retire)
36
+ - [RubberBand](https://github.com/grantr/rubberband) - EOL, no Mongoid
37
+ - [Mebla](https://github.com/cousine/mebla) - long dead
37
38
 
38
39
  ## Installation
39
40
 
@@ -60,7 +61,7 @@ Or install it yourself as:
60
61
  end
61
62
 
62
63
  Post.es.search 'test text' # shortcut for Post.es.search({q: 'test text'})
63
- result = Post.es.search query: {...}, facets: {...} etc
64
+ result = Post.es.search body: {query: {...}, facets: {...}} etc
64
65
  result.raw_response
65
66
  result.results # by default returns an Enumerable with Post instances exactly
66
67
  # like they were loaded from MongoDB
@@ -77,26 +78,50 @@ Or install it yourself as:
77
78
  response = Mongoid::Elasticsearch.search 'test'
78
79
 
79
80
 
81
+ search syntax docs: http://rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Actions#search-instance_method
82
+
80
83
  more docs: http://rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Actions
81
84
 
82
85
  ES docs: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/index.html
83
86
 
84
87
  ### Advanced:
85
88
 
89
+ prefix all app's index names:
90
+
91
+ Mongoid::Elasticsearch.prefix = 'my_app'
92
+
93
+ default options for Elasticsearch::Client.new (url etc)
94
+
95
+ Mongoid::Elasticsearch.client_options = {hosts: ['localhost']}
96
+
97
+ index definition options and custom model serialization:
98
+
86
99
  include Mongoid::Elasticsearch
87
- # define index_options (raw elasticsearch index definition
88
- #
89
- elasticsearch! index_name: 'mongoid_es_news', prefix_name: false, index_options: {}, index_mappings: {
90
- name: {
91
- type: 'multi_field',
92
- fields: {
93
- name: {type: 'string', analyzer: 'snowball'},
94
- raw: {type: 'string', index: :not_analyzed},
95
- suggest: {type: 'completion'}
96
- }
100
+ elasticsearch!({
101
+ # index name (prefix is added)
102
+ index_name: 'mongoid_es_news',
103
+
104
+ # don't use global name prefix
105
+ prefix_name: false,
106
+
107
+ # elasticsearch index definition
108
+ index_options: {},
109
+
110
+ # or only mappings with empty options
111
+ index_mappings: {
112
+ name: {
113
+ type: 'multi_field',
114
+ fields: {
115
+ name: {type: 'string', analyzer: 'snowball'},
116
+ raw: {type: 'string', index: :not_analyzed},
117
+ suggest: {type: 'completion'}
118
+ }
119
+ },
120
+ tags: {type: 'string', include_in_all: false}
97
121
  },
98
- tags: {type: 'string', include_in_all: false}
99
- }, wrapper: :load
122
+ wrapper: :load
123
+ })
124
+
100
125
  # customize what gets sent to elasticsearch:
101
126
  def as_indexed_json
102
127
  # id field is properly added automatically
@@ -106,6 +131,15 @@ ES docs: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/i
106
131
  }
107
132
  end
108
133
 
134
+ [Mapping definition docs](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-core-types.html)
135
+
136
+ ### Possible wrappers for results:
137
+
138
+ - :hash - raw hash from ES
139
+ - :mash - [Hashie::Mash](https://github.com/intridea/hashie#mash) (gem '[hashie](https://github.com/intridea/hashie)' must be added to gemfile)
140
+ - :load - load each found model by ID from database
141
+ - :model - create a model instance from data stored in elasticsearch
142
+
109
143
  See more examples in specs.
110
144
 
111
145
  ## Contributing
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mongoid", github: "mongoid/mongoid", branch: "master"
4
+ gem 'elasticsearch', '0.4.0'
5
+
6
+ gemspec path: "../"
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mongoid", github: "mongoid/mongoid", branch: "master"
4
+ gem 'elasticsearch', '0.4.1'
5
+
6
+ gemspec path: "../"
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mongoid", github: "mongoid/mongoid", branch: "master"
4
+ gem 'elasticsearch', github: 'elasticsearch/elasticsearch-ruby', branch: "master"
5
+
6
+ gemspec path: "../"
@@ -29,27 +29,29 @@ module Mongoid
29
29
  query[:size] = ( per_page.to_i ) if per_page
30
30
  query[:from] = ( page.to_i <= 1 ? 0 : (per_page.to_i * (page.to_i-1)) ) if page && per_page
31
31
 
32
- Response.new(client, query.merge(type_options(true)), false, klass, klass.es_wrapper, options)
32
+ options[:wrapper] ||= klass.es_wrapper
33
+
34
+ Response.new(client, query.merge(type_options), false, klass, options)
33
35
  end
34
36
 
35
- def options_for(obj, escape = false)
36
- {id: obj.id.to_s}.merge type_options(escape)
37
+ def all(options = {})
38
+ search({body: {query: {match_all: {}}}}, options)
37
39
  end
38
40
 
39
- def type_options(escape = false)
40
- {index: index.name, type: escape ? Utils.escape(index.type) : index.type}
41
+ def options_for(obj)
42
+ {id: obj.id.to_s}.merge type_options
41
43
  end
42
44
 
43
- def index_item(obj)
44
- client.index({body: obj.as_indexed_json}.merge(options_for(obj, true)))
45
+ def type_options
46
+ {index: index.name, type: index.type}
45
47
  end
46
48
 
47
- def remove_item(obj)
48
- client.delete(options_for(obj, true).merge(ignore: 404))
49
+ def index_item(obj)
50
+ client.index({body: obj.as_indexed_json}.merge(options_for(obj)))
49
51
  end
50
52
 
51
- def all(options = {})
52
- search({match_all: {}}, options)
53
+ def remove_item(obj)
54
+ client.delete(options_for(obj).merge(ignore: 404))
53
55
  end
54
56
 
55
57
  def completion_supported?
@@ -14,7 +14,7 @@ module Mongoid
14
14
  end
15
15
 
16
16
  def type
17
- klass.model_name.collection
17
+ klass.model_name.collection.singularize
18
18
  end
19
19
 
20
20
  def options
@@ -11,12 +11,12 @@ module Mongoid
11
11
  attr_reader :time, :total, :options, :facets, :max
12
12
  attr_reader :response
13
13
 
14
- def initialize(client, query, multi, model, wrapper, options)
14
+ def initialize(client, query, multi, model, options)
15
15
  @client = client
16
16
  @query = query
17
17
  @multi = multi
18
18
  @model = model
19
- @wrapper = wrapper
19
+ @wrapper = options[:wrapper]
20
20
  @options = options
21
21
  end
22
22
 
@@ -44,7 +44,7 @@ module Mongoid
44
44
  end
45
45
 
46
46
  def hits
47
- @hits ||= raw_response['hits']['hits'].map { |d| d.update '_type' => Utils.unescape(d['_type']) }
47
+ @hits ||= raw_response['hits']['hits']
48
48
  end
49
49
 
50
50
  def results
@@ -59,7 +59,8 @@ module Mongoid
59
59
  end
60
60
  when :mash
61
61
  hits.map do |h|
62
- m = Hashie::Mash.new(h)
62
+ s = h.delete('_source')
63
+ m = Hashie::Mash.new(h.merge(s))
63
64
  m.id = BSON::ObjectId.from_string(h['_id'])
64
65
  m._id = m.id
65
66
  m
@@ -7,7 +7,7 @@ module Elasticsearch
7
7
  module Utils
8
8
  alias_method :__pathify_without_slashes, :__pathify
9
9
  def __pathify(*segments)
10
- __pathify_without_slashes(*segments).gsub('%252F', '%2F')
10
+ __pathify_without_slashes(*segments.map { |s| s.gsub('/', '%2F')}).gsub('%252F', '%2F')
11
11
  end
12
12
  end
13
13
  end
@@ -4,16 +4,6 @@ require 'uri'
4
4
  module Mongoid
5
5
  module Elasticsearch
6
6
  module Utils
7
-
8
- def escape(s)
9
- URI.encode_www_form_component(s.to_s)
10
- end
11
-
12
- def unescape(s)
13
- s = s.to_s.respond_to?(:force_encoding) ? s.to_s.force_encoding(Encoding::UTF_8) : s.to_s
14
- URI.decode_www_form_component(s)
15
- end
16
-
17
7
  def clean(s)
18
8
  s.to_s.gsub(/\W+/, ' ').gsub(/ +/, '').strip
19
9
  end
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Elasticsearch
3
- VERSION = "0.2.1"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -9,7 +9,10 @@ require 'mongoid/elasticsearch/callbacks'
9
9
  require 'mongoid/elasticsearch/index'
10
10
  require 'mongoid/elasticsearch/indexing'
11
11
  require 'mongoid/elasticsearch/response'
12
- require 'mongoid/elasticsearch/slash_monkeypatch'
12
+
13
+ if Elasticsearch::VERSION < '0.4.1'
14
+ require 'mongoid/elasticsearch/slash_monkeypatch'
15
+ end
13
16
 
14
17
  module Mongoid
15
18
  module Elasticsearch
@@ -81,7 +84,7 @@ module Mongoid
81
84
  end
82
85
 
83
86
  # search multiple models
84
- def self.search(query, options = {}, wrapper = :model)
87
+ def self.search(query, options = {})
85
88
  if query.is_a?(String)
86
89
  query = {q: Utils.clean(query)}
87
90
  end
@@ -98,9 +101,10 @@ module Mongoid
98
101
  query[:size] = ( per_page.to_i ) if per_page
99
102
  query[:from] = ( page.to_i <= 1 ? 0 : (per_page.to_i * (page.to_i-1)) ) if page && per_page
100
103
 
104
+ options[:wrapper] ||= :model
101
105
 
102
106
  client = ::Elasticsearch::Client.new Mongoid::Elasticsearch.client_options
103
- Response.new(client, query, true, nil, wrapper, options)
107
+ Response.new(client, query, true, nil, options)
104
108
  end
105
109
  end
106
110
  end
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency "kaminari"
28
28
  spec.add_development_dependency "database_cleaner"
29
29
  spec.add_development_dependency "coveralls"
30
+ spec.add_development_dependency "hashie"
30
31
  end
@@ -4,7 +4,7 @@ describe Article do
4
4
  it 'properly uses options' do
5
5
  Article.es_index_name.should eq 'mongoid_es_news'
6
6
  Article.es.index.name.should eq 'mongoid_es_news'
7
- Article.es.index.type.should eq 'articles'
7
+ Article.es.index.type.should eq 'article'
8
8
  Article.es_wrapper.should eq :load
9
9
  Article.es_client_options.should eq({})
10
10
  end
@@ -210,13 +210,20 @@ describe "Multisearch" do
210
210
  response.to_a.map(&:class).map(&:name).uniq.sort.should eq ['Article', 'Namespaced::Model', 'Post']
211
211
  response.select { |r| r.class == Article && r.id == @article_1.id }.first.should_not be_nil
212
212
  end
213
+
214
+ it '#multi_with_load' do
215
+ response = Mongoid::Elasticsearch.search 'test', wrapper: :load
216
+ response.length.should eq 4
217
+ response.to_a.map(&:class).map(&:name).uniq.sort.should eq ['Article', 'Namespaced::Model', 'Post']
218
+ response.select { |r| r.class == Article && r.id == @article_1.id }.first.should_not be_nil
219
+ end
213
220
  end
214
221
 
215
222
  describe Namespaced::Model do
216
223
  it 'properly uses options' do
217
224
  Namespaced::Model.es_index_name.should eq 'mongoid_es_test_namespaced_models'
218
225
  Namespaced::Model.es.index.name.should eq 'mongoid_es_test_namespaced_models'
219
- Namespaced::Model.es.index.type.should eq 'namespaced/models'
226
+ Namespaced::Model.es.index.type.should eq 'namespaced/model'
220
227
  Namespaced::Model.es_wrapper.should eq :model
221
228
  Namespaced::Model.es_client_options.should eq({})
222
229
  end
@@ -265,28 +272,45 @@ describe Namespaced::Model do
265
272
 
266
273
  context 'pagination' do
267
274
  before :each do
275
+ Namespaced::Model.es.index.reset
268
276
  @articles = []
269
277
  20.times { @articles << Namespaced::Model.create!(name: 'test') }
278
+ @a1 = Namespaced::Model.create!(name: 'irrelevant')
279
+ @a2 = Namespaced::Model.create!(name: 'unmatched')
270
280
  Namespaced::Model.es.index.refresh
271
281
  end
272
282
 
283
+ it '#search ignores irrelevant' do
284
+ Namespaced::Model.es.search('irrelevant').to_a.size.should eq 1
285
+ Namespaced::Model.es.search('test').to_a.size.should eq 20
286
+ end
287
+
288
+ it '#search dynamic wrapper' do
289
+ Namespaced::Model.es.search('test', wrapper: :hash).map(&:class).map(&:name).uniq.should eq ['Hash']
290
+ Namespaced::Model.es.search('test', wrapper: :mash).map(&:class).map(&:name).uniq.should eq ['Hashie::Mash']
291
+ Namespaced::Model.es.search('test', wrapper: :mash).first.name.should eq 'test'
292
+ end
293
+
273
294
  it '#search' do
274
295
  Namespaced::Model.es.search('test', per_page: 10, page: 2).to_a.size.should eq 10
275
296
  Namespaced::Model.es.search('test', per_page: 30, page: 2).to_a.size.should eq 0
276
297
  Namespaced::Model.es.search('test', per_page: 2, page: 2).to_a.size.should eq 2
298
+ Namespaced::Model.es.search(body: {query: {query_string: {query: 'test'}}}).to_a.length.should eq 20
277
299
  end
278
300
 
279
301
  it '#all' do
280
302
  result = Namespaced::Model.es.all(per_page: 7, page: 3)
281
- result.num_pages.should eq 3
282
- result.to_a.size.should eq 6
303
+ result.num_pages.should eq 4
304
+ result.to_a.size.should eq 7
283
305
  p1 = Namespaced::Model.es.all(per_page: 7, page: 1).to_a
284
306
  p2 = Namespaced::Model.es.all(per_page: 7, page: 2).to_a
307
+ p4 = Namespaced::Model.es.all(per_page: 7, page: 4).to_a
285
308
  p1.length.should eq 7
286
309
  p2.length.should eq 7
287
- all = (result.to_a + p1 + p2).map(&:id).map(&:to_s).sort
288
- all.length.should eq 20
289
- all.should eq @articles.map(&:id).map(&:to_s).sort
310
+ p4.length.should eq 1
311
+ all = (p1 + p2 + result.to_a + p4).map(&:id).map(&:to_s).sort
312
+ all.length.should eq 22
313
+ all.should eq (@articles + [@a1, @a2]).map(&:id).map(&:to_s).sort
290
314
  end
291
315
  end
292
316
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,11 @@
1
+ require 'simplecov'
1
2
  require 'coveralls'
2
- Coveralls.wear!
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+ SimpleCov.start
3
9
 
4
10
  $LOAD_PATH.unshift(File.dirname(__FILE__))
5
11
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
@@ -9,6 +15,7 @@ MODELS = File.join(File.dirname(__FILE__), "models")
9
15
  require "rubygems"
10
16
  require "rspec"
11
17
  require "mongoid"
18
+ require "hashie"
12
19
  require "database_cleaner"
13
20
 
14
21
  require "mongoid-elasticsearch"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - glebtv
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-18 00:00:00.000000000 Z
11
+ date: 2013-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mongoid
@@ -128,6 +128,20 @@ dependencies:
128
128
  - - '>='
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: hashie
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - '>='
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
131
145
  description: Simple and easy integration of mongoid with the new elasticsearch gem
132
146
  email:
133
147
  - glebtv@gmail.com
@@ -145,6 +159,9 @@ files:
145
159
  - MIT-LICENSE.txt
146
160
  - README.md
147
161
  - Rakefile
162
+ - gemfiles/es-0.4.0.gemfile
163
+ - gemfiles/es-0.4.1.gemfile
164
+ - gemfiles/es-git.gemfile
148
165
  - gemfiles/mongoid-4.0.gemfile
149
166
  - lib/mongoid-elasticsearch.rb
150
167
  - lib/mongoid/elasticsearch.rb