elasticsearch-model 0.1.9 → 2.0.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +53 -10
- data/Rakefile +24 -15
- data/elasticsearch-model.gemspec +8 -11
- data/examples/activerecord_article.rb +1 -1
- data/examples/activerecord_associations.rb +7 -6
- data/gemfiles/5.0.gemfile +12 -0
- data/lib/elasticsearch/model.rb +25 -1
- data/lib/elasticsearch/model/adapters/active_record.rb +6 -3
- data/lib/elasticsearch/model/naming.rb +26 -2
- data/lib/elasticsearch/model/response.rb +1 -1
- data/lib/elasticsearch/model/response/aggregations.rb +36 -0
- data/lib/elasticsearch/model/version.rb +1 -1
- data/test/integration/active_record_associations_parent_child.rb +11 -3
- data/test/integration/active_record_associations_test.rb +73 -59
- data/test/integration/active_record_basic_test.rb +43 -26
- data/test/integration/active_record_custom_serialization_test.rb +5 -0
- data/test/integration/active_record_import_test.rb +19 -13
- data/test/integration/active_record_namespaced_model_test.rb +5 -0
- data/test/integration/active_record_pagination_test.rb +18 -14
- data/test/integration/dynamic_index_name_test.rb +5 -0
- data/test/integration/multiple_models_test.rb +29 -25
- data/test/unit/indexing_test.rb +4 -4
- data/test/unit/module_test.rb +11 -0
- data/test/unit/naming_inheritance_test.rb +94 -0
- data/test/unit/response_aggregations_test.rb +46 -0
- data/test/unit/response_result_test.rb +1 -1
- metadata +34 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f2934457bc9ab48762cfab715d994d56b9421f0
|
4
|
+
data.tar.gz: 4c7ed85875ee9ab58ff390ad1e6e7a13d576807b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df184cea73c42757b1c52afe22c009000310eaf5383d01b82055e51cb953f86701584b5afc56dadb9ef811e4ca87c92e8e67c9a7e84ef3a3bab680330c27f445
|
7
|
+
data.tar.gz: 34e576da4c6d6e0ea80ed5f175c226f1583332c29d3eb0fc8b488d4f7dbc0222ea3eba5e87001e7c3a7e79493a230cba402acfc7adcfa5b150d7e86e0a7086f0
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,25 @@
|
|
1
1
|
# Elasticsearch::Model
|
2
2
|
|
3
3
|
The `elasticsearch-model` library builds on top of the
|
4
|
-
the [`elasticsearch`](https://github.com/
|
4
|
+
the [`elasticsearch`](https://github.com/elastic/elasticsearch-ruby) library.
|
5
5
|
|
6
6
|
It aims to simplify integration of Ruby classes ("models"), commonly found
|
7
7
|
e.g. in [Ruby on Rails](http://rubyonrails.org) applications, with the
|
8
8
|
[Elasticsearch](http://www.elasticsearch.org) search and analytics engine.
|
9
9
|
|
10
|
-
|
10
|
+
## Compatibility
|
11
|
+
|
12
|
+
This library is compatible with Ruby 1.9.3 and higher.
|
13
|
+
|
14
|
+
The library version numbers follow the Elasticsearch major versions, and the `master` branch
|
15
|
+
is compatible with the Elasticsearch `master` branch, therefore, with the next major version.
|
16
|
+
|
17
|
+
| Rubygem | | Elasticsearch |
|
18
|
+
|:-------------:|:-:| :-----------: |
|
19
|
+
| 0.1 | → | 1.x |
|
20
|
+
| 2.x | → | 2.x |
|
21
|
+
| 5.x | → | 5.x |
|
22
|
+
| master | → | master |
|
11
23
|
|
12
24
|
## Installation
|
13
25
|
|
@@ -17,11 +29,11 @@ Install the package from [Rubygems](https://rubygems.org):
|
|
17
29
|
|
18
30
|
To use an unreleased version, either add it to your `Gemfile` for [Bundler](http://bundler.io):
|
19
31
|
|
20
|
-
gem 'elasticsearch-model', git: 'git://github.com/
|
32
|
+
gem 'elasticsearch-model', git: 'git://github.com/elastic/elasticsearch-rails.git', branch: '5.x'
|
21
33
|
|
22
34
|
or install it from a source code checkout:
|
23
35
|
|
24
|
-
git clone https://github.com/
|
36
|
+
git clone https://github.com/elastic/elasticsearch-rails.git
|
25
37
|
cd elasticsearch-rails/elasticsearch-model
|
26
38
|
bundle install
|
27
39
|
rake install
|
@@ -109,7 +121,7 @@ See the `Elasticsearch::Model` module documentation for technical information.
|
|
109
121
|
|
110
122
|
### The Elasticsearch client
|
111
123
|
|
112
|
-
The module will set up a [client](https://github.com/
|
124
|
+
The module will set up a [client](https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch),
|
113
125
|
connected to `localhost:9200`, by default. You can access and use it as any other `Elasticsearch::Client`:
|
114
126
|
|
115
127
|
```ruby
|
@@ -132,7 +144,7 @@ Elasticsearch::Model.client = Elasticsearch::Client.new log: true
|
|
132
144
|
You might want to do this during your application bootstrap process, e.g. in a Rails initializer.
|
133
145
|
|
134
146
|
Please refer to the
|
135
|
-
[`elasticsearch-transport`](https://github.com/
|
147
|
+
[`elasticsearch-transport`](https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-transport)
|
136
148
|
library documentation for all the configuration options, and to the
|
137
149
|
[`elasticsearch-api`](http://rubydoc.info/gems/elasticsearch-api) library documentation
|
138
150
|
for information about the Ruby client API.
|
@@ -241,7 +253,7 @@ response.records.order(:title).to_a
|
|
241
253
|
The `records` method returns the real instances of your model, which is useful when you want to access your
|
242
254
|
model methods -- at the expense of slowing down your application, of course.
|
243
255
|
In most cases, working with `results` coming from Elasticsearch is sufficient, and much faster. See the
|
244
|
-
[`elasticsearch-rails`](https://github.com/
|
256
|
+
[`elasticsearch-rails`](https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-rails)
|
245
257
|
library for more information about compatibility with the Ruby on Rails framework.
|
246
258
|
|
247
259
|
When you want to access both the database `records` and search `results`, use the `each_with_hit`
|
@@ -303,7 +315,7 @@ In a Rails controller, use the the `params[:page]` parameter to paginate through
|
|
303
315
|
To initialize and include the Kaminari pagination support manually:
|
304
316
|
|
305
317
|
```ruby
|
306
|
-
Kaminari::Hooks.init
|
318
|
+
Kaminari::Hooks.init if defined?(Kaminari::Hooks)
|
307
319
|
Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model::Response::Pagination::Kaminari
|
308
320
|
```
|
309
321
|
|
@@ -320,8 +332,8 @@ response.results.first.highlight.title
|
|
320
332
|
# ["Quick brown <em>fox</em>"]
|
321
333
|
```
|
322
334
|
|
323
|
-
You can pass any object which implements a `to_hash` method,
|
324
|
-
to build the search definition
|
335
|
+
You can pass any object which implements a `to_hash` method, which is called automatically,
|
336
|
+
so you can use a custom class or your favourite JSON builder to build the search definition:
|
325
337
|
|
326
338
|
```ruby
|
327
339
|
require 'jbuilder'
|
@@ -341,6 +353,25 @@ response.results.first.title
|
|
341
353
|
# => "Quick brown fox"
|
342
354
|
```
|
343
355
|
|
356
|
+
Also, you can use the [**`elasticsearch-dsl`**](https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-dsl) library, which provides a specialized Ruby API for
|
357
|
+
the Elasticsearch Query DSL:
|
358
|
+
|
359
|
+
```ruby
|
360
|
+
require 'elasticsearch/dsl'
|
361
|
+
|
362
|
+
query = Elasticsearch::DSL::Search.search do
|
363
|
+
query do
|
364
|
+
match :title do
|
365
|
+
query 'fox dogs'
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
response = Article.search query
|
371
|
+
response.results.first.title
|
372
|
+
# => "Quick brown fox"
|
373
|
+
```
|
374
|
+
|
344
375
|
### Index Configuration
|
345
376
|
|
346
377
|
For proper search engine function, it's often necessary to configure the index properly.
|
@@ -685,6 +716,18 @@ response.records.records.class
|
|
685
716
|
More examples can be found in the `examples` folder. Please see the `Elasticsearch::Model::Adapter`
|
686
717
|
module and its submodules for technical information.
|
687
718
|
|
719
|
+
### Settings
|
720
|
+
|
721
|
+
The module provides a common `settings` method to customize various features.
|
722
|
+
|
723
|
+
At the moment, the only supported setting is `:inheritance_enabled`, which makes the class receiving the module
|
724
|
+
respect index names and document types of a super-class, eg. in case you're using "single table inheritance" (STI)
|
725
|
+
in Rails:
|
726
|
+
|
727
|
+
```ruby
|
728
|
+
Elasticsearch::Model.settings[:inheritance_enabled] = true
|
729
|
+
```
|
730
|
+
|
688
731
|
## Development and Community
|
689
732
|
|
690
733
|
For local development, clone the repository and run `bundle install`. See `rake -T` for a list of
|
data/Rakefile
CHANGED
@@ -4,40 +4,49 @@ desc "Run unit tests"
|
|
4
4
|
task :default => 'test:unit'
|
5
5
|
task :test => 'test:unit'
|
6
6
|
|
7
|
+
namespace :bundler do
|
8
|
+
desc "Install dependencies for all the Gemfiles"
|
9
|
+
task :install do
|
10
|
+
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/3.0.gemfile', __FILE__)}' bundle install"
|
11
|
+
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/4.0.gemfile', __FILE__)}' bundle install"
|
12
|
+
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/5.0.gemfile', __FILE__)}' bundle install"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
7
16
|
# ----- Test tasks ------------------------------------------------------------
|
8
17
|
|
9
18
|
require 'rake/testtask'
|
10
19
|
namespace :test do
|
11
|
-
|
12
|
-
ENV['CI_REPORTS'] ||= 'tmp/reports'
|
13
|
-
require 'ci/reporter/rake/minitest'
|
14
|
-
Rake::Task['ci:setup:minitest'].invoke
|
15
|
-
end
|
16
|
-
|
17
|
-
Rake::TestTask.new(:unit) do |test|
|
18
|
-
Rake::Task['test:ci_reporter'].invoke if ENV['CI']
|
20
|
+
Rake::TestTask.new(:run_unit) do |test|
|
19
21
|
test.libs << 'lib' << 'test'
|
20
22
|
test.test_files = FileList["test/unit/**/*_test.rb"]
|
21
|
-
|
22
|
-
|
23
|
+
test.verbose = false
|
24
|
+
test.warning = false
|
23
25
|
end
|
24
26
|
|
25
27
|
Rake::TestTask.new(:run_integration) do |test|
|
26
|
-
Rake::Task['test:ci_reporter'].invoke if ENV['CI']
|
27
28
|
test.libs << 'lib' << 'test'
|
28
29
|
test.test_files = FileList["test/integration/**/*_test.rb"]
|
30
|
+
test.verbose = false
|
31
|
+
test.warning = false
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Run unit tests against ActiveModel 3, 4 and 5"
|
35
|
+
task :unit do
|
36
|
+
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/3.0.gemfile', __FILE__)}' bundle exec rake test:run_unit"
|
37
|
+
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/4.0.gemfile', __FILE__)}' bundle exec rake test:run_unit"
|
38
|
+
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/5.0.gemfile', __FILE__)}' bundle exec rake test:run_unit"
|
29
39
|
end
|
30
40
|
|
31
|
-
desc "Run integration tests against ActiveModel 3 and
|
41
|
+
desc "Run integration tests against ActiveModel 3, 4 and 5"
|
32
42
|
task :integration do
|
33
|
-
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/3.0.gemfile', __FILE__)}' bundle exec rake test:run_integration"
|
43
|
+
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/3.0.gemfile', __FILE__)}' bundle exec rake test:run_integration"
|
34
44
|
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/4.0.gemfile', __FILE__)}' bundle exec rake test:run_integration"
|
45
|
+
sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/5.0.gemfile', __FILE__)}' bundle exec rake test:run_integration"
|
35
46
|
end
|
36
47
|
|
37
48
|
desc "Run unit and integration tests"
|
38
49
|
task :all do
|
39
|
-
Rake::Task['test:ci_reporter'].invoke if ENV['CI']
|
40
|
-
|
41
50
|
Rake::Task['test:unit'].invoke
|
42
51
|
Rake::Task['test:integration'].invoke
|
43
52
|
end
|
data/elasticsearch-model.gemspec
CHANGED
@@ -23,35 +23,32 @@ Gem::Specification.new do |s|
|
|
23
23
|
|
24
24
|
s.required_ruby_version = ">= 1.9.3"
|
25
25
|
|
26
|
-
s.add_dependency "elasticsearch", '
|
26
|
+
s.add_dependency "elasticsearch", '~> 1.1'
|
27
27
|
s.add_dependency "activesupport", '> 3'
|
28
28
|
s.add_dependency "hashie"
|
29
29
|
|
30
30
|
s.add_development_dependency "bundler", "~> 1.3"
|
31
|
-
s.add_development_dependency "rake", "
|
31
|
+
s.add_development_dependency "rake", "~> 11.1"
|
32
32
|
|
33
33
|
s.add_development_dependency "elasticsearch-extensions"
|
34
34
|
|
35
35
|
s.add_development_dependency "sqlite3"
|
36
|
-
s.add_development_dependency "activemodel", "> 3
|
36
|
+
s.add_development_dependency "activemodel", "> 3"
|
37
37
|
|
38
38
|
s.add_development_dependency "oj"
|
39
39
|
s.add_development_dependency "kaminari"
|
40
40
|
s.add_development_dependency "will_paginate"
|
41
41
|
|
42
|
-
s.add_development_dependency "minitest"
|
43
|
-
s.add_development_dependency "test-unit"
|
42
|
+
s.add_development_dependency "minitest"
|
43
|
+
s.add_development_dependency "test-unit"
|
44
44
|
s.add_development_dependency "shoulda-context"
|
45
45
|
s.add_development_dependency "mocha"
|
46
46
|
s.add_development_dependency "turn"
|
47
47
|
s.add_development_dependency "yard"
|
48
48
|
s.add_development_dependency "ruby-prof"
|
49
49
|
s.add_development_dependency "pry"
|
50
|
-
s.add_development_dependency "ci_reporter", "~> 1.9"
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
s.add_development_dependency "require-prof"
|
56
|
-
end
|
51
|
+
s.add_development_dependency "simplecov"
|
52
|
+
s.add_development_dependency "cane"
|
53
|
+
s.add_development_dependency "require-prof"
|
57
54
|
end
|
@@ -28,23 +28,23 @@ ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ":memory:
|
|
28
28
|
ActiveRecord::Schema.define(version: 1) do
|
29
29
|
create_table :categories do |t|
|
30
30
|
t.string :title
|
31
|
-
t.timestamps
|
31
|
+
t.timestamps null: false
|
32
32
|
end
|
33
33
|
|
34
34
|
create_table :authors do |t|
|
35
35
|
t.string :first_name, :last_name
|
36
|
-
t.timestamps
|
36
|
+
t.timestamps null: false
|
37
37
|
end
|
38
38
|
|
39
39
|
create_table :authorships do |t|
|
40
40
|
t.references :article
|
41
41
|
t.references :author
|
42
|
-
t.timestamps
|
42
|
+
t.timestamps null: false
|
43
43
|
end
|
44
44
|
|
45
45
|
create_table :articles do |t|
|
46
46
|
t.string :title
|
47
|
-
t.timestamps
|
47
|
+
t.timestamps null: false
|
48
48
|
end
|
49
49
|
|
50
50
|
create_table :articles_categories, id: false do |t|
|
@@ -54,9 +54,10 @@ ActiveRecord::Schema.define(version: 1) do
|
|
54
54
|
create_table :comments do |t|
|
55
55
|
t.string :text
|
56
56
|
t.references :article
|
57
|
-
t.timestamps
|
57
|
+
t.timestamps null: false
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
|
+
add_index(:comments, :article_id) unless index_exists?(:comments, :article_id)
|
60
61
|
end
|
61
62
|
|
62
63
|
# ----- Elasticsearch client setup ----------------------------------------------------------------
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Usage:
|
2
|
+
#
|
3
|
+
# $ BUNDLE_GEMFILE=./gemfiles/5.0.gemfile bundle install
|
4
|
+
# $ BUNDLE_GEMFILE=./gemfiles/5.0.gemfile bundle exec rake test:integration
|
5
|
+
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
|
8
|
+
gemspec path: '../'
|
9
|
+
|
10
|
+
gem 'activemodel', '~> 5'
|
11
|
+
gem 'activerecord', '~> 5'
|
12
|
+
gem 'sqlite3'
|
data/lib/elasticsearch/model.rb
CHANGED
@@ -31,6 +31,7 @@ require 'elasticsearch/model/response/result'
|
|
31
31
|
require 'elasticsearch/model/response/results'
|
32
32
|
require 'elasticsearch/model/response/records'
|
33
33
|
require 'elasticsearch/model/response/pagination'
|
34
|
+
require 'elasticsearch/model/response/aggregations'
|
34
35
|
require 'elasticsearch/model/response/suggestions'
|
35
36
|
|
36
37
|
require 'elasticsearch/model/ext/active_record'
|
@@ -129,8 +130,13 @@ module Elasticsearch
|
|
129
130
|
end
|
130
131
|
end
|
131
132
|
|
132
|
-
module
|
133
|
+
# Access the module settings
|
134
|
+
#
|
135
|
+
def self.settings
|
136
|
+
@settings ||= {}
|
137
|
+
end
|
133
138
|
|
139
|
+
module ClassMethods
|
134
140
|
# Get the client common for all models
|
135
141
|
#
|
136
142
|
# @example Get the client
|
@@ -180,6 +186,24 @@ module Elasticsearch
|
|
180
186
|
request = Searching::SearchRequest.new(models, query_or_payload, options)
|
181
187
|
Response::Response.new(models, request)
|
182
188
|
end
|
189
|
+
|
190
|
+
# Check if inheritance is enabled
|
191
|
+
#
|
192
|
+
# @note Inheritance is disabled by default.
|
193
|
+
#
|
194
|
+
def inheritance_enabled
|
195
|
+
@inheritance_enabled ||= false
|
196
|
+
end
|
197
|
+
|
198
|
+
# Enable inheritance of index_name and document_type
|
199
|
+
#
|
200
|
+
# @example Enable inheritance
|
201
|
+
#
|
202
|
+
# Elasticsearch::Model.inheritance_enabled = true
|
203
|
+
#
|
204
|
+
def inheritance_enabled=(inheritance_enabled)
|
205
|
+
@inheritance_enabled = inheritance_enabled
|
206
|
+
end
|
183
207
|
end
|
184
208
|
extend ClassMethods
|
185
209
|
|
@@ -26,14 +26,17 @@ module Elasticsearch
|
|
26
26
|
# by redefining `to_a`, unless the user has called `order()`
|
27
27
|
#
|
28
28
|
sql_records.instance_exec(response.response['hits']['hits']) do |hits|
|
29
|
-
|
29
|
+
ar_records_method_name = :to_a
|
30
|
+
ar_records_method_name = :records if defined?(::ActiveRecord) && ::ActiveRecord::VERSION::MAJOR >= 5
|
31
|
+
|
32
|
+
define_singleton_method(ar_records_method_name) do
|
30
33
|
if defined?(::ActiveRecord) && ::ActiveRecord::VERSION::MAJOR >= 4
|
31
34
|
self.load
|
32
35
|
else
|
33
36
|
self.__send__(:exec_queries)
|
34
37
|
end
|
35
38
|
@records.sort_by { |record| hits.index { |hit| hit['_id'].to_s == record.id.to_s } }
|
36
|
-
end
|
39
|
+
end if self
|
37
40
|
end
|
38
41
|
|
39
42
|
sql_records
|
@@ -42,7 +45,7 @@ module Elasticsearch
|
|
42
45
|
# Prevent clash with `ActiveSupport::Dependencies::Loadable`
|
43
46
|
#
|
44
47
|
def load
|
45
|
-
records.load
|
48
|
+
records.__send__(:load)
|
46
49
|
end
|
47
50
|
|
48
51
|
# Intercept call to the `order` method, so we can ignore the order from Elasticsearch
|
@@ -34,7 +34,7 @@ module Elasticsearch
|
|
34
34
|
if @index_name.respond_to?(:call)
|
35
35
|
@index_name.call
|
36
36
|
else
|
37
|
-
@index_name ||
|
37
|
+
@index_name || implicit(:index_name)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -58,7 +58,7 @@ module Elasticsearch
|
|
58
58
|
# Article.document_type "my-article"
|
59
59
|
#
|
60
60
|
def document_type name=nil
|
61
|
-
@document_type = name || @document_type ||
|
61
|
+
@document_type = name || @document_type || implicit(:document_type)
|
62
62
|
end
|
63
63
|
|
64
64
|
|
@@ -69,6 +69,30 @@ module Elasticsearch
|
|
69
69
|
def document_type=(name)
|
70
70
|
@document_type = name
|
71
71
|
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def implicit(prop)
|
76
|
+
value = nil
|
77
|
+
|
78
|
+
if Elasticsearch::Model.settings[:inheritance_enabled]
|
79
|
+
self.ancestors.each do |klass|
|
80
|
+
next if klass == self
|
81
|
+
break if value = klass.respond_to?(prop) && klass.send(prop)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
value || self.send("default_#{prop}")
|
86
|
+
end
|
87
|
+
|
88
|
+
def default_index_name
|
89
|
+
self.model_name.collection.gsub(/\//, '-')
|
90
|
+
end
|
91
|
+
|
92
|
+
def default_document_type
|
93
|
+
self.model_name.element
|
94
|
+
end
|
95
|
+
|
72
96
|
end
|
73
97
|
|
74
98
|
module InstanceMethods
|