esse 0.0.2
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 +12 -0
- data/.rubocop.yml +128 -0
- data/CHANGELOG.md +0 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +60 -0
- data/LICENSE.txt +21 -0
- data/README.md +50 -0
- data/Rakefile +4 -0
- data/bin/console +22 -0
- data/bin/setup +8 -0
- data/esse.gemspec +39 -0
- data/exec/esse +9 -0
- data/lib/esse.rb +7 -0
- data/lib/esse/backend/index.rb +38 -0
- data/lib/esse/backend/index/aliases.rb +69 -0
- data/lib/esse/backend/index/create.rb +56 -0
- data/lib/esse/backend/index/delete.rb +38 -0
- data/lib/esse/backend/index/documents.rb +23 -0
- data/lib/esse/backend/index/existance.rb +23 -0
- data/lib/esse/backend/index/update.rb +19 -0
- data/lib/esse/backend/index_type.rb +32 -0
- data/lib/esse/backend/index_type/documents.rb +203 -0
- data/lib/esse/cli.rb +29 -0
- data/lib/esse/cli/base.rb +11 -0
- data/lib/esse/cli/generate.rb +51 -0
- data/lib/esse/cli/index.rb +14 -0
- data/lib/esse/cli/templates/index.rb.erb +59 -0
- data/lib/esse/cli/templates/mappings.json +6 -0
- data/lib/esse/cli/templates/serializer.rb.erb +14 -0
- data/lib/esse/cluster.rb +58 -0
- data/lib/esse/config.rb +73 -0
- data/lib/esse/core.rb +89 -0
- data/lib/esse/index.rb +21 -0
- data/lib/esse/index/actions.rb +10 -0
- data/lib/esse/index/backend.rb +13 -0
- data/lib/esse/index/base.rb +118 -0
- data/lib/esse/index/descendants.rb +17 -0
- data/lib/esse/index/inheritance.rb +18 -0
- data/lib/esse/index/mappings.rb +47 -0
- data/lib/esse/index/naming.rb +64 -0
- data/lib/esse/index/settings.rb +48 -0
- data/lib/esse/index/type.rb +31 -0
- data/lib/esse/index_mapping.rb +38 -0
- data/lib/esse/index_setting.rb +41 -0
- data/lib/esse/index_type.rb +10 -0
- data/lib/esse/index_type/actions.rb +11 -0
- data/lib/esse/index_type/backend.rb +13 -0
- data/lib/esse/index_type/mappings.rb +42 -0
- data/lib/esse/index_type/serializer.rb +87 -0
- data/lib/esse/primitives.rb +3 -0
- data/lib/esse/primitives/hstring.rb +85 -0
- data/lib/esse/template_loader.rb +46 -0
- data/lib/esse/types/mapping.rb +0 -0
- data/lib/esse/version.rb +5 -0
- metadata +215 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
module Backend
|
5
|
+
class Index
|
6
|
+
module InstanceMethods
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
alias: true,
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
# Creates index and applies mappings and settings.
|
12
|
+
#
|
13
|
+
# UsersIndex.backend.create # creates index named `<prefix_>users_<suffix|index_version|timestamp>`
|
14
|
+
#
|
15
|
+
# @param options [Hash] Options hash
|
16
|
+
# @option options [Boolean] :alias Update `index_name` alias along with the new index
|
17
|
+
# @option options [String] :suffix The index suffix. Defaults to the `IndexClass#index_version` or
|
18
|
+
# `Esse.timestamp`. Suffixed index names might be used for zero-downtime mapping change.
|
19
|
+
# @return [Hash, false] the elasticsearch response or false in case of unsuccessful creation.
|
20
|
+
#
|
21
|
+
# @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
|
22
|
+
def create(suffix: nil, **options)
|
23
|
+
create!(suffix: suffix, **options)
|
24
|
+
rescue Elasticsearch::Transport::Transport::Errors::BadRequest
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
# Creates index and applies mappings and settings.
|
29
|
+
#
|
30
|
+
# UsersIndex.backend.create! # creates index named `<prefix_>users_<suffix|index_version|timestamp>`
|
31
|
+
#
|
32
|
+
# @param options [Hash] Options hash
|
33
|
+
# @option options [Boolean] :alias Update `index_name` alias along with the new index
|
34
|
+
# @option options [String] :suffix The index suffix. Defaults to the `IndexClass#index_version` or
|
35
|
+
# `Esse.timestamp`. Suffixed index names might be used for zero-downtime mapping change.
|
36
|
+
# @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when index already exists
|
37
|
+
# @return [Hash] the elasticsearch response
|
38
|
+
#
|
39
|
+
# @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
|
40
|
+
def create!(suffix: nil, **options)
|
41
|
+
options = DEFAULT_OPTIONS.merge(options)
|
42
|
+
name = real_index_name(suffix)
|
43
|
+
definition = [settings_hash, mappings_hash].reduce(&:merge)
|
44
|
+
|
45
|
+
if options[:alias] && name != index_name
|
46
|
+
definition[:aliases] = { index_name => {} }
|
47
|
+
end
|
48
|
+
|
49
|
+
client.indices.create(index: name, body: definition)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
include InstanceMethods
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
module Backend
|
5
|
+
class Index
|
6
|
+
module InstanceMethods
|
7
|
+
# Deletes ES index
|
8
|
+
#
|
9
|
+
# UsersIndex.backend.delete! # deletes `<prefix_>users<_suffix|_index_version|_timestamp>` index
|
10
|
+
#
|
11
|
+
# @param options [Hash] Options hash
|
12
|
+
# @option [String, nil] :suffix The index suffix Use nil if you want to delete the current index.
|
13
|
+
# @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when index does not exists
|
14
|
+
# @return [Hash] elasticsearch response
|
15
|
+
def delete!(suffix:)
|
16
|
+
name = suffix ? real_index_name(suffix) : index_name
|
17
|
+
|
18
|
+
client.indices.delete(index: name)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Deletes ES index
|
22
|
+
#
|
23
|
+
# UsersIndex.backend.delete # deletes `<prefix_>users<_suffix|_index_version|_timestamp>` index
|
24
|
+
#
|
25
|
+
# @param options [Hash] Options hash
|
26
|
+
# @option [String] :suffix The index suffix. Use nil if you want to delete the current index.
|
27
|
+
# @return [Hash, false] elasticsearch response, of false in case of error.
|
28
|
+
def delete(suffix: index_version)
|
29
|
+
delete!(suffix: suffix)
|
30
|
+
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
include InstanceMethods
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
module Backend
|
5
|
+
class Index
|
6
|
+
module InstanceMethods
|
7
|
+
def import!(**options)
|
8
|
+
type_hash.each_value do |type|
|
9
|
+
type.backend.import!(**options)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def import(**options)
|
14
|
+
type_hash.each_value do |type|
|
15
|
+
type.backend.import(**options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
include InstanceMethods
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
module Backend
|
5
|
+
class Index
|
6
|
+
module InstanceMethods
|
7
|
+
# Checks the index existance. Returns true or false
|
8
|
+
#
|
9
|
+
# UsersIndex.backend.exist? #=> true
|
10
|
+
#
|
11
|
+
# @param options [Hash] Options hash
|
12
|
+
# @option options [String, nil] :suffix The index suffix. Defaults to the index_version.
|
13
|
+
# Use nil if you want to check existence of the `index_name` index or alias.
|
14
|
+
def exist?(suffix: index_version)
|
15
|
+
name = suffix ? real_index_name(suffix) : index_name
|
16
|
+
client.indices.exists(index: name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
include InstanceMethods
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
module Backend
|
5
|
+
class Index
|
6
|
+
module InstanceMethods
|
7
|
+
def update_mapping!(**options)
|
8
|
+
# @TODO
|
9
|
+
end
|
10
|
+
|
11
|
+
def update_settings!(**options)
|
12
|
+
# @TODO
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
include InstanceMethods
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Esse
|
6
|
+
module Backend
|
7
|
+
class IndexType
|
8
|
+
require_relative 'index_type/documents'
|
9
|
+
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
# Type delegators
|
13
|
+
def_delegators :@index_type, :type_name, :each_serialized_batch, :serialize
|
14
|
+
# Index delegators
|
15
|
+
def_delegators :index_class, :index_name
|
16
|
+
|
17
|
+
def initialize(type)
|
18
|
+
@index_type = type
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def index_class
|
24
|
+
@index_type.index
|
25
|
+
end
|
26
|
+
|
27
|
+
def client
|
28
|
+
index_class.cluster.client
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
module Backend
|
5
|
+
class IndexType
|
6
|
+
module InstanceMethods
|
7
|
+
# Resolve collection and index data
|
8
|
+
#
|
9
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
10
|
+
# @option [Hash] :context The collection context. This value will be passed as argument to the collection
|
11
|
+
# May be SQL condition or any other filter you have defined on the collection.
|
12
|
+
def import(context: {}, **options)
|
13
|
+
each_serialized_batch(context || {}) do |batch|
|
14
|
+
bulk(index: batch, **options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
alias import! import
|
18
|
+
|
19
|
+
# Performs multiple indexing or delete operations in a single API call.
|
20
|
+
# This reduces overhead and can greatly increase indexing speed.
|
21
|
+
#
|
22
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
23
|
+
# @param options [Array] :index list of serialized documents to be indexed(Optional)
|
24
|
+
# @param options [Array] :delete list of serialized documents to be deleted(Optional)
|
25
|
+
# @param options [Array] :create list of serialized documents to be created(Optional)
|
26
|
+
# @return [Hash, nil] the elasticsearch response or nil if there is no data.
|
27
|
+
#
|
28
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-bulk.html
|
29
|
+
def bulk(index: nil, delete: nil, create: nil, **options)
|
30
|
+
body = []
|
31
|
+
Array(index).each do |entry|
|
32
|
+
id, data = Esse.doc_id!(entry)
|
33
|
+
body << { index: { _id: id, data: data } } if id
|
34
|
+
end
|
35
|
+
Array(create).each do |entry|
|
36
|
+
id, data = Esse.doc_id!(entry)
|
37
|
+
body << { create: { _id: id, data: data } } if id
|
38
|
+
end
|
39
|
+
Array(delete).each do |entry|
|
40
|
+
id, _data = Esse.doc_id!(entry, delete: [], keep: %w[_id id])
|
41
|
+
body << { delete: { _id: id } } if id
|
42
|
+
end
|
43
|
+
|
44
|
+
return if body.empty?
|
45
|
+
|
46
|
+
definition = {
|
47
|
+
index: index_name,
|
48
|
+
type: type_name,
|
49
|
+
body: body,
|
50
|
+
}.merge(options)
|
51
|
+
|
52
|
+
client.bulk(definition)
|
53
|
+
end
|
54
|
+
alias bulk! bulk
|
55
|
+
|
56
|
+
# Adds a JSON document to the specified index and makes it searchable. If the document
|
57
|
+
# already exists, updates the document and increments its version.
|
58
|
+
#
|
59
|
+
# UsersIndex::User.index(id: 1, body: { name: 'name' }) # { '_id' => 1, ...}
|
60
|
+
#
|
61
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
62
|
+
# @param options [String, Integer] :id The `_id` of the elasticsearch document
|
63
|
+
# @param options [Hash] :body The JSON document that will be indexed (Required)
|
64
|
+
# @return [Hash] the elasticsearch response Hash
|
65
|
+
#
|
66
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-index_.html
|
67
|
+
def index(id:, body:, **options)
|
68
|
+
client.index(
|
69
|
+
options.merge(index: index_name, type: type_name, id: id, body: body),
|
70
|
+
)
|
71
|
+
end
|
72
|
+
alias index! index
|
73
|
+
|
74
|
+
# Updates a document using the specified script.
|
75
|
+
#
|
76
|
+
# UsersIndex::User.update!(id: 1, body: { doc: { ... } }) # { '_id' => 1, ...}
|
77
|
+
#
|
78
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
79
|
+
# @param options [String, Integer] :id The `_id` of the elasticsearch document
|
80
|
+
# @param options [Hash] :body the body of the request
|
81
|
+
# @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when the doc does not exist
|
82
|
+
# @return [Hash] elasticsearch response hash
|
83
|
+
#
|
84
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-update.html
|
85
|
+
def update!(id:, body:, **options)
|
86
|
+
client.update(
|
87
|
+
options.merge(index: index_name, type: type_name, id: id, body: body),
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Updates a document using the specified script.
|
92
|
+
#
|
93
|
+
# UsersIndex::User.update(id: 1, body: { doc: { ... } }) # { '_id' => 1, ...}
|
94
|
+
#
|
95
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
96
|
+
# @param options [String, Integer] :id The `_id` of the elasticsearch document
|
97
|
+
# @param options [Hash] :body the body of the request
|
98
|
+
# @return [Hash, false] the elasticsearch response hash, or false in case of failure
|
99
|
+
#
|
100
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-update.html
|
101
|
+
def update(id:, body:, **options)
|
102
|
+
update!(id: id, body: body, **options)
|
103
|
+
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
104
|
+
false
|
105
|
+
end
|
106
|
+
|
107
|
+
# Removes a JSON document from the specified index.
|
108
|
+
#
|
109
|
+
# UsersIndex::User.delete!(id: 1) # true
|
110
|
+
# UsersIndex::User.delete!(id: 'missing') # raise Elasticsearch::Transport::Transport::Errors::NotFound
|
111
|
+
#
|
112
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
113
|
+
# @param options [String, Integer] :id The `_id` of the elasticsearch document
|
114
|
+
# @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when the doc does not exist
|
115
|
+
# @return [Boolean] true when the operation is successfully completed
|
116
|
+
#
|
117
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-delete.html
|
118
|
+
def delete!(id:, **options)
|
119
|
+
client.delete(options.merge(index: index_name, type: type_name, id: id))
|
120
|
+
end
|
121
|
+
|
122
|
+
# Removes a JSON document from the specified index.
|
123
|
+
#
|
124
|
+
# UsersIndex::User.delete(id: 1) # true
|
125
|
+
# UsersIndex::User.delete(id: 'missing') # false
|
126
|
+
#
|
127
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
128
|
+
# @param options [String, Integer] :id The `_id` of the elasticsearch document
|
129
|
+
# @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when the doc does not exist
|
130
|
+
# @return [Boolean] true when the operation is successfully completed
|
131
|
+
#
|
132
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-delete.html
|
133
|
+
def delete(id:, **options)
|
134
|
+
delete!(id: id, **options)
|
135
|
+
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
136
|
+
false
|
137
|
+
end
|
138
|
+
|
139
|
+
# Gets the number of matches for a search query.
|
140
|
+
#
|
141
|
+
# UsersIndex::User.count # 999
|
142
|
+
# UsersIndex::User.count(body: { ... }) # 32
|
143
|
+
#
|
144
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
145
|
+
# @param options [Hash] :body A query to restrict the results specified with the Query DSL (optional)
|
146
|
+
# @return [Integer] amount of documents found
|
147
|
+
#
|
148
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/search-count.html
|
149
|
+
def count(**options)
|
150
|
+
response = client.count(options.merge(index: index_name, type: type_name))
|
151
|
+
response['count']
|
152
|
+
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
153
|
+
0
|
154
|
+
end
|
155
|
+
|
156
|
+
# Check if a JSON document exists
|
157
|
+
#
|
158
|
+
# UsersIndex::User.exist?(id: 1) # true
|
159
|
+
# UsersIndex::User.exist?(id: 'missing') # false
|
160
|
+
#
|
161
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
162
|
+
# @param options [String, Integer] :id The `_id` of the elasticsearch document
|
163
|
+
# @return [Boolean] true if the document exists
|
164
|
+
def exist?(id:, **options)
|
165
|
+
client.exists(options.merge(index: index_name, type: type_name, id: id))
|
166
|
+
end
|
167
|
+
|
168
|
+
# Retrieves the specified JSON document from an index.
|
169
|
+
#
|
170
|
+
# UsersIndex::User.find!(id: 1) # { '_id' => 1, ... }
|
171
|
+
# UsersIndex::User.find!(id: 'missing') # raise Elasticsearch::Transport::Transport::Errors::NotFound
|
172
|
+
#
|
173
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
174
|
+
# @param options [String, Integer] :id The `_id` of the elasticsearch document
|
175
|
+
# @raise [Elasticsearch::Transport::Transport::Errors::NotFound] when the doc does not exist
|
176
|
+
# @return [Hash] The elasticsearch document.
|
177
|
+
#
|
178
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-get.html
|
179
|
+
def find!(id:, **options)
|
180
|
+
client.get(options.merge(index: index_name, type: type_name, id: id))
|
181
|
+
end
|
182
|
+
|
183
|
+
# Retrieves the specified JSON document from an index.
|
184
|
+
#
|
185
|
+
# UsersIndex::User.find(id: 1) # { '_id' => 1, ... }
|
186
|
+
# UsersIndex::User.find(id: 'missing') # nil
|
187
|
+
#
|
188
|
+
# @param options [Hash] Hash of paramenters that will be passed along to elasticsearch request
|
189
|
+
# @param options [String, Integer] :id The `_id` of the elasticsearch document
|
190
|
+
# @return [Hash, nil] The elasticsearch document
|
191
|
+
#
|
192
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-get.html
|
193
|
+
def find(id:, **options)
|
194
|
+
find!(id: id, **options)
|
195
|
+
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
196
|
+
nil
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
include InstanceMethods
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
data/lib/esse/cli.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
require_relative 'cli/index'
|
6
|
+
require_relative 'cli/generate'
|
7
|
+
|
8
|
+
module Esse
|
9
|
+
module CLI
|
10
|
+
def self.start(*args)
|
11
|
+
Root.start(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
class Root < Thor
|
15
|
+
map %w[--version -v] => :version
|
16
|
+
|
17
|
+
desc 'index SUBCOMMAND ...ARGS', 'Manage indices'
|
18
|
+
subcommand 'index', Index
|
19
|
+
|
20
|
+
desc 'generate SUBCOMMAND ...ARGS', 'Run generators'
|
21
|
+
subcommand 'generate', Generate
|
22
|
+
|
23
|
+
desc '--version, -v', 'Show package version'
|
24
|
+
def version
|
25
|
+
puts format('Esse version: %<version>s', version: Esse::VERSION)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|