elasticsearch-model-queryable 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
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'