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.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +695 -0
- data/Rakefile +59 -0
- data/elasticsearch-model.gemspec +57 -0
- data/examples/activerecord_article.rb +77 -0
- data/examples/activerecord_associations.rb +162 -0
- data/examples/couchbase_article.rb +66 -0
- data/examples/datamapper_article.rb +71 -0
- data/examples/mongoid_article.rb +68 -0
- data/examples/ohm_article.rb +70 -0
- data/examples/riak_article.rb +52 -0
- data/gemfiles/3.0.gemfile +12 -0
- data/gemfiles/4.0.gemfile +11 -0
- data/lib/elasticsearch/model/adapter.rb +145 -0
- data/lib/elasticsearch/model/adapters/active_record.rb +104 -0
- data/lib/elasticsearch/model/adapters/default.rb +50 -0
- data/lib/elasticsearch/model/adapters/mongoid.rb +92 -0
- data/lib/elasticsearch/model/callbacks.rb +35 -0
- data/lib/elasticsearch/model/client.rb +61 -0
- data/lib/elasticsearch/model/ext/active_record.rb +14 -0
- data/lib/elasticsearch/model/hash_wrapper.rb +15 -0
- data/lib/elasticsearch/model/importing.rb +144 -0
- data/lib/elasticsearch/model/indexing.rb +472 -0
- data/lib/elasticsearch/model/naming.rb +101 -0
- data/lib/elasticsearch/model/proxy.rb +127 -0
- data/lib/elasticsearch/model/response/base.rb +44 -0
- data/lib/elasticsearch/model/response/pagination.rb +173 -0
- data/lib/elasticsearch/model/response/records.rb +69 -0
- data/lib/elasticsearch/model/response/result.rb +63 -0
- data/lib/elasticsearch/model/response/results.rb +31 -0
- data/lib/elasticsearch/model/response.rb +71 -0
- data/lib/elasticsearch/model/searching.rb +107 -0
- data/lib/elasticsearch/model/serializing.rb +35 -0
- data/lib/elasticsearch/model/version.rb +5 -0
- data/lib/elasticsearch/model.rb +157 -0
- data/test/integration/active_record_associations_parent_child.rb +139 -0
- data/test/integration/active_record_associations_test.rb +307 -0
- data/test/integration/active_record_basic_test.rb +179 -0
- data/test/integration/active_record_custom_serialization_test.rb +62 -0
- data/test/integration/active_record_import_test.rb +100 -0
- data/test/integration/active_record_namespaced_model_test.rb +49 -0
- data/test/integration/active_record_pagination_test.rb +132 -0
- data/test/integration/mongoid_basic_test.rb +193 -0
- data/test/test_helper.rb +63 -0
- data/test/unit/adapter_active_record_test.rb +140 -0
- data/test/unit/adapter_default_test.rb +41 -0
- data/test/unit/adapter_mongoid_test.rb +102 -0
- data/test/unit/adapter_test.rb +69 -0
- data/test/unit/callbacks_test.rb +31 -0
- data/test/unit/client_test.rb +27 -0
- data/test/unit/importing_test.rb +176 -0
- data/test/unit/indexing_test.rb +478 -0
- data/test/unit/module_test.rb +57 -0
- data/test/unit/naming_test.rb +76 -0
- data/test/unit/proxy_test.rb +89 -0
- data/test/unit/response_base_test.rb +40 -0
- data/test/unit/response_pagination_kaminari_test.rb +189 -0
- data/test/unit/response_pagination_will_paginate_test.rb +208 -0
- data/test/unit/response_records_test.rb +91 -0
- data/test/unit/response_result_test.rb +90 -0
- data/test/unit/response_results_test.rb +31 -0
- data/test/unit/response_test.rb +67 -0
- data/test/unit/searching_search_request_test.rb +78 -0
- data/test/unit/searching_test.rb +41 -0
- data/test/unit/serializing_test.rb +17 -0
- 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'
|