elasticsearch-model 0.1.9 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|