elasticsearch-model 2.0.1 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/elasticsearch-model.gemspec +1 -1
- data/examples/activerecord_associations.rb +46 -11
- data/examples/activerecord_mapping_completion.rb +24 -9
- data/examples/activerecord_mapping_edge_ngram.rb +101 -0
- data/lib/elasticsearch/model.rb +4 -3
- data/lib/elasticsearch/model/hash_wrapper.rb +15 -0
- data/lib/elasticsearch/model/indexing.rb +9 -5
- data/lib/elasticsearch/model/response.rb +2 -2
- data/lib/elasticsearch/model/response/aggregations.rb +2 -0
- data/lib/elasticsearch/model/response/result.rb +1 -1
- data/lib/elasticsearch/model/response/suggestions.rb +2 -0
- data/lib/elasticsearch/model/version.rb +1 -1
- data/test/integration/{active_record_associations_parent_child.rb → active_record_associations_parent_child_test.rb} +1 -1
- data/test/integration/active_record_associations_test.rb +5 -6
- data/test/integration/active_record_basic_test.rb +2 -2
- data/test/integration/active_record_import_test.rb +1 -1
- data/test/integration/active_record_pagination_test.rb +1 -1
- data/test/integration/mongoid_basic_test.rb +1 -1
- data/test/integration/multiple_models_test.rb +2 -2
- data/test/unit/hash_wrapper_test.rb +13 -0
- data/test/unit/indexing_test.rb +32 -21
- data/test/unit/response_test.rb +1 -1
- metadata +12 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 578a444488ef68a50e4f19c87bf43c3c3d950a39
|
4
|
+
data.tar.gz: c602b0f07801e4dc864921a067a94a8fc482da75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe1dc3d34dd8cd3447160f0eaf2c0941e57058f80a5e8334b6a058bb0e3acab4b960070c0402f81d2dd976b939951e675cb907eb9a828b9a70f9853cf65c5ff9
|
7
|
+
data.tar.gz: a366fbee0a6ff94ec51202fecfcb63b159d4cc169bc4b38debb3df032cf1dd5a94514fde0da6d4c92e2f5f2ddbaef44dc5487b75e749d762136d905c963836f7
|
data/README.md
CHANGED
@@ -302,7 +302,7 @@ response.page(2).results
|
|
302
302
|
response.page(2).records
|
303
303
|
```
|
304
304
|
|
305
|
-
In a Rails controller, use the
|
305
|
+
In a Rails controller, use the `params[:page]` parameter to paginate through results:
|
306
306
|
|
307
307
|
```ruby
|
308
308
|
@articles = Article.search(params[:q]).page(params[:page]).records
|
@@ -377,6 +377,10 @@ response.results.first.title
|
|
377
377
|
For proper search engine function, it's often necessary to configure the index properly.
|
378
378
|
The `Elasticsearch::Model` integration provides class methods to set up index settings and mappings.
|
379
379
|
|
380
|
+
**NOTE**: Elasticsearch will automatically create an index when a document is indexed,
|
381
|
+
with default settings and mappings. Create the index in advance with the `create_index!`
|
382
|
+
method, so your index configuration is respected.
|
383
|
+
|
380
384
|
```ruby
|
381
385
|
class Article
|
382
386
|
settings index: { number_of_shards: 1 } do
|
data/elasticsearch-model.gemspec
CHANGED
@@ -12,12 +12,12 @@
|
|
12
12
|
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
13
13
|
|
14
14
|
require 'pry'
|
15
|
-
Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
|
16
15
|
|
17
16
|
require 'logger'
|
18
17
|
require 'ansi/core'
|
19
18
|
require 'active_record'
|
20
19
|
|
20
|
+
require 'json'
|
21
21
|
require 'elasticsearch/model'
|
22
22
|
|
23
23
|
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
|
@@ -33,6 +33,7 @@ ActiveRecord::Schema.define(version: 1) do
|
|
33
33
|
|
34
34
|
create_table :authors do |t|
|
35
35
|
t.string :first_name, :last_name
|
36
|
+
t.string :department
|
36
37
|
t.timestamps null: false
|
37
38
|
end
|
38
39
|
|
@@ -63,7 +64,7 @@ end
|
|
63
64
|
# ----- Elasticsearch client setup ----------------------------------------------------------------
|
64
65
|
|
65
66
|
Elasticsearch::Model.client = Elasticsearch::Client.new log: true
|
66
|
-
Elasticsearch::Model.client.transport.logger.formatter = proc { |s, d, p, m| "\e[
|
67
|
+
Elasticsearch::Model.client.transport.logger.formatter = proc { |s, d, p, m| "\e[2m#{m}\n\e[0m" }
|
67
68
|
|
68
69
|
# ----- Search integration ------------------------------------------------------------------------
|
69
70
|
|
@@ -84,7 +85,7 @@ module Searchable
|
|
84
85
|
def as_indexed_json(options={})
|
85
86
|
self.as_json(
|
86
87
|
include: { categories: { only: :title},
|
87
|
-
authors: { methods: [:full_name], only: [:full_name] },
|
88
|
+
authors: { methods: [:full_name, :department], only: [:full_name, :department] },
|
88
89
|
comments: { only: :text }
|
89
90
|
})
|
90
91
|
end
|
@@ -140,7 +141,7 @@ category = Category.create title: 'One'
|
|
140
141
|
|
141
142
|
# Create author
|
142
143
|
#
|
143
|
-
author = Author.create first_name: 'John', last_name: 'Smith'
|
144
|
+
author = Author.create first_name: 'John', last_name: 'Smith', department: 'Business'
|
144
145
|
|
145
146
|
# Create article
|
146
147
|
|
@@ -161,18 +162,52 @@ article.comments.create text: 'Second comment for article One'
|
|
161
162
|
|
162
163
|
Elasticsearch::Model.client.indices.refresh index: Elasticsearch::Model::Registry.all.map(&:index_name)
|
163
164
|
|
164
|
-
|
165
|
+
# Search for a term and return records
|
166
|
+
#
|
167
|
+
puts "",
|
168
|
+
"Articles containing 'one':".ansi(:bold),
|
169
|
+
Article.search('one').records.to_a.map(&:inspect),
|
170
|
+
""
|
165
171
|
|
166
|
-
puts "
|
172
|
+
puts "",
|
173
|
+
"All Models containing 'one':".ansi(:bold),
|
174
|
+
Elasticsearch::Model.search('one').records.to_a.map(&:inspect),
|
175
|
+
""
|
167
176
|
|
168
|
-
#
|
177
|
+
# Difference between `records` and `results`
|
169
178
|
#
|
170
|
-
|
179
|
+
response = Article.search query: { match: { title: 'first' } }
|
171
180
|
|
172
|
-
|
181
|
+
puts "",
|
182
|
+
"Search results are wrapped in the <#{response.class}> class",
|
183
|
+
""
|
184
|
+
|
185
|
+
puts "",
|
186
|
+
"Access the <ActiveRecord> instances with the `#records` method:".ansi(:bold),
|
187
|
+
response.records.map { |r| "* #{r.title} | Authors: #{r.authors.map(&:full_name) } | Comment count: #{r.comments.size}" }.join("\n"),
|
188
|
+
""
|
189
|
+
|
190
|
+
puts "",
|
191
|
+
"Access the Elasticsearch documents with the `#results` method (without touching the database):".ansi(:bold),
|
192
|
+
response.results.map { |r| "* #{r.title} | Authors: #{r.authors.map(&:full_name) } | Comment count: #{r.comments.size}" }.join("\n"),
|
193
|
+
""
|
194
|
+
|
195
|
+
puts "",
|
196
|
+
"The whole indexed document (according to `Article#as_indexed_json`):".ansi(:bold),
|
197
|
+
JSON.pretty_generate(response.results.first._source.to_hash),
|
198
|
+
""
|
173
199
|
|
174
|
-
|
200
|
+
# Retrieve only selected fields from Elasticsearch
|
201
|
+
#
|
202
|
+
response = Article.search query: { match: { title: 'first' } }, _source: ['title', 'authors.full_name']
|
203
|
+
|
204
|
+
puts "",
|
205
|
+
"Retrieve only selected fields from Elasticsearch:".ansi(:bold),
|
206
|
+
JSON.pretty_generate(response.results.first._source.to_hash),
|
207
|
+
""
|
208
|
+
|
209
|
+
# ----- Pry ---------------------------------------------------------------------------------------
|
175
210
|
|
176
211
|
Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
|
177
|
-
input: StringIO.new(
|
212
|
+
input: StringIO.new('response.records.first'),
|
178
213
|
quiet: true)
|
@@ -18,17 +18,16 @@ class Article < ActiveRecord::Base
|
|
18
18
|
include Elasticsearch::Model::Callbacks
|
19
19
|
|
20
20
|
mapping do
|
21
|
-
indexes :title
|
22
|
-
|
21
|
+
indexes :title, type: 'text' do
|
22
|
+
indexes :suggest, type: 'completion'
|
23
|
+
end
|
24
|
+
indexes :url, type: 'keyword'
|
23
25
|
end
|
24
26
|
|
25
27
|
def as_indexed_json(options={})
|
26
28
|
as_json.merge \
|
27
|
-
title_suggest: {
|
28
|
-
|
29
|
-
output: title,
|
30
|
-
payload: { url: "/articles/#{id}" }
|
31
|
-
}
|
29
|
+
title_suggest: { input: title },
|
30
|
+
url: "/articles/#{id}"
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
@@ -58,12 +57,28 @@ response_2 = Article.__elasticsearch__.client.suggest \
|
|
58
57
|
body: {
|
59
58
|
articles: {
|
60
59
|
text: 'foo',
|
61
|
-
completion: { field: '
|
60
|
+
completion: { field: 'title.suggest' }
|
62
61
|
}
|
63
62
|
};
|
64
63
|
|
65
64
|
puts "Article suggest:".ansi(:bold),
|
66
|
-
response_2['articles'].first['options'].map { |d| "#{d['text']} -> #{d['
|
65
|
+
response_2['articles'].first['options'].map { |d| "#{d['text']} -> #{d['_source']['url']}" }.
|
67
66
|
inspect.ansi(:bold, :green)
|
68
67
|
|
68
|
+
response_3 = Article.search \
|
69
|
+
query: {
|
70
|
+
match: { title: 'foo' }
|
71
|
+
},
|
72
|
+
suggest: {
|
73
|
+
articles: {
|
74
|
+
text: 'foo',
|
75
|
+
completion: { field: 'title.suggest' }
|
76
|
+
}
|
77
|
+
},
|
78
|
+
_source: ['title', 'url']
|
79
|
+
|
80
|
+
puts "Article search with suggest:".ansi(:bold),
|
81
|
+
response_3.response['suggest']['articles'].first['options'].map { |d| "#{d['text']} -> #{d['_source']['url']}" }.
|
82
|
+
inspect.ansi(:bold, :blue)
|
83
|
+
|
69
84
|
require 'pry'; binding.pry;
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'ansi'
|
2
|
+
require 'sqlite3'
|
3
|
+
require 'active_record'
|
4
|
+
require 'elasticsearch/model'
|
5
|
+
|
6
|
+
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
|
7
|
+
ActiveRecord::Base.establish_connection( adapter: 'sqlite3', database: ":memory:" )
|
8
|
+
|
9
|
+
ActiveRecord::Schema.define(version: 1) do
|
10
|
+
create_table :articles do |t|
|
11
|
+
t.string :title
|
12
|
+
t.date :published_at
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Article < ActiveRecord::Base
|
18
|
+
include Elasticsearch::Model
|
19
|
+
include Elasticsearch::Model::Callbacks
|
20
|
+
|
21
|
+
article_es_settings = {
|
22
|
+
index: {
|
23
|
+
analysis: {
|
24
|
+
filter: {
|
25
|
+
autocomplete_filter: {
|
26
|
+
type: "edge_ngram",
|
27
|
+
min_gram: 1,
|
28
|
+
max_gram: 20
|
29
|
+
}
|
30
|
+
},
|
31
|
+
analyzer:{
|
32
|
+
autocomplete: {
|
33
|
+
type: "custom",
|
34
|
+
tokenizer: "standard",
|
35
|
+
filter: ["lowercase", "autocomplete_filter"]
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
settings article_es_settings do
|
43
|
+
mapping do
|
44
|
+
indexes :title
|
45
|
+
indexes :suggestable_title, type: 'string', analyzer: 'autocomplete'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def as_indexed_json(options={})
|
50
|
+
as_json.merge(suggestable_title: title)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
Article.__elasticsearch__.client = Elasticsearch::Client.new log: true
|
55
|
+
|
56
|
+
# Create index
|
57
|
+
|
58
|
+
Article.__elasticsearch__.create_index! force: true
|
59
|
+
|
60
|
+
# Store data
|
61
|
+
|
62
|
+
Article.delete_all
|
63
|
+
Article.create title: 'Foo'
|
64
|
+
Article.create title: 'Bar'
|
65
|
+
Article.create title: 'Foo Foo'
|
66
|
+
Article.__elasticsearch__.refresh_index!
|
67
|
+
|
68
|
+
# Search and suggest
|
69
|
+
fulltext_search_response = Article.search(query: { match: { title: 'foo'} } )
|
70
|
+
|
71
|
+
puts "", "Article search for 'foo':".ansi(:bold),
|
72
|
+
fulltext_search_response.to_a.map { |d| "Title: #{d.title}" }.inspect.ansi(:bold, :yellow),
|
73
|
+
""
|
74
|
+
|
75
|
+
fulltext_search_response_2 = Article.search(query: { match: { title: 'fo'} } )
|
76
|
+
|
77
|
+
puts "", "Article search for 'fo':".ansi(:bold),
|
78
|
+
fulltext_search_response_2.to_a.map { |d| "Title: #{d.title}" }.inspect.ansi(:bold, :red),
|
79
|
+
""
|
80
|
+
|
81
|
+
autocomplete_search_response = Article.search(query: { match: { suggestable_title: { query: 'fo', analyzer: 'standard'} } } )
|
82
|
+
|
83
|
+
puts "", "Article autocomplete for 'fo':".ansi(:bold),
|
84
|
+
autocomplete_search_response.to_a.map { |d| "Title: #{d.suggestable_title}" }.inspect.ansi(:bold, :green),
|
85
|
+
""
|
86
|
+
|
87
|
+
puts "", "Text 'Foo Bar' analyzed with the default analyzer:".ansi(:bold),
|
88
|
+
Article.__elasticsearch__.client.indices.analyze(
|
89
|
+
index: Article.__elasticsearch__.index_name,
|
90
|
+
field: 'title',
|
91
|
+
text: 'Foo Bar')['tokens'].map { |t| t['token'] }.inspect.ansi(:bold, :yellow),
|
92
|
+
""
|
93
|
+
|
94
|
+
puts "", "Text 'Foo Bar' analyzed with the autocomplete filter:".ansi(:bold),
|
95
|
+
Article.__elasticsearch__.client.indices.analyze(
|
96
|
+
index: Article.__elasticsearch__.index_name,
|
97
|
+
field: 'suggestable_title',
|
98
|
+
text: 'Foo Bar')['tokens'].map { |t| t['token'] }.inspect.ansi(:bold, :yellow),
|
99
|
+
""
|
100
|
+
|
101
|
+
require 'pry'; binding.pry;
|
data/lib/elasticsearch/model.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
require 'hashie'
|
1
|
+
require 'hashie/mash'
|
4
2
|
|
5
3
|
require 'active_support/core_ext/module/delegation'
|
6
4
|
|
5
|
+
require 'elasticsearch'
|
6
|
+
|
7
7
|
require 'elasticsearch/model/version'
|
8
8
|
|
9
|
+
require 'elasticsearch/model/hash_wrapper'
|
9
10
|
require 'elasticsearch/model/client'
|
10
11
|
|
11
12
|
require 'elasticsearch/model/multimodel'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Subclass of `Hashie::Mash` to wrap Hash-like structures
|
5
|
+
# (responses from Elasticsearch, search definitions, etc)
|
6
|
+
#
|
7
|
+
# The primary goal of the subclass is to disable the
|
8
|
+
# warning being printed by Hashie for re-defined
|
9
|
+
# methods, such as `sort`.
|
10
|
+
#
|
11
|
+
class HashWrapper < ::Hashie::Mash
|
12
|
+
disable_warnings if respond_to?(:disable_warnings)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -65,8 +65,8 @@ module Elasticsearch
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
# Set the type to `
|
69
|
-
@mapping[name][:type] ||= '
|
68
|
+
# Set the type to `text` by default
|
69
|
+
@mapping[name][:type] ||= 'text'
|
70
70
|
|
71
71
|
self
|
72
72
|
end
|
@@ -220,15 +220,19 @@ module Elasticsearch
|
|
220
220
|
# Article.__elasticsearch__.create_index! index: 'my-index'
|
221
221
|
#
|
222
222
|
def create_index!(options={})
|
223
|
-
|
223
|
+
options = options.clone
|
224
|
+
|
225
|
+
target_index = options.delete(:index) || self.index_name
|
226
|
+
settings = options.delete(:settings) || self.settings.to_hash
|
227
|
+
mappings = options.delete(:mappings) || self.mappings.to_hash
|
224
228
|
|
225
229
|
delete_index!(options.merge index: target_index) if options[:force]
|
226
230
|
|
227
231
|
unless index_exists?(index: target_index)
|
228
232
|
self.client.indices.create index: target_index,
|
229
233
|
body: {
|
230
|
-
settings:
|
231
|
-
mappings:
|
234
|
+
settings: settings,
|
235
|
+
mappings: mappings }
|
232
236
|
end
|
233
237
|
end
|
234
238
|
|
@@ -28,7 +28,7 @@ module Elasticsearch
|
|
28
28
|
#
|
29
29
|
def response
|
30
30
|
@response ||= begin
|
31
|
-
|
31
|
+
HashWrapper.new(search.execute!)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -63,7 +63,7 @@ module Elasticsearch
|
|
63
63
|
# Returns the statistics on shards
|
64
64
|
#
|
65
65
|
def shards
|
66
|
-
|
66
|
+
HashWrapper.new(response['_shards'])
|
67
67
|
end
|
68
68
|
|
69
69
|
# Returns a Hashie::Mash of the aggregations
|
@@ -29,13 +29,12 @@ module Elasticsearch
|
|
29
29
|
indexes :authors do
|
30
30
|
indexes :first_name
|
31
31
|
indexes :last_name
|
32
|
-
indexes :full_name, type: '
|
33
|
-
indexes :
|
34
|
-
indexes :raw, analyzer: 'keyword'
|
32
|
+
indexes :full_name, type: 'text' do
|
33
|
+
indexes :raw, type: 'keyword'
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
|
-
indexes :categories,
|
37
|
+
indexes :categories, type: 'keyword'
|
39
38
|
|
40
39
|
indexes :comments, type: 'nested' do
|
41
40
|
indexes :text
|
@@ -188,8 +187,8 @@ module Elasticsearch
|
|
188
187
|
Post.__elasticsearch__.refresh_index!
|
189
188
|
|
190
189
|
query = { query: {
|
191
|
-
|
192
|
-
|
190
|
+
bool: {
|
191
|
+
must: {
|
193
192
|
multi_match: {
|
194
193
|
fields: ['title'],
|
195
194
|
query: 'first'
|
@@ -18,8 +18,8 @@ module Elasticsearch
|
|
18
18
|
|
19
19
|
settings index: { number_of_shards: 1, number_of_replicas: 0 } do
|
20
20
|
mapping do
|
21
|
-
indexes :title, type: '
|
22
|
-
indexes :body, type: '
|
21
|
+
indexes :title, type: 'text', analyzer: 'snowball'
|
22
|
+
indexes :body, type: 'text'
|
23
23
|
indexes :clicks, type: 'integer'
|
24
24
|
indexes :created_at, type: 'date'
|
25
25
|
end
|
@@ -16,7 +16,7 @@ module Elasticsearch
|
|
16
16
|
|
17
17
|
settings index: { number_of_shards: 1, number_of_replicas: 0 } do
|
18
18
|
mapping do
|
19
|
-
indexes :title, type: '
|
19
|
+
indexes :title, type: 'text', analyzer: 'snowball'
|
20
20
|
indexes :created_at, type: 'date'
|
21
21
|
end
|
22
22
|
end
|
@@ -20,7 +20,7 @@ if Mongo.available?
|
|
20
20
|
|
21
21
|
settings index: { number_of_shards: 1, number_of_replicas: 0 } do
|
22
22
|
mapping do
|
23
|
-
indexes :title, type: '
|
23
|
+
indexes :title, type: 'text', analyzer: 'snowball'
|
24
24
|
indexes :created_at, type: 'date'
|
25
25
|
end
|
26
26
|
end
|
@@ -20,7 +20,7 @@ module Elasticsearch
|
|
20
20
|
|
21
21
|
settings index: {number_of_shards: 1, number_of_replicas: 0} do
|
22
22
|
mapping do
|
23
|
-
indexes :name, type: '
|
23
|
+
indexes :name, type: 'text', analyzer: 'snowball'
|
24
24
|
indexes :created_at, type: 'date'
|
25
25
|
end
|
26
26
|
end
|
@@ -130,7 +130,7 @@ module Elasticsearch
|
|
130
130
|
|
131
131
|
settings index: {number_of_shards: 1, number_of_replicas: 0} do
|
132
132
|
mapping do
|
133
|
-
indexes :name, type: '
|
133
|
+
indexes :name, type: 'text', analyzer: 'snowball'
|
134
134
|
indexes :created_at, type: 'date'
|
135
135
|
end
|
136
136
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'hashie/version'
|
4
|
+
|
5
|
+
class Elasticsearch::Model::HashWrapperTest < Test::Unit::TestCase
|
6
|
+
context "The HashWrapper class" do
|
7
|
+
should "not print the warning for re-defined methods" do
|
8
|
+
Hashie.logger.expects(:warn).never
|
9
|
+
|
10
|
+
subject = Elasticsearch::Model::HashWrapper.new(:foo => 'bar', :sort => true)
|
11
|
+
end if Hashie::VERSION >= '3.5.3'
|
12
|
+
end
|
13
|
+
end
|
data/test/unit/indexing_test.rb
CHANGED
@@ -83,33 +83,23 @@ class Elasticsearch::Model::IndexingTest < Test::Unit::TestCase
|
|
83
83
|
assert_equal 'boolean', mappings.to_hash[:mytype][:properties][:foo][:type]
|
84
84
|
end
|
85
85
|
|
86
|
-
should "define type as
|
86
|
+
should "define type as 'text' by default" do
|
87
87
|
mappings = Elasticsearch::Model::Indexing::Mappings.new :mytype
|
88
88
|
|
89
|
-
mappings.indexes :bar
|
90
|
-
assert_equal '
|
89
|
+
mappings.indexes :bar
|
90
|
+
assert_equal 'text', mappings.to_hash[:mytype][:properties][:bar][:type]
|
91
91
|
end
|
92
92
|
|
93
93
|
should "define multiple fields" do
|
94
94
|
mappings = Elasticsearch::Model::Indexing::Mappings.new :mytype
|
95
95
|
|
96
|
-
mappings.indexes :
|
97
|
-
indexes :raw,
|
96
|
+
mappings.indexes :my_field, type: 'text' do
|
97
|
+
indexes :raw, type: 'keyword'
|
98
98
|
end
|
99
99
|
|
100
|
-
mappings.
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
assert_equal 'string', mappings.to_hash[:mytype][:properties][:foo_1][:type]
|
105
|
-
assert_equal 'string', mappings.to_hash[:mytype][:properties][:foo_1][:fields][:raw][:type]
|
106
|
-
assert_equal 'keyword', mappings.to_hash[:mytype][:properties][:foo_1][:fields][:raw][:analyzer]
|
107
|
-
assert_nil mappings.to_hash[:mytype][:properties][:foo_1][:properties]
|
108
|
-
|
109
|
-
assert_equal 'multi_field', mappings.to_hash[:mytype][:properties][:foo_2][:type]
|
110
|
-
assert_equal 'string', mappings.to_hash[:mytype][:properties][:foo_2][:fields][:raw][:type]
|
111
|
-
assert_equal 'keyword', mappings.to_hash[:mytype][:properties][:foo_2][:fields][:raw][:analyzer]
|
112
|
-
assert_nil mappings.to_hash[:mytype][:properties][:foo_2][:properties]
|
100
|
+
assert_equal 'text', mappings.to_hash[:mytype][:properties][:my_field][:type]
|
101
|
+
assert_equal 'keyword', mappings.to_hash[:mytype][:properties][:my_field][:fields][:raw][:type]
|
102
|
+
assert_nil mappings.to_hash[:mytype][:properties][:my_field][:properties]
|
113
103
|
end
|
114
104
|
|
115
105
|
should "define embedded properties" do
|
@@ -134,15 +124,15 @@ class Elasticsearch::Model::IndexingTest < Test::Unit::TestCase
|
|
134
124
|
# Object is the default when `type` is missing and there's a block passed
|
135
125
|
#
|
136
126
|
assert_equal 'object', mappings.to_hash[:mytype][:properties][:foo][:type]
|
137
|
-
assert_equal '
|
127
|
+
assert_equal 'text', mappings.to_hash[:mytype][:properties][:foo][:properties][:bar][:type]
|
138
128
|
assert_nil mappings.to_hash[:mytype][:properties][:foo][:fields]
|
139
129
|
|
140
130
|
assert_equal 'object', mappings.to_hash[:mytype][:properties][:foo_object][:type]
|
141
|
-
assert_equal '
|
131
|
+
assert_equal 'text', mappings.to_hash[:mytype][:properties][:foo_object][:properties][:bar][:type]
|
142
132
|
assert_nil mappings.to_hash[:mytype][:properties][:foo_object][:fields]
|
143
133
|
|
144
134
|
assert_equal 'nested', mappings.to_hash[:mytype][:properties][:foo_nested][:type]
|
145
|
-
assert_equal '
|
135
|
+
assert_equal 'text', mappings.to_hash[:mytype][:properties][:foo_nested][:properties][:bar][:type]
|
146
136
|
assert_nil mappings.to_hash[:mytype][:properties][:foo_nested][:fields]
|
147
137
|
|
148
138
|
assert_equal :nested, mappings.to_hash[:mytype][:properties][:foo_nested_as_symbol][:type]
|
@@ -538,6 +528,27 @@ class Elasticsearch::Model::IndexingTest < Test::Unit::TestCase
|
|
538
528
|
assert_nothing_raised { DummyIndexingModelForRecreate.create_index! }
|
539
529
|
end
|
540
530
|
|
531
|
+
should "get the index settings and mappings from options" do
|
532
|
+
client = stub('client')
|
533
|
+
indices = stub('indices')
|
534
|
+
client.stubs(:indices).returns(indices)
|
535
|
+
|
536
|
+
indices.expects(:create).with do |payload|
|
537
|
+
assert_equal 'foobar', payload[:index]
|
538
|
+
assert_equal 3, payload[:body][:settings][:index][:number_of_shards]
|
539
|
+
assert_equal 'bar', payload[:body][:mappings][:foobar][:properties][:foo][:analyzer]
|
540
|
+
true
|
541
|
+
end.returns({})
|
542
|
+
|
543
|
+
DummyIndexingModelForRecreate.expects(:index_exists?).returns(false)
|
544
|
+
DummyIndexingModelForRecreate.expects(:client).returns(client).at_least_once
|
545
|
+
|
546
|
+
DummyIndexingModelForRecreate.create_index! \
|
547
|
+
index: 'foobar',
|
548
|
+
settings: { index: { number_of_shards: 3 } },
|
549
|
+
mappings: { foobar: { properties: { foo: { analyzer: 'bar' } } } }
|
550
|
+
end
|
551
|
+
|
541
552
|
should "not create the index when it exists" do
|
542
553
|
client = stub('client')
|
543
554
|
indices = stub('indices')
|
data/test/unit/response_test.rb
CHANGED
@@ -27,7 +27,7 @@ class Elasticsearch::Model::ResponseTest < Test::Unit::TestCase
|
|
27
27
|
assert_equal 'OK', response.shards.one
|
28
28
|
end
|
29
29
|
|
30
|
-
should "wrap the raw Hash response in
|
30
|
+
should "wrap the raw Hash response in a HashWrapper" do
|
31
31
|
@search = Elasticsearch::Model::Searching::SearchRequest.new OriginClass, '*'
|
32
32
|
@search.stubs(:execute!).returns({'hits' => { 'hits' => [] }, 'aggregations' => { 'dates' => 'FOO' }})
|
33
33
|
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticsearch-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karel Minarik
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: elasticsearch
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -337,6 +337,7 @@ files:
|
|
337
337
|
- examples/activerecord_article.rb
|
338
338
|
- examples/activerecord_associations.rb
|
339
339
|
- examples/activerecord_mapping_completion.rb
|
340
|
+
- examples/activerecord_mapping_edge_ngram.rb
|
340
341
|
- examples/couchbase_article.rb
|
341
342
|
- examples/datamapper_article.rb
|
342
343
|
- examples/mongoid_article.rb
|
@@ -354,6 +355,7 @@ files:
|
|
354
355
|
- lib/elasticsearch/model/callbacks.rb
|
355
356
|
- lib/elasticsearch/model/client.rb
|
356
357
|
- lib/elasticsearch/model/ext/active_record.rb
|
358
|
+
- lib/elasticsearch/model/hash_wrapper.rb
|
357
359
|
- lib/elasticsearch/model/importing.rb
|
358
360
|
- lib/elasticsearch/model/indexing.rb
|
359
361
|
- lib/elasticsearch/model/multimodel.rb
|
@@ -370,7 +372,7 @@ files:
|
|
370
372
|
- lib/elasticsearch/model/searching.rb
|
371
373
|
- lib/elasticsearch/model/serializing.rb
|
372
374
|
- lib/elasticsearch/model/version.rb
|
373
|
-
- test/integration/
|
375
|
+
- test/integration/active_record_associations_parent_child_test.rb
|
374
376
|
- test/integration/active_record_associations_test.rb
|
375
377
|
- test/integration/active_record_basic_test.rb
|
376
378
|
- test/integration/active_record_custom_serialization_test.rb
|
@@ -390,6 +392,7 @@ files:
|
|
390
392
|
- test/unit/adapter_test.rb
|
391
393
|
- test/unit/callbacks_test.rb
|
392
394
|
- test/unit/client_test.rb
|
395
|
+
- test/unit/hash_wrapper_test.rb
|
393
396
|
- test/unit/importing_test.rb
|
394
397
|
- test/unit/indexing_test.rb
|
395
398
|
- test/unit/module_test.rb
|
@@ -434,7 +437,7 @@ signing_key:
|
|
434
437
|
specification_version: 4
|
435
438
|
summary: ActiveModel/Record integrations for Elasticsearch.
|
436
439
|
test_files:
|
437
|
-
- test/integration/
|
440
|
+
- test/integration/active_record_associations_parent_child_test.rb
|
438
441
|
- test/integration/active_record_associations_test.rb
|
439
442
|
- test/integration/active_record_basic_test.rb
|
440
443
|
- test/integration/active_record_custom_serialization_test.rb
|
@@ -454,6 +457,7 @@ test_files:
|
|
454
457
|
- test/unit/adapter_test.rb
|
455
458
|
- test/unit/callbacks_test.rb
|
456
459
|
- test/unit/client_test.rb
|
460
|
+
- test/unit/hash_wrapper_test.rb
|
457
461
|
- test/unit/importing_test.rb
|
458
462
|
- test/unit/indexing_test.rb
|
459
463
|
- test/unit/module_test.rb
|