elasticsearch-model-queryable 0.1.5

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.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/CHANGELOG.md +26 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +13 -0
  6. data/README.md +695 -0
  7. data/Rakefile +59 -0
  8. data/elasticsearch-model.gemspec +57 -0
  9. data/examples/activerecord_article.rb +77 -0
  10. data/examples/activerecord_associations.rb +162 -0
  11. data/examples/couchbase_article.rb +66 -0
  12. data/examples/datamapper_article.rb +71 -0
  13. data/examples/mongoid_article.rb +68 -0
  14. data/examples/ohm_article.rb +70 -0
  15. data/examples/riak_article.rb +52 -0
  16. data/gemfiles/3.0.gemfile +12 -0
  17. data/gemfiles/4.0.gemfile +11 -0
  18. data/lib/elasticsearch/model/adapter.rb +145 -0
  19. data/lib/elasticsearch/model/adapters/active_record.rb +104 -0
  20. data/lib/elasticsearch/model/adapters/default.rb +50 -0
  21. data/lib/elasticsearch/model/adapters/mongoid.rb +92 -0
  22. data/lib/elasticsearch/model/callbacks.rb +35 -0
  23. data/lib/elasticsearch/model/client.rb +61 -0
  24. data/lib/elasticsearch/model/ext/active_record.rb +14 -0
  25. data/lib/elasticsearch/model/hash_wrapper.rb +15 -0
  26. data/lib/elasticsearch/model/importing.rb +144 -0
  27. data/lib/elasticsearch/model/indexing.rb +472 -0
  28. data/lib/elasticsearch/model/naming.rb +101 -0
  29. data/lib/elasticsearch/model/proxy.rb +127 -0
  30. data/lib/elasticsearch/model/response/base.rb +44 -0
  31. data/lib/elasticsearch/model/response/pagination.rb +173 -0
  32. data/lib/elasticsearch/model/response/records.rb +69 -0
  33. data/lib/elasticsearch/model/response/result.rb +63 -0
  34. data/lib/elasticsearch/model/response/results.rb +31 -0
  35. data/lib/elasticsearch/model/response.rb +71 -0
  36. data/lib/elasticsearch/model/searching.rb +107 -0
  37. data/lib/elasticsearch/model/serializing.rb +35 -0
  38. data/lib/elasticsearch/model/version.rb +5 -0
  39. data/lib/elasticsearch/model.rb +157 -0
  40. data/test/integration/active_record_associations_parent_child.rb +139 -0
  41. data/test/integration/active_record_associations_test.rb +307 -0
  42. data/test/integration/active_record_basic_test.rb +179 -0
  43. data/test/integration/active_record_custom_serialization_test.rb +62 -0
  44. data/test/integration/active_record_import_test.rb +100 -0
  45. data/test/integration/active_record_namespaced_model_test.rb +49 -0
  46. data/test/integration/active_record_pagination_test.rb +132 -0
  47. data/test/integration/mongoid_basic_test.rb +193 -0
  48. data/test/test_helper.rb +63 -0
  49. data/test/unit/adapter_active_record_test.rb +140 -0
  50. data/test/unit/adapter_default_test.rb +41 -0
  51. data/test/unit/adapter_mongoid_test.rb +102 -0
  52. data/test/unit/adapter_test.rb +69 -0
  53. data/test/unit/callbacks_test.rb +31 -0
  54. data/test/unit/client_test.rb +27 -0
  55. data/test/unit/importing_test.rb +176 -0
  56. data/test/unit/indexing_test.rb +478 -0
  57. data/test/unit/module_test.rb +57 -0
  58. data/test/unit/naming_test.rb +76 -0
  59. data/test/unit/proxy_test.rb +89 -0
  60. data/test/unit/response_base_test.rb +40 -0
  61. data/test/unit/response_pagination_kaminari_test.rb +189 -0
  62. data/test/unit/response_pagination_will_paginate_test.rb +208 -0
  63. data/test/unit/response_records_test.rb +91 -0
  64. data/test/unit/response_result_test.rb +90 -0
  65. data/test/unit/response_results_test.rb +31 -0
  66. data/test/unit/response_test.rb +67 -0
  67. data/test/unit/searching_search_request_test.rb +78 -0
  68. data/test/unit/searching_test.rb +41 -0
  69. data/test/unit/serializing_test.rb +17 -0
  70. metadata +466 -0
data/Rakefile ADDED
@@ -0,0 +1,59 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc "Run unit tests"
4
+ task :default => 'test:unit'
5
+ task :test => 'test:unit'
6
+
7
+ # ----- Test tasks ------------------------------------------------------------
8
+
9
+ require 'rake/testtask'
10
+ namespace :test do
11
+ task :ci_reporter do
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']
19
+ test.libs << 'lib' << 'test'
20
+ test.test_files = FileList["test/unit/**/*_test.rb"]
21
+ # test.verbose = true
22
+ # test.warning = true
23
+ end
24
+
25
+ Rake::TestTask.new(:run_integration) do |test|
26
+ Rake::Task['test:ci_reporter'].invoke if ENV['CI']
27
+ test.libs << 'lib' << 'test'
28
+ test.test_files = FileList["test/integration/**/*_test.rb"]
29
+ end
30
+
31
+ desc "Run integration tests against ActiveModel 3 and 4"
32
+ task :integration do
33
+ sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/3.0.gemfile', __FILE__)}' bundle exec rake test:run_integration" unless defined?(RUBY_VERSION) && RUBY_VERSION > '2.2'
34
+ sh "BUNDLE_GEMFILE='#{File.expand_path('../gemfiles/4.0.gemfile', __FILE__)}' bundle exec rake test:run_integration"
35
+ end
36
+
37
+ Rake::TestTask.new(:all) do |test|
38
+ Rake::Task['test:ci_reporter'].invoke if ENV['CI']
39
+ test.libs << 'lib' << 'test'
40
+ test.test_files = FileList["test/unit/**/*_test.rb", "test/integration/**/*_test.rb"]
41
+ end
42
+ end
43
+
44
+ # ----- Documentation tasks ---------------------------------------------------
45
+
46
+ require 'yard'
47
+ YARD::Rake::YardocTask.new(:doc) do |t|
48
+ t.options = %w| --embed-mixins --markup=markdown |
49
+ end
50
+
51
+ # ----- Code analysis tasks ---------------------------------------------------
52
+
53
+ if defined?(RUBY_VERSION) && RUBY_VERSION > '1.9'
54
+ require 'cane/rake_task'
55
+ Cane::RakeTask.new(:quality) do |cane|
56
+ cane.abc_max = 15
57
+ cane.no_style = true
58
+ end
59
+ end
@@ -0,0 +1,57 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "elasticsearch/model/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "elasticsearch-model-queryable"
8
+ s.version = Elasticsearch::Model::VERSION
9
+ s.authors = ["Karel Minarik"]
10
+ s.email = ["karel.minarik@elasticsearch.org"]
11
+ s.description = "ActiveModel/Record integrations for Elasticsearch."
12
+ s.summary = "ActiveModel/Record integrations for Elasticsearch."
13
+ s.homepage = "https://github.com/elasticsearch/elasticsearch-rails/"
14
+ s.license = "Apache 2"
15
+
16
+ s.files = `git ls-files`.split($/)
17
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+ s.require_paths = ["lib"]
20
+
21
+ s.extra_rdoc_files = ["README.md", "LICENSE.txt"]
22
+ s.rdoc_options = ["--charset=UTF-8"]
23
+
24
+ s.required_ruby_version = ">= 1.9.3"
25
+
26
+ s.add_dependency "elasticsearch", "> 0.4"
27
+ s.add_dependency "activesupport", "> 3"
28
+ s.add_dependency "hashie"
29
+
30
+ s.add_development_dependency "bundler", "~> 1.3"
31
+ s.add_development_dependency "rake"
32
+
33
+ s.add_development_dependency "elasticsearch-extensions"
34
+
35
+ s.add_development_dependency "sqlite3"
36
+ s.add_development_dependency "activemodel", "> 3.0"
37
+
38
+ s.add_development_dependency "oj"
39
+ s.add_development_dependency "kaminari"
40
+ s.add_development_dependency "will_paginate"
41
+
42
+ s.add_development_dependency "minitest", "~> 4"
43
+ s.add_development_dependency "test-unit" if defined?(RUBY_VERSION) && RUBY_VERSION > "2.2"
44
+ s.add_development_dependency "shoulda-context"
45
+ s.add_development_dependency "mocha"
46
+ s.add_development_dependency "turn"
47
+ s.add_development_dependency "yard"
48
+ s.add_development_dependency "ruby-prof"
49
+ s.add_development_dependency "pry"
50
+ s.add_development_dependency "ci_reporter", "~> 1.9"
51
+
52
+ if defined?(RUBY_VERSION) && RUBY_VERSION > "1.9"
53
+ s.add_development_dependency "simplecov"
54
+ s.add_development_dependency "cane"
55
+ s.add_development_dependency "require-prof"
56
+ end
57
+ end
@@ -0,0 +1,77 @@
1
+ # ActiveRecord and Elasticsearch
2
+ # ==============================
3
+ #
4
+ # https://github.com/rails/rails/tree/master/activerecord
5
+
6
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
7
+
8
+ require 'pry'
9
+ Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
10
+
11
+ require 'logger'
12
+ require 'ansi/core'
13
+ require 'active_record'
14
+ require 'kaminari'
15
+
16
+ require 'elasticsearch/model'
17
+
18
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
19
+ ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ":memory:" )
20
+
21
+ ActiveRecord::Schema.define(version: 1) do
22
+ create_table :articles do |t|
23
+ t.string :title
24
+ t.date :published_at
25
+ t.timestamps
26
+ end
27
+ end
28
+
29
+ Kaminari::Hooks.init
30
+
31
+ class Article < ActiveRecord::Base
32
+ end
33
+
34
+ # Store data
35
+ #
36
+ Article.delete_all
37
+ Article.create title: 'Foo'
38
+ Article.create title: 'Bar'
39
+ Article.create title: 'Foo Foo'
40
+
41
+ # Index data
42
+ #
43
+ client = Elasticsearch::Client.new log:true
44
+
45
+ # client.indices.delete index: 'articles' rescue nil
46
+ # client.indices.create index: 'articles', body: { mappings: { article: { dynamic: 'strict' }, properties: {} } }
47
+
48
+ client.indices.delete index: 'articles' rescue nil
49
+ client.bulk index: 'articles',
50
+ type: 'article',
51
+ body: Article.all.as_json.map { |a| { index: { _id: a.delete('id'), data: a } } },
52
+ refresh: true
53
+
54
+ # Extend the model with Elasticsearch support
55
+ #
56
+ Article.__send__ :include, Elasticsearch::Model
57
+ # Article.__send__ :include, Elasticsearch::Model::Callbacks
58
+
59
+ # ActiveRecord::Base.logger.silence do
60
+ # 10_000.times do |i|
61
+ # Article.create title: "Foo #{i}"
62
+ # end
63
+ # end
64
+
65
+ puts '', '-'*Pry::Terminal.width!
66
+
67
+ Elasticsearch::Model.client = Elasticsearch::Client.new log: true
68
+
69
+ response = Article.search 'foo';
70
+
71
+ p response.size
72
+ p response.results.size
73
+ p response.records.size
74
+
75
+ Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
76
+ input: StringIO.new('response.records.to_a'),
77
+ quiet: true)
@@ -0,0 +1,162 @@
1
+ # ActiveRecord associations and Elasticsearch
2
+ # ===========================================
3
+ #
4
+ # https://github.com/rails/rails/tree/master/activerecord
5
+ # http://guides.rubyonrails.org/association_basics.html
6
+ #
7
+ # Run me with:
8
+ #
9
+ # ruby -I lib examples/activerecord_associations.rb
10
+ #
11
+
12
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
13
+
14
+ require 'pry'
15
+ Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
16
+
17
+ require 'logger'
18
+ require 'ansi/core'
19
+ require 'active_record'
20
+
21
+ require 'elasticsearch/model'
22
+
23
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
24
+ ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ":memory:" )
25
+
26
+ # ----- Schema definition -------------------------------------------------------------------------
27
+
28
+ ActiveRecord::Schema.define(version: 1) do
29
+ create_table :categories do |t|
30
+ t.string :title
31
+ t.timestamps
32
+ end
33
+
34
+ create_table :authors do |t|
35
+ t.string :first_name, :last_name
36
+ t.timestamps
37
+ end
38
+
39
+ create_table :authorships do |t|
40
+ t.references :article
41
+ t.references :author
42
+ t.timestamps
43
+ end
44
+
45
+ create_table :articles do |t|
46
+ t.string :title
47
+ t.timestamps
48
+ end
49
+
50
+ create_table :articles_categories, id: false do |t|
51
+ t.references :article, :category
52
+ end
53
+
54
+ create_table :comments do |t|
55
+ t.string :text
56
+ t.references :article
57
+ t.timestamps
58
+ end
59
+ add_index(:comments, :article_id)
60
+ end
61
+
62
+ # ----- Model definitions -------------------------------------------------------------------------
63
+
64
+ class Category < ActiveRecord::Base
65
+ has_and_belongs_to_many :articles
66
+ end
67
+
68
+ class Author < ActiveRecord::Base
69
+ has_many :authorships
70
+
71
+ after_update { self.authorships.each(&:touch) }
72
+
73
+ def full_name
74
+ [first_name, last_name].compact.join(' ')
75
+ end
76
+ end
77
+
78
+ class Authorship < ActiveRecord::Base
79
+ belongs_to :author
80
+ belongs_to :article, touch: true
81
+ end
82
+
83
+ class Article < ActiveRecord::Base
84
+ has_and_belongs_to_many :categories, after_add: [ lambda { |a,c| a.__elasticsearch__.index_document } ],
85
+ after_remove: [ lambda { |a,c| a.__elasticsearch__.index_document } ]
86
+ has_many :authorships
87
+ has_many :authors, through: :authorships
88
+ has_many :comments
89
+ end
90
+
91
+ class Article < ActiveRecord::Base; delegate :size, to: :comments, prefix: true; end
92
+
93
+ class Comment < ActiveRecord::Base
94
+ belongs_to :article, touch: true
95
+ end
96
+
97
+ # ----- Search integration ------------------------------------------------------------------------
98
+
99
+ module Searchable
100
+ extend ActiveSupport::Concern
101
+
102
+ included do
103
+ include Elasticsearch::Model
104
+ include Elasticsearch::Model::Callbacks
105
+
106
+ __elasticsearch__.client = Elasticsearch::Client.new log: true
107
+ __elasticsearch__.client.transport.logger.formatter = proc { |s, d, p, m| "\e[32m#{m}\n\e[0m" }
108
+
109
+ include Indexing
110
+ after_touch() { __elasticsearch__.index_document }
111
+ end
112
+
113
+ module Indexing
114
+
115
+ # Customize the JSON serialization for Elasticsearch
116
+ def as_indexed_json(options={})
117
+ self.as_json(
118
+ include: { categories: { only: :title},
119
+ authors: { methods: [:full_name], only: [:full_name] },
120
+ comments: { only: :text }
121
+ })
122
+ end
123
+ end
124
+ end
125
+
126
+ Article.__send__ :include, Searchable
127
+
128
+ # ----- Insert data -------------------------------------------------------------------------------
129
+
130
+ # Create category
131
+ #
132
+ category = Category.create title: 'One'
133
+
134
+ # Create author
135
+ #
136
+ author = Author.create first_name: 'John', last_name: 'Smith'
137
+
138
+ # Create article
139
+
140
+ article = Article.create title: 'First Article'
141
+
142
+ # Assign category
143
+ #
144
+ article.categories << category
145
+
146
+ # Assign author
147
+ #
148
+ article.authors << author
149
+
150
+ # Add comment
151
+ #
152
+ article.comments.create text: 'First comment'
153
+
154
+ # Load
155
+ #
156
+ article = Article.all.includes(:categories, :authors, :comments).first
157
+
158
+ # ----- Pry ---------------------------------------------------------------------------------------
159
+
160
+ Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
161
+ input: StringIO.new('puts "\n\narticle.as_indexed_json\n"; article.as_indexed_json'),
162
+ quiet: true)
@@ -0,0 +1,66 @@
1
+ # Couchbase and Elasticsearch
2
+ # ===========================
3
+ #
4
+ # https://github.com/couchbase/couchbase-ruby-model
5
+
6
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
7
+
8
+ require 'pry'
9
+ Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
10
+
11
+ require 'logger'
12
+ require 'couchbase/model'
13
+
14
+ require 'elasticsearch/model'
15
+
16
+ # Documents are stored as JSON objects in Riak but have rich
17
+ # semantics, including validations and associations.
18
+ class Article < Couchbase::Model
19
+ attribute :title
20
+ attribute :published_at
21
+
22
+ # view :all, :limit => 10, :descending => true
23
+ # TODO: Implement view a la
24
+ # bucket.save_design_doc <<-JSON
25
+ # {
26
+ # "_id": "_design/article",
27
+ # "language": "javascript",
28
+ # "views": {
29
+ # "all": {
30
+ # "map": "function(doc, meta) { emit(doc.id, doc.title); }"
31
+ # }
32
+ # }
33
+ # }
34
+ # JSON
35
+
36
+ end
37
+
38
+ # Extend the model with Elasticsearch support
39
+ #
40
+ Article.__send__ :extend, Elasticsearch::Model::Client::ClassMethods
41
+ Article.__send__ :extend, Elasticsearch::Model::Searching::ClassMethods
42
+ Article.__send__ :extend, Elasticsearch::Model::Naming::ClassMethods
43
+
44
+ # Create documents in Riak
45
+ #
46
+ Article.create id: '1', title: 'Foo' rescue nil
47
+ Article.create id: '2', title: 'Bar' rescue nil
48
+ Article.create id: '3', title: 'Foo Foo' rescue nil
49
+
50
+ # Index data into Elasticsearch
51
+ #
52
+ client = Elasticsearch::Client.new log:true
53
+
54
+ client.indices.delete index: 'articles' rescue nil
55
+ client.bulk index: 'articles',
56
+ type: 'article',
57
+ body: Article.find(['1', '2', '3']).map { |a|
58
+ { index: { _id: a.id, data: a.attributes } }
59
+ },
60
+ refresh: true
61
+
62
+ response = Article.search 'foo', index: 'articles', type: 'article';
63
+
64
+ Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
65
+ input: StringIO.new('response.records.to_a'),
66
+ quiet: true)
@@ -0,0 +1,71 @@
1
+ # DataMapper and Elasticsearch
2
+ # ============================
3
+ #
4
+ # https://github.com/datamapper/dm-core
5
+ # https://github.com/datamapper/dm-active_model
6
+
7
+
8
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
9
+
10
+ require 'pry'
11
+ Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
12
+
13
+ require 'logger'
14
+ require 'ansi/core'
15
+
16
+ require 'data_mapper'
17
+ require 'dm-active_model'
18
+
19
+ require 'active_support/all'
20
+
21
+ require 'elasticsearch/model'
22
+
23
+ DataMapper::Logger.new(STDOUT, :debug)
24
+ DataMapper.setup(:default, 'sqlite::memory:')
25
+
26
+ class Article
27
+ include DataMapper::Resource
28
+
29
+ property :id, Serial
30
+ property :title, String
31
+ property :published_at, DateTime
32
+ end
33
+
34
+ DataMapper.auto_migrate!
35
+ DataMapper.finalize
36
+
37
+ Article.create title: 'Foo'
38
+ Article.create title: 'Bar'
39
+ Article.create title: 'Foo Foo'
40
+
41
+ # Extend the model with Elasticsearch support
42
+ #
43
+ Article.__send__ :include, Elasticsearch::Model
44
+
45
+ # The DataMapper adapter
46
+ #
47
+ module DataMapperAdapter
48
+
49
+ # Implement the interface for fetching records
50
+ #
51
+ module Records
52
+ def records
53
+ klass.all(id: @ids)
54
+ end
55
+
56
+ # ...
57
+ end
58
+ end
59
+
60
+ # Register the adapter
61
+ #
62
+ Elasticsearch::Model::Adapter.register(
63
+ DataMapperAdapter,
64
+ lambda { |klass| defined?(::DataMapper::Resource) and klass.ancestors.include?(::DataMapper::Resource) }
65
+ )
66
+
67
+ response = Article.search 'foo';
68
+
69
+ Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
70
+ input: StringIO.new('response.records.to_a'),
71
+ quiet: true)
@@ -0,0 +1,68 @@
1
+ # Mongoid and Elasticsearch
2
+ # =========================
3
+ #
4
+ # http://mongoid.org/en/mongoid/index.html
5
+
6
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
7
+
8
+ require 'pry'
9
+ Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
10
+
11
+ require 'benchmark'
12
+ require 'logger'
13
+ require 'ansi/core'
14
+ require 'mongoid'
15
+
16
+ require 'elasticsearch/model'
17
+ require 'elasticsearch/model/callbacks'
18
+
19
+ Mongoid.logger.level = Logger::DEBUG
20
+ Moped.logger.level = Logger::DEBUG
21
+
22
+ Mongoid.connect_to 'articles'
23
+
24
+ Elasticsearch::Model.client = Elasticsearch::Client.new host: 'localhost:9250', log: true
25
+
26
+ class Article
27
+ include Mongoid::Document
28
+ field :id, type: String
29
+ field :title, type: String
30
+ field :published_at, type: DateTime
31
+ attr_accessible :id, :title, :published_at if respond_to? :attr_accessible
32
+
33
+ def as_indexed_json(options={})
34
+ as_json(except: [:id, :_id])
35
+ end
36
+ end
37
+
38
+ # Extend the model with Elasticsearch support
39
+ #
40
+ Article.__send__ :include, Elasticsearch::Model
41
+ # Article.__send__ :include, Elasticsearch::Model::Callbacks
42
+
43
+ # Store data
44
+ #
45
+ Article.delete_all
46
+ Article.create id: '1', title: 'Foo'
47
+ Article.create id: '2', title: 'Bar'
48
+ Article.create id: '3', title: 'Foo Foo'
49
+
50
+ # Index data
51
+ #
52
+ client = Elasticsearch::Client.new host:'localhost:9250', log:true
53
+
54
+ client.indices.delete index: 'articles' rescue nil
55
+ client.bulk index: 'articles',
56
+ type: 'article',
57
+ body: Article.all.map { |a| { index: { _id: a.id, data: a.attributes } } },
58
+ refresh: true
59
+
60
+ # puts Benchmark.realtime { 9_875.times { |i| Article.create title: "Foo #{i}" } }
61
+
62
+ puts '', '-'*Pry::Terminal.width!
63
+
64
+ response = Article.search 'foo';
65
+
66
+ Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
67
+ input: StringIO.new('response.records.to_a'),
68
+ quiet: true)
@@ -0,0 +1,70 @@
1
+ # Ohm for Redis and Elasticsearch
2
+ # ===============================
3
+ #
4
+ # https://github.com/soveran/ohm#example
5
+
6
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
7
+
8
+ require 'pry'
9
+ Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
10
+
11
+ require 'logger'
12
+ require 'ansi/core'
13
+ require 'active_model'
14
+ require 'ohm'
15
+
16
+ require 'elasticsearch/model'
17
+
18
+ class Article < Ohm::Model
19
+ # Include JSON serialization from ActiveModel
20
+ include ActiveModel::Serializers::JSON
21
+
22
+ attribute :title
23
+ attribute :published_at
24
+ end
25
+
26
+ # Extend the model with Elasticsearch support
27
+ #
28
+ Article.__send__ :include, Elasticsearch::Model
29
+
30
+ # Register a custom adapter
31
+ #
32
+ module Elasticsearch
33
+ module Model
34
+ module Adapter
35
+ module Ohm
36
+ Adapter.register self,
37
+ lambda { |klass| defined?(::Ohm::Model) and klass.ancestors.include?(::Ohm::Model) }
38
+ module Records
39
+ def records
40
+ klass.fetch(@ids)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ # Configure the Elasticsearch client to log operations
49
+ #
50
+ Elasticsearch::Model.client = Elasticsearch::Client.new log: true
51
+
52
+ puts '', '-'*Pry::Terminal.width!
53
+
54
+ Article.all.map { |a| a.delete }
55
+ Article.create id: '1', title: 'Foo'
56
+ Article.create id: '2', title: 'Bar'
57
+ Article.create id: '3', title: 'Foo Foo'
58
+
59
+ Article.__elasticsearch__.client.indices.delete index: 'articles' rescue nil
60
+ Article.__elasticsearch__.client.bulk index: 'articles',
61
+ type: 'article',
62
+ body: Article.all.map { |a| { index: { _id: a.id, data: a.attributes } } },
63
+ refresh: true
64
+
65
+
66
+ response = Article.search 'foo', index: 'articles', type: 'article';
67
+
68
+ Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
69
+ input: StringIO.new('response.records.to_a'),
70
+ quiet: true)
@@ -0,0 +1,52 @@
1
+ # Riak and Elasticsearch
2
+ # ======================
3
+ #
4
+ # https://github.com/basho-labs/ripple
5
+
6
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
7
+
8
+ require 'pry'
9
+ Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
10
+
11
+ require 'logger'
12
+ require 'ripple'
13
+
14
+ require 'elasticsearch/model'
15
+
16
+ # Documents are stored as JSON objects in Riak but have rich
17
+ # semantics, including validations and associations.
18
+ class Article
19
+ include Ripple::Document
20
+
21
+ property :title, String
22
+ property :published_at, Time, :default => proc { Time.now }
23
+ end
24
+
25
+ # Extend the model with Elasticsearch support
26
+ #
27
+ Article.__send__ :include, Elasticsearch::Model
28
+
29
+ # Create documents in Riak
30
+ #
31
+ Article.destroy_all
32
+ Article.create id: '1', title: 'Foo'
33
+ Article.create id: '2', title: 'Bar'
34
+ Article.create id: '3', title: 'Foo Foo'
35
+
36
+ # Index data into Elasticsearch
37
+ #
38
+ client = Elasticsearch::Client.new log:true
39
+
40
+ client.indices.delete index: 'articles' rescue nil
41
+ client.bulk index: 'articles',
42
+ type: 'article',
43
+ body: Article.all.map { |a|
44
+ { index: { _id: a.key, data: JSON.parse(a.robject.raw_data) } }
45
+ }.as_json,
46
+ refresh: true
47
+
48
+ response = Article.search 'foo';
49
+
50
+ Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
51
+ input: StringIO.new('response.records.to_a'),
52
+ quiet: true)
@@ -0,0 +1,12 @@
1
+ # Usage:
2
+ #
3
+ # $ BUNDLE_GEMFILE=./gemfiles/3.0.gemfile bundle install
4
+ # $ BUNDLE_GEMFILE=./gemfiles/3.0.gemfile bundle exec rake test:integration
5
+
6
+ source 'https://rubygems.org'
7
+
8
+ gemspec path: '../'
9
+
10
+ gem 'activemodel', '>= 3.0'
11
+ gem 'activerecord', '~> 3.2'
12
+ gem 'mongoid', '>= 3.0'