elasticsearch-model 5.1.0 → 6.1.1
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 -3
- data/Gemfile +5 -0
- data/README.md +18 -11
- data/Rakefile +27 -36
- data/elasticsearch-model.gemspec +6 -6
- data/examples/activerecord_custom_analyzer.rb +135 -0
- data/examples/activerecord_mapping_completion.rb +3 -18
- data/examples/datamapper_article.rb +11 -1
- data/gemfiles/3.0.gemfile +6 -1
- data/gemfiles/4.0.gemfile +8 -1
- data/gemfiles/5.0.gemfile +7 -1
- data/gemfiles/6.0.gemfile +18 -0
- data/lib/elasticsearch/model/adapters/active_record.rb +8 -24
- data/lib/elasticsearch/model/adapters/mongoid.rb +10 -3
- data/lib/elasticsearch/model/importing.rb +1 -1
- data/lib/elasticsearch/model/indexing.rb +6 -4
- data/lib/elasticsearch/model/naming.rb +9 -2
- data/lib/elasticsearch/model/response/aggregations.rb +1 -1
- data/lib/elasticsearch/model/response/base.rb +3 -2
- data/lib/elasticsearch/model/response/pagination/kaminari.rb +109 -0
- data/lib/elasticsearch/model/response/pagination/will_paginate.rb +95 -0
- data/lib/elasticsearch/model/response/pagination.rb +2 -192
- data/lib/elasticsearch/model/response/result.rb +1 -1
- data/lib/elasticsearch/model/response/suggestions.rb +1 -1
- data/lib/elasticsearch/model/response.rb +11 -10
- data/lib/elasticsearch/model/version.rb +1 -1
- data/lib/elasticsearch/model.rb +15 -8
- data/spec/elasticsearch/model/adapter_spec.rb +119 -0
- data/spec/elasticsearch/model/adapters/active_record/associations_spec.rb +334 -0
- data/spec/elasticsearch/model/adapters/active_record/basic_spec.rb +340 -0
- data/spec/elasticsearch/model/adapters/active_record/dynamic_index_name_spec.rb +18 -0
- data/spec/elasticsearch/model/adapters/active_record/import_spec.rb +187 -0
- data/spec/elasticsearch/model/adapters/active_record/multi_model_spec.rb +110 -0
- data/spec/elasticsearch/model/adapters/active_record/namespaced_model_spec.rb +38 -0
- data/spec/elasticsearch/model/adapters/active_record/pagination_spec.rb +315 -0
- data/spec/elasticsearch/model/adapters/active_record/parent_child_spec.rb +75 -0
- data/spec/elasticsearch/model/adapters/active_record/serialization_spec.rb +61 -0
- data/spec/elasticsearch/model/adapters/active_record_spec.rb +207 -0
- data/spec/elasticsearch/model/adapters/default_spec.rb +41 -0
- data/spec/elasticsearch/model/adapters/mongoid/basic_spec.rb +267 -0
- data/spec/elasticsearch/model/adapters/mongoid/multi_model_spec.rb +66 -0
- data/spec/elasticsearch/model/adapters/mongoid_spec.rb +235 -0
- data/spec/elasticsearch/model/adapters/multiple_spec.rb +125 -0
- data/spec/elasticsearch/model/callbacks_spec.rb +33 -0
- data/spec/elasticsearch/model/client_spec.rb +66 -0
- data/spec/elasticsearch/model/hash_wrapper_spec.rb +12 -0
- data/spec/elasticsearch/model/importing_spec.rb +214 -0
- data/spec/elasticsearch/model/indexing_spec.rb +918 -0
- data/spec/elasticsearch/model/module_spec.rb +101 -0
- data/spec/elasticsearch/model/multimodel_spec.rb +55 -0
- data/spec/elasticsearch/model/naming_inheritance_spec.rb +184 -0
- data/spec/elasticsearch/model/naming_spec.rb +186 -0
- data/spec/elasticsearch/model/proxy_spec.rb +107 -0
- data/spec/elasticsearch/model/response/aggregations_spec.rb +66 -0
- data/spec/elasticsearch/model/response/base_spec.rb +90 -0
- data/spec/elasticsearch/model/response/pagination/kaminari_spec.rb +410 -0
- data/spec/elasticsearch/model/response/pagination/will_paginate_spec.rb +262 -0
- data/spec/elasticsearch/model/response/records_spec.rb +118 -0
- data/spec/elasticsearch/model/response/response_spec.rb +131 -0
- data/spec/elasticsearch/model/response/result_spec.rb +122 -0
- data/spec/elasticsearch/model/response/results_spec.rb +56 -0
- data/spec/elasticsearch/model/searching_search_request_spec.rb +112 -0
- data/spec/elasticsearch/model/searching_spec.rb +49 -0
- data/spec/elasticsearch/model/serializing_spec.rb +22 -0
- data/spec/spec_helper.rb +161 -0
- data/spec/support/app/answer.rb +33 -0
- data/spec/support/app/article.rb +22 -0
- data/spec/support/app/article_for_pagination.rb +12 -0
- data/spec/support/app/article_with_custom_serialization.rb +13 -0
- data/spec/support/app/article_with_dynamic_index_name.rb +15 -0
- data/spec/support/app/author.rb +9 -0
- data/spec/support/app/authorship.rb +4 -0
- data/spec/support/app/category.rb +3 -0
- data/spec/support/app/comment.rb +3 -0
- data/spec/support/app/episode.rb +11 -0
- data/spec/support/app/image.rb +19 -0
- data/spec/support/app/import_article.rb +12 -0
- data/spec/support/app/mongoid_article.rb +21 -0
- data/spec/support/app/namespaced_book.rb +10 -0
- data/spec/support/app/parent_and_child_searchable.rb +24 -0
- data/spec/support/app/post.rb +14 -0
- data/spec/support/app/question.rb +27 -0
- data/spec/support/app/searchable.rb +48 -0
- data/spec/support/app/series.rb +11 -0
- data/spec/support/app.rb +21 -0
- data/spec/support/model.json +1 -0
- data/{test → spec}/support/model.yml +0 -0
- metadata +134 -89
- data/test/integration/active_record_associations_parent_child_test.rb +0 -147
- data/test/integration/active_record_associations_test.rb +0 -339
- data/test/integration/active_record_basic_test.rb +0 -251
- data/test/integration/active_record_custom_serialization_test.rb +0 -67
- data/test/integration/active_record_import_test.rb +0 -115
- data/test/integration/active_record_namespaced_model_test.rb +0 -54
- data/test/integration/active_record_pagination_test.rb +0 -149
- data/test/integration/dynamic_index_name_test.rb +0 -52
- data/test/integration/mongoid_basic_test.rb +0 -176
- data/test/integration/multiple_models_test.rb +0 -176
- data/test/support/model.json +0 -1
- data/test/test_helper.rb +0 -92
- data/test/unit/adapter_active_record_test.rb +0 -157
- data/test/unit/adapter_default_test.rb +0 -41
- data/test/unit/adapter_mongoid_test.rb +0 -104
- data/test/unit/adapter_multiple_test.rb +0 -106
- data/test/unit/adapter_test.rb +0 -69
- data/test/unit/callbacks_test.rb +0 -31
- data/test/unit/client_test.rb +0 -27
- data/test/unit/hash_wrapper_test.rb +0 -13
- data/test/unit/importing_test.rb +0 -203
- data/test/unit/indexing_test.rb +0 -687
- data/test/unit/module_test.rb +0 -68
- data/test/unit/multimodel_test.rb +0 -38
- data/test/unit/naming_inheritance_test.rb +0 -94
- data/test/unit/naming_test.rb +0 -103
- data/test/unit/proxy_test.rb +0 -98
- data/test/unit/response_aggregations_test.rb +0 -46
- data/test/unit/response_base_test.rb +0 -40
- data/test/unit/response_pagination_kaminari_test.rb +0 -433
- data/test/unit/response_pagination_will_paginate_test.rb +0 -398
- data/test/unit/response_records_test.rb +0 -91
- data/test/unit/response_result_test.rb +0 -90
- data/test/unit/response_results_test.rb +0 -31
- data/test/unit/response_test.rb +0 -104
- data/test/unit/searching_search_request_test.rb +0 -78
- data/test/unit/searching_test.rb +0 -41
- data/test/unit/serializing_test.rb +0 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 75f65b56d90c490e0f107c9f57883a91eedc3c1c25793951df233872892f1a01
|
|
4
|
+
data.tar.gz: fe2cc84bbeb796de9b88f11f741f4822d6c3a4999bbaff5a54f40a339ff918a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a458e5ad312c67db37c7ff678c4bbfc19570202d72534a089a30818825fae380e06a40a419ec2f854838f0e924315a2d67f46ca9f966da91a264339c91f2be9f
|
|
7
|
+
data.tar.gz: dba1a2b0c88ecaca8a5b408f4f6ae8757812ad522320ecfd1f823e679398c6e1c042bb35deec5a6cbe38b9043e6e50605558f07cd0c2d33fd9e4642e5786478e
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -19,6 +19,7 @@ is compatible with the Elasticsearch `master` branch, therefore, with the next m
|
|
|
19
19
|
| 0.1 | → | 1.x |
|
|
20
20
|
| 2.x | → | 2.x |
|
|
21
21
|
| 5.x | → | 5.x |
|
|
22
|
+
| 6.x | → | 6.x |
|
|
22
23
|
| master | → | master |
|
|
23
24
|
|
|
24
25
|
## Installation
|
|
@@ -321,7 +322,7 @@ Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model
|
|
|
321
322
|
|
|
322
323
|
#### The Elasticsearch DSL
|
|
323
324
|
|
|
324
|
-
In most
|
|
325
|
+
In most situations, you'll want to pass the search definition
|
|
325
326
|
in the Elasticsearch [domain-specific language](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html) to the client:
|
|
326
327
|
|
|
327
328
|
```ruby
|
|
@@ -425,7 +426,7 @@ Article.__elasticsearch__.refresh_index!
|
|
|
425
426
|
```
|
|
426
427
|
|
|
427
428
|
By default, index name and document type will be inferred from your class name,
|
|
428
|
-
you can set it
|
|
429
|
+
you can set it explicitly, however:
|
|
429
430
|
|
|
430
431
|
```ruby
|
|
431
432
|
class Article
|
|
@@ -534,7 +535,7 @@ class Indexer
|
|
|
534
535
|
case operation.to_s
|
|
535
536
|
when /index/
|
|
536
537
|
record = Article.find(record_id)
|
|
537
|
-
Client.index index: 'articles', type: 'article', id: record.id, body: record.as_indexed_json
|
|
538
|
+
Client.index index: 'articles', type: 'article', id: record.id, body: record.__elasticsearch__.as_indexed_json
|
|
538
539
|
when /delete/
|
|
539
540
|
Client.delete index: 'articles', type: 'article', id: record_id
|
|
540
541
|
else raise ArgumentError, "Unknown operation '#{operation}'"
|
|
@@ -674,7 +675,7 @@ module DataMapperAdapter
|
|
|
674
675
|
#
|
|
675
676
|
module Records
|
|
676
677
|
def records
|
|
677
|
-
klass.all(id:
|
|
678
|
+
klass.all(id: ids)
|
|
678
679
|
end
|
|
679
680
|
|
|
680
681
|
# ...
|
|
@@ -724,13 +725,8 @@ module and its submodules for technical information.
|
|
|
724
725
|
|
|
725
726
|
The module provides a common `settings` method to customize various features.
|
|
726
727
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
in Rails:
|
|
730
|
-
|
|
731
|
-
```ruby
|
|
732
|
-
Elasticsearch::Model.settings[:inheritance_enabled] = true
|
|
733
|
-
```
|
|
728
|
+
Before version 7.0.0 of the gem, the only supported setting was `:inheritance_enabled`. This setting has been deprecated
|
|
729
|
+
and removed.
|
|
734
730
|
|
|
735
731
|
## Development and Community
|
|
736
732
|
|
|
@@ -748,6 +744,17 @@ curl -# https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticse
|
|
|
748
744
|
SERVER=start TEST_CLUSTER_COMMAND=$PWD/tmp/elasticsearch-1.0.0.RC1/bin/elasticsearch bundle exec rake test:all
|
|
749
745
|
```
|
|
750
746
|
|
|
747
|
+
### Single Table Inheritance deprecation
|
|
748
|
+
|
|
749
|
+
`Single Table Inheritance` has been supported through the 6.x series of this gem. With this feature,
|
|
750
|
+
elasticsearch settings (index mappings, etc) on a parent model could be inherited by a child model leading to different
|
|
751
|
+
model documents being indexed into the same Elasticsearch index. This feature depended on the ability to set a `type`
|
|
752
|
+
for a document in Elasticsearch. The Elasticsearch team has deprecated support for `types`, as is described
|
|
753
|
+
[here.](https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html)
|
|
754
|
+
This gem will also remove support for types and `Single Table Inheritance` in version 7.0 as it enables an anti-pattern.
|
|
755
|
+
Please save different model documents in separate indices. If you want to use STI, you can include an artificial
|
|
756
|
+
`type` field manually in each document and use it in other operations.
|
|
757
|
+
|
|
751
758
|
## License
|
|
752
759
|
|
|
753
760
|
This software is licensed under the Apache 2 license, quoted below.
|
data/Rakefile
CHANGED
|
@@ -4,12 +4,25 @@ desc "Run unit tests"
|
|
|
4
4
|
task :default => 'test:unit'
|
|
5
5
|
task :test => 'test:unit'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
if RUBY_VERSION < '2.3'
|
|
8
|
+
GEMFILES = ['3.0.gemfile', '4.0.gemfile', '5.0.gemfile']
|
|
9
|
+
else
|
|
10
|
+
GEMFILES = ['4.0.gemfile', '5.0.gemfile']
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
namespace :bundle do
|
|
14
|
+
desc 'Install dependencies for all the Gemfiles in /gemfiles. Optionally define env variable RAILS_VERSIONS. E.g. RAILS_VERSIONS=3.0,5.0'
|
|
9
15
|
task :install do
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
unless defined?(JRUBY_VERSION)
|
|
17
|
+
puts '-'*80
|
|
18
|
+
gemfiles = ENV['RAILS_VERSIONS'] ? ENV['RAILS_VERSIONS'].split(',').map { |v| "#{v}.gemfile"} : GEMFILES
|
|
19
|
+
gemfiles.each do |gemfile|
|
|
20
|
+
Bundler.with_clean_env do
|
|
21
|
+
sh "bundle install --gemfile #{File.expand_path('../gemfiles/'+gemfile, __FILE__)}"
|
|
22
|
+
end
|
|
23
|
+
puts '-'*80
|
|
24
|
+
end
|
|
25
|
+
end
|
|
13
26
|
end
|
|
14
27
|
end
|
|
15
28
|
|
|
@@ -17,38 +30,16 @@ end
|
|
|
17
30
|
|
|
18
31
|
require 'rake/testtask'
|
|
19
32
|
namespace :test do
|
|
20
|
-
Rake::TestTask.new(:run_unit) do |test|
|
|
21
|
-
test.libs << 'lib' << 'test'
|
|
22
|
-
test.test_files = FileList["test/unit/**/*_test.rb"]
|
|
23
|
-
test.verbose = false
|
|
24
|
-
test.warning = false
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
Rake::TestTask.new(:run_integration) do |test|
|
|
28
|
-
test.libs << 'lib' << 'test'
|
|
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"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
desc "Run integration tests against latest stable ActiveModel (5)"
|
|
42
|
-
task :integration do
|
|
43
|
-
#sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/3.0.gemfile', __FILE__)}' bundle exec rake test:run_integration"
|
|
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"
|
|
46
|
-
end
|
|
47
33
|
|
|
48
|
-
desc
|
|
49
|
-
task :all do
|
|
50
|
-
|
|
51
|
-
|
|
34
|
+
desc 'Run all tests. Optionally define env variable RAILS_VERSIONS. E.g. RAILS_VERSIONS=3.0,5.0'
|
|
35
|
+
task :all, [:rails_versions] do |task, args|
|
|
36
|
+
gemfiles = ENV['RAILS_VERSIONS'] ? ENV['RAILS_VERSIONS'].split(',').map {|v| "#{v}.gemfile"} : GEMFILES
|
|
37
|
+
puts '-' * 80
|
|
38
|
+
gemfiles.each do |gemfile|
|
|
39
|
+
sh "BUNDLE_GEMFILE='#{File.expand_path("../gemfiles/#{gemfile}", __FILE__)}' " +
|
|
40
|
+
" bundle exec rspec"
|
|
41
|
+
puts '-' * 80
|
|
42
|
+
end
|
|
52
43
|
end
|
|
53
44
|
end
|
|
54
45
|
|
data/elasticsearch-model.gemspec
CHANGED
|
@@ -21,21 +21,21 @@ Gem::Specification.new do |s|
|
|
|
21
21
|
s.extra_rdoc_files = [ "README.md", "LICENSE.txt" ]
|
|
22
22
|
s.rdoc_options = [ "--charset=UTF-8" ]
|
|
23
23
|
|
|
24
|
-
s.required_ruby_version = ">=
|
|
24
|
+
s.required_ruby_version = ">= 2.2"
|
|
25
25
|
|
|
26
|
-
s.add_dependency "elasticsearch", '~>
|
|
26
|
+
s.add_dependency "elasticsearch", '~> 6'
|
|
27
27
|
s.add_dependency "activesupport", '> 3'
|
|
28
28
|
s.add_dependency "hashie"
|
|
29
29
|
|
|
30
|
-
s.add_development_dependency "bundler"
|
|
30
|
+
s.add_development_dependency "bundler"
|
|
31
31
|
s.add_development_dependency "rake", "~> 11.1"
|
|
32
32
|
|
|
33
33
|
s.add_development_dependency "elasticsearch-extensions"
|
|
34
34
|
|
|
35
|
-
s.add_development_dependency "sqlite3"
|
|
35
|
+
s.add_development_dependency "sqlite3" unless defined?(JRUBY_VERSION)
|
|
36
36
|
s.add_development_dependency "activemodel", "> 3"
|
|
37
37
|
|
|
38
|
-
s.add_development_dependency "oj"
|
|
38
|
+
s.add_development_dependency "oj" unless defined?(JRUBY_VERSION)
|
|
39
39
|
s.add_development_dependency "kaminari"
|
|
40
40
|
s.add_development_dependency "will_paginate"
|
|
41
41
|
|
|
@@ -45,7 +45,7 @@ Gem::Specification.new do |s|
|
|
|
45
45
|
s.add_development_dependency "mocha"
|
|
46
46
|
s.add_development_dependency "turn"
|
|
47
47
|
s.add_development_dependency "yard"
|
|
48
|
-
s.add_development_dependency "ruby-prof"
|
|
48
|
+
s.add_development_dependency "ruby-prof" unless defined?(JRUBY_VERSION)
|
|
49
49
|
s.add_development_dependency "pry"
|
|
50
50
|
|
|
51
51
|
s.add_development_dependency "simplecov"
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Custom Analyzer for ActiveRecord integration with Elasticsearch
|
|
2
|
+
# ===============================================================
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
5
|
+
|
|
6
|
+
require 'ansi'
|
|
7
|
+
require 'logger'
|
|
8
|
+
|
|
9
|
+
require 'active_record'
|
|
10
|
+
require 'elasticsearch/model'
|
|
11
|
+
|
|
12
|
+
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
|
|
13
|
+
ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ":memory:" )
|
|
14
|
+
|
|
15
|
+
ActiveRecord::Schema.define(version: 1) do
|
|
16
|
+
create_table :articles do |t|
|
|
17
|
+
t.string :title
|
|
18
|
+
t.date :published_at
|
|
19
|
+
t.timestamps
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Elasticsearch::Model.client.transport.logger = ActiveSupport::Logger.new(STDOUT)
|
|
24
|
+
Elasticsearch::Model.client.transport.logger.formatter = lambda { |s, d, p, m| "#{m.ansi(:faint)}\n" }
|
|
25
|
+
|
|
26
|
+
class Article < ActiveRecord::Base
|
|
27
|
+
include Elasticsearch::Model
|
|
28
|
+
|
|
29
|
+
settings index: {
|
|
30
|
+
number_of_shards: 1,
|
|
31
|
+
number_of_replicas: 0,
|
|
32
|
+
analysis: {
|
|
33
|
+
analyzer: {
|
|
34
|
+
pattern: {
|
|
35
|
+
type: 'pattern',
|
|
36
|
+
pattern: "\\s|_|-|\\.",
|
|
37
|
+
lowercase: true
|
|
38
|
+
},
|
|
39
|
+
trigram: {
|
|
40
|
+
tokenizer: 'trigram'
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
tokenizer: {
|
|
44
|
+
trigram: {
|
|
45
|
+
type: 'ngram',
|
|
46
|
+
min_gram: 3,
|
|
47
|
+
max_gram: 3,
|
|
48
|
+
token_chars: ['letter', 'digit']
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} } do
|
|
52
|
+
mapping do
|
|
53
|
+
indexes :title, type: 'text', analyzer: 'english' do
|
|
54
|
+
indexes :keyword, analyzer: 'keyword'
|
|
55
|
+
indexes :pattern, analyzer: 'pattern'
|
|
56
|
+
indexes :trigram, analyzer: 'trigram'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Create example records
|
|
63
|
+
#
|
|
64
|
+
Article.delete_all
|
|
65
|
+
Article.create title: 'Foo'
|
|
66
|
+
Article.create title: 'Foo-Bar'
|
|
67
|
+
Article.create title: 'Foo_Bar_Bazooka'
|
|
68
|
+
Article.create title: 'Foo.Bar'
|
|
69
|
+
|
|
70
|
+
# Index records
|
|
71
|
+
#
|
|
72
|
+
errors = Article.import force: true, refresh: true, return: 'errors'
|
|
73
|
+
puts "[!] Errors importing records: #{errors.map { |d| d['index']['error'] }.join(', ')}".ansi(:red) && exit(1) unless errors.empty?
|
|
74
|
+
|
|
75
|
+
puts '', '-'*80
|
|
76
|
+
|
|
77
|
+
puts "English analyzer [Foo_Bar_1_Bazooka]".ansi(:bold),
|
|
78
|
+
"Tokens: " +
|
|
79
|
+
Article.__elasticsearch__.client.indices
|
|
80
|
+
.analyze(index: Article.index_name, body: { field: 'title', text: 'Foo_Bar_1_Bazooka' })['tokens']
|
|
81
|
+
.map { |d| "[#{d['token']}]" }.join(' '),
|
|
82
|
+
"\n"
|
|
83
|
+
|
|
84
|
+
puts "Keyword analyzer [Foo_Bar_1_Bazooka]".ansi(:bold),
|
|
85
|
+
"Tokens: " +
|
|
86
|
+
Article.__elasticsearch__.client.indices
|
|
87
|
+
.analyze(index: Article.index_name, body: { field: 'title.keyword', text: 'Foo_Bar_1_Bazooka' })['tokens']
|
|
88
|
+
.map { |d| "[#{d['token']}]" }.join(' '),
|
|
89
|
+
"\n"
|
|
90
|
+
|
|
91
|
+
puts "Pattern analyzer [Foo_Bar_1_Bazooka]".ansi(:bold),
|
|
92
|
+
"Tokens: " +
|
|
93
|
+
Article.__elasticsearch__.client.indices
|
|
94
|
+
.analyze(index: Article.index_name, body: { field: 'title.pattern', text: 'Foo_Bar_1_Bazooka' })['tokens']
|
|
95
|
+
.map { |d| "[#{d['token']}]" }.join(' '),
|
|
96
|
+
"\n"
|
|
97
|
+
|
|
98
|
+
puts "Trigram analyzer [Foo_Bar_1_Bazooka]".ansi(:bold),
|
|
99
|
+
"Tokens: " +
|
|
100
|
+
Article.__elasticsearch__.client.indices
|
|
101
|
+
.analyze(index: Article.index_name, body: { field: 'title.trigram', text: 'Foo_Bar_1_Bazooka' })['tokens']
|
|
102
|
+
.map { |d| "[#{d['token']}]" }.join(' '),
|
|
103
|
+
"\n"
|
|
104
|
+
|
|
105
|
+
puts '', '-'*80
|
|
106
|
+
|
|
107
|
+
response = Article.search query: { match: { 'title' => 'foo' } } ;
|
|
108
|
+
|
|
109
|
+
puts "English search for 'foo'".ansi(:bold),
|
|
110
|
+
"#{response.response.hits.total} matches: " +
|
|
111
|
+
response.records.map { |d| d.title }.join(', '),
|
|
112
|
+
"\n"
|
|
113
|
+
|
|
114
|
+
puts '', '-'*80
|
|
115
|
+
|
|
116
|
+
response = Article.search query: { match: { 'title.pattern' => 'foo' } } ;
|
|
117
|
+
|
|
118
|
+
puts "Pattern search for 'foo'".ansi(:bold),
|
|
119
|
+
"#{response.response.hits.total} matches: " +
|
|
120
|
+
response.records.map { |d| d.title }.join(', '),
|
|
121
|
+
"\n"
|
|
122
|
+
|
|
123
|
+
puts '', '-'*80
|
|
124
|
+
|
|
125
|
+
response = Article.search query: { match: { 'title.trigram' => 'zoo' } } ;
|
|
126
|
+
|
|
127
|
+
puts "Trigram search for 'zoo'".ansi(:bold),
|
|
128
|
+
"#{response.response.hits.total} matches: " +
|
|
129
|
+
response.records.map { |d| d.title }.join(', '),
|
|
130
|
+
"\n"
|
|
131
|
+
|
|
132
|
+
puts '', '-'*80
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
require 'pry'; binding.pry;
|
|
@@ -25,9 +25,7 @@ class Article < ActiveRecord::Base
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def as_indexed_json(options={})
|
|
28
|
-
as_json.merge
|
|
29
|
-
title_suggest: { input: title },
|
|
30
|
-
url: "/articles/#{id}"
|
|
28
|
+
as_json.merge 'url' => "/articles/#{id}"
|
|
31
29
|
end
|
|
32
30
|
end
|
|
33
31
|
|
|
@@ -52,20 +50,7 @@ response_1 = Article.search 'foo';
|
|
|
52
50
|
puts "Article search:".ansi(:bold),
|
|
53
51
|
response_1.to_a.map { |d| "Title: #{d.title}" }.inspect.ansi(:bold, :yellow)
|
|
54
52
|
|
|
55
|
-
response_2 = Article.
|
|
56
|
-
index: Article.index_name,
|
|
57
|
-
body: {
|
|
58
|
-
articles: {
|
|
59
|
-
text: 'foo',
|
|
60
|
-
completion: { field: 'title.suggest' }
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
puts "Article suggest:".ansi(:bold),
|
|
65
|
-
response_2['articles'].first['options'].map { |d| "#{d['text']} -> #{d['_source']['url']}" }.
|
|
66
|
-
inspect.ansi(:bold, :green)
|
|
67
|
-
|
|
68
|
-
response_3 = Article.search \
|
|
53
|
+
response_2 = Article.search \
|
|
69
54
|
query: {
|
|
70
55
|
match: { title: 'foo' }
|
|
71
56
|
},
|
|
@@ -78,7 +63,7 @@ response_3 = Article.search \
|
|
|
78
63
|
_source: ['title', 'url']
|
|
79
64
|
|
|
80
65
|
puts "Article search with suggest:".ansi(:bold),
|
|
81
|
-
|
|
66
|
+
response_2.response['suggest']['articles'].first['options'].map { |d| "#{d['text']} -> #{d['_source']['url']}" }.
|
|
82
67
|
inspect.ansi(:bold, :blue)
|
|
83
68
|
|
|
84
69
|
require 'pry'; binding.pry;
|
|
@@ -50,11 +50,21 @@ module DataMapperAdapter
|
|
|
50
50
|
#
|
|
51
51
|
module Records
|
|
52
52
|
def records
|
|
53
|
-
klass.all(id:
|
|
53
|
+
klass.all(id: ids)
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
# ...
|
|
57
57
|
end
|
|
58
|
+
|
|
59
|
+
module Callbacks
|
|
60
|
+
def self.included(model)
|
|
61
|
+
model.class_eval do
|
|
62
|
+
after(:create) { __elasticsearch__.index_document }
|
|
63
|
+
after(:save) { __elasticsearch__.update_document }
|
|
64
|
+
after(:destroy) { __elasticsearch__.delete_document }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
58
68
|
end
|
|
59
69
|
|
|
60
70
|
# Register the adapter
|
data/gemfiles/3.0.gemfile
CHANGED
|
@@ -10,4 +10,9 @@ gemspec path: '../'
|
|
|
10
10
|
gem 'activemodel', '>= 3.0'
|
|
11
11
|
gem 'activerecord', '~> 3.2'
|
|
12
12
|
gem 'mongoid', '>= 3.0'
|
|
13
|
-
gem 'sqlite3'
|
|
13
|
+
gem 'sqlite3', '~> 1.3.6' unless defined?(JRUBY_VERSION)
|
|
14
|
+
|
|
15
|
+
group :development, :testing do
|
|
16
|
+
gem 'rspec'
|
|
17
|
+
gem 'pry-nav'
|
|
18
|
+
end
|
data/gemfiles/4.0.gemfile
CHANGED
|
@@ -9,4 +9,11 @@ gemspec path: '../'
|
|
|
9
9
|
|
|
10
10
|
gem 'activemodel', '~> 4'
|
|
11
11
|
gem 'activerecord', '~> 4'
|
|
12
|
-
gem '
|
|
12
|
+
gem 'mongoid', '~> 5'
|
|
13
|
+
gem 'sqlite3', '~> 1.3.6' unless defined?(JRUBY_VERSION)
|
|
14
|
+
|
|
15
|
+
group :development, :testing do
|
|
16
|
+
gem 'bigdecimal', '~> 1'
|
|
17
|
+
gem 'pry-nav'
|
|
18
|
+
gem 'rspec'
|
|
19
|
+
end
|
data/gemfiles/5.0.gemfile
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Usage:
|
|
2
|
+
#
|
|
3
|
+
# $ BUNDLE_GEMFILE=./gemfiles/6.0.gemfile bundle install
|
|
4
|
+
# $ BUNDLE_GEMFILE=./gemfiles/6.0.gemfile bundle exec rake test:integration
|
|
5
|
+
|
|
6
|
+
source 'https://rubygems.org'
|
|
7
|
+
|
|
8
|
+
gemspec path: '../'
|
|
9
|
+
|
|
10
|
+
gem 'activemodel', '~> 6'
|
|
11
|
+
gem 'activerecord', '~> 6'
|
|
12
|
+
gem 'sqlite3' unless defined?(JRUBY_VERSION)
|
|
13
|
+
gem 'mongoid', '~> 7'
|
|
14
|
+
|
|
15
|
+
group :development, :testing do
|
|
16
|
+
gem 'rspec'
|
|
17
|
+
gem 'pry-nav'
|
|
18
|
+
end
|
|
@@ -35,7 +35,11 @@ module Elasticsearch
|
|
|
35
35
|
else
|
|
36
36
|
self.__send__(:exec_queries)
|
|
37
37
|
end
|
|
38
|
-
|
|
38
|
+
if !self.order_values.present?
|
|
39
|
+
@records.sort_by { |record| hits.index { |hit| hit['_id'].to_s == record.id.to_s } }
|
|
40
|
+
else
|
|
41
|
+
@records
|
|
42
|
+
end
|
|
39
43
|
end if self
|
|
40
44
|
end
|
|
41
45
|
|
|
@@ -47,27 +51,6 @@ module Elasticsearch
|
|
|
47
51
|
def load
|
|
48
52
|
records.__send__(:load)
|
|
49
53
|
end
|
|
50
|
-
|
|
51
|
-
# Intercept call to the `order` method, so we can ignore the order from Elasticsearch
|
|
52
|
-
#
|
|
53
|
-
def order(*args)
|
|
54
|
-
sql_records = records.__send__ :order, *args
|
|
55
|
-
|
|
56
|
-
# Redefine the `to_a` method to the original one
|
|
57
|
-
#
|
|
58
|
-
sql_records.instance_exec do
|
|
59
|
-
define_singleton_method(:to_a) do
|
|
60
|
-
if defined?(::ActiveRecord) && ::ActiveRecord::VERSION::MAJOR >= 4
|
|
61
|
-
self.load
|
|
62
|
-
else
|
|
63
|
-
self.__send__(:exec_queries)
|
|
64
|
-
end
|
|
65
|
-
@records
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
sql_records
|
|
70
|
-
end
|
|
71
54
|
end
|
|
72
55
|
|
|
73
56
|
module Callbacks
|
|
@@ -102,8 +85,9 @@ module Elasticsearch
|
|
|
102
85
|
scope = scope.__send__(named_scope) if named_scope
|
|
103
86
|
scope = scope.instance_exec(&query) if query
|
|
104
87
|
|
|
105
|
-
scope.find_in_batches(options) do |batch|
|
|
106
|
-
|
|
88
|
+
scope.find_in_batches(**options) do |batch|
|
|
89
|
+
batch = self.__send__(preprocess, batch) if preprocess
|
|
90
|
+
yield(batch) if batch.present?
|
|
107
91
|
end
|
|
108
92
|
end
|
|
109
93
|
|
|
@@ -63,10 +63,17 @@ module Elasticsearch
|
|
|
63
63
|
# @see https://github.com/karmi/retire/pull/724
|
|
64
64
|
#
|
|
65
65
|
def __find_in_batches(options={}, &block)
|
|
66
|
-
options[:batch_size]
|
|
66
|
+
batch_size = options[:batch_size] || 1_000
|
|
67
|
+
query = options[:query]
|
|
68
|
+
named_scope = options[:scope]
|
|
69
|
+
preprocess = options[:preprocess]
|
|
70
|
+
|
|
71
|
+
scope = all
|
|
72
|
+
scope = scope.send(named_scope) if named_scope
|
|
73
|
+
scope = query.is_a?(Proc) ? scope.class_exec(&query) : scope.where(query) if query
|
|
67
74
|
|
|
68
|
-
|
|
69
|
-
yield items
|
|
75
|
+
scope.no_timeout.each_slice(batch_size) do |items|
|
|
76
|
+
yield (preprocess ? self.__send__(preprocess, items) : items)
|
|
70
77
|
end
|
|
71
78
|
end
|
|
72
79
|
|
|
@@ -269,7 +269,8 @@ module Elasticsearch
|
|
|
269
269
|
self.client.indices.delete index: target_index
|
|
270
270
|
rescue Exception => e
|
|
271
271
|
if e.class.to_s =~ /NotFound/ && options[:force]
|
|
272
|
-
|
|
272
|
+
client.transport.logger.debug("[!!!] Index does not exist (#{e.class})") if client.transport.logger
|
|
273
|
+
nil
|
|
273
274
|
else
|
|
274
275
|
raise e
|
|
275
276
|
end
|
|
@@ -295,7 +296,8 @@ module Elasticsearch
|
|
|
295
296
|
self.client.indices.refresh index: target_index
|
|
296
297
|
rescue Exception => e
|
|
297
298
|
if e.class.to_s =~ /NotFound/ && options[:force]
|
|
298
|
-
|
|
299
|
+
client.transport.logger.debug("[!!!] Index does not exist (#{e.class})") if client.transport.logger
|
|
300
|
+
nil
|
|
299
301
|
else
|
|
300
302
|
raise e
|
|
301
303
|
end
|
|
@@ -397,7 +399,7 @@ module Elasticsearch
|
|
|
397
399
|
# @see http://rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Actions:update
|
|
398
400
|
#
|
|
399
401
|
def update_document(options={})
|
|
400
|
-
if attributes_in_database = self.instance_variable_get(:@__changed_model_attributes)
|
|
402
|
+
if attributes_in_database = self.instance_variable_get(:@__changed_model_attributes).presence
|
|
401
403
|
attributes = if respond_to?(:as_indexed_json)
|
|
402
404
|
self.as_indexed_json.select { |k,v| attributes_in_database.keys.map(&:to_s).include? k.to_s }
|
|
403
405
|
else
|
|
@@ -409,7 +411,7 @@ module Elasticsearch
|
|
|
409
411
|
type: document_type,
|
|
410
412
|
id: self.id,
|
|
411
413
|
body: { doc: attributes } }.merge(options)
|
|
412
|
-
)
|
|
414
|
+
) unless attributes.empty?
|
|
413
415
|
else
|
|
414
416
|
index_document(options)
|
|
415
417
|
end
|
|
@@ -5,6 +5,8 @@ module Elasticsearch
|
|
|
5
5
|
#
|
|
6
6
|
module Naming
|
|
7
7
|
|
|
8
|
+
DEFAULT_DOC_TYPE = '_doc'.freeze
|
|
9
|
+
|
|
8
10
|
module ClassMethods
|
|
9
11
|
|
|
10
12
|
# Get or set the name of the index
|
|
@@ -77,7 +79,12 @@ module Elasticsearch
|
|
|
77
79
|
|
|
78
80
|
if Elasticsearch::Model.settings[:inheritance_enabled]
|
|
79
81
|
self.ancestors.each do |klass|
|
|
80
|
-
|
|
82
|
+
# When Naming is included in Proxy::ClassMethods the actual model
|
|
83
|
+
# is among its ancestors. We don't want to call the actual model
|
|
84
|
+
# since it will result in the same call to the same instance of
|
|
85
|
+
# Proxy::ClassMethods. To prevent this we also skip the ancestor
|
|
86
|
+
# that is the target.
|
|
87
|
+
next if klass == self || self.respond_to?(:target) && klass == self.target
|
|
81
88
|
break if value = klass.respond_to?(prop) && klass.send(prop)
|
|
82
89
|
end
|
|
83
90
|
end
|
|
@@ -90,7 +97,7 @@ module Elasticsearch
|
|
|
90
97
|
end
|
|
91
98
|
|
|
92
99
|
def default_document_type
|
|
93
|
-
|
|
100
|
+
DEFAULT_DOC_TYPE
|
|
94
101
|
end
|
|
95
102
|
|
|
96
103
|
end
|
|
@@ -4,7 +4,7 @@ module Elasticsearch
|
|
|
4
4
|
# Common funtionality for classes in the {Elasticsearch::Model::Response} module
|
|
5
5
|
#
|
|
6
6
|
module Base
|
|
7
|
-
attr_reader :klass, :response
|
|
7
|
+
attr_reader :klass, :response, :raw_response
|
|
8
8
|
|
|
9
9
|
# @param klass [Class] The name of the model class
|
|
10
10
|
# @param response [Hash] The full response returned from Elasticsearch client
|
|
@@ -12,7 +12,8 @@ module Elasticsearch
|
|
|
12
12
|
#
|
|
13
13
|
def initialize(klass, response, options={})
|
|
14
14
|
@klass = klass
|
|
15
|
-
@
|
|
15
|
+
@raw_response = response
|
|
16
|
+
@response = response
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
# @abstract Implement this method in specific class
|