elastic_record 4.1.8 → 5.1.0
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 +5 -5
- data/.travis.yml +15 -8
- data/Gemfile +1 -1
- data/README.md +29 -21
- data/elastic_record.gemspec +1 -1
- data/lib/elastic_record.rb +25 -13
- data/lib/elastic_record/aggregation_response/aggregation.rb +19 -0
- data/lib/elastic_record/aggregation_response/bucket.rb +24 -0
- data/lib/elastic_record/aggregation_response/builder.rb +55 -0
- data/lib/elastic_record/aggregation_response/has_aggregations.rb +9 -0
- data/lib/elastic_record/aggregation_response/multi_bucket_aggregation.rb +9 -0
- data/lib/elastic_record/aggregation_response/multi_value_aggregation.rb +6 -0
- data/lib/elastic_record/aggregation_response/single_bucket_aggregation.rb +8 -0
- data/lib/elastic_record/aggregation_response/single_value_aggregation.rb +7 -0
- data/lib/elastic_record/as_document.rb +33 -16
- data/lib/elastic_record/callbacks.rb +1 -1
- data/lib/elastic_record/config.rb +3 -0
- data/lib/elastic_record/connection.rb +4 -4
- data/lib/elastic_record/errors.rb +7 -1
- data/lib/elastic_record/index.rb +6 -8
- data/lib/elastic_record/index/analyze.rb +10 -0
- data/lib/elastic_record/index/deferred.rb +2 -2
- data/lib/elastic_record/index/documents.rb +42 -29
- data/lib/elastic_record/index/manage.rb +6 -8
- data/lib/elastic_record/index/mapping.rb +16 -8
- data/lib/elastic_record/index/mapping_type.rb +16 -0
- data/lib/elastic_record/index/mapping_type_test.rb +18 -0
- data/lib/elastic_record/index/settings.rb +6 -17
- data/lib/elastic_record/model.rb +2 -14
- data/lib/elastic_record/percolator_model.rb +11 -19
- data/lib/elastic_record/relation.rb +9 -30
- data/lib/elastic_record/relation/batches.rb +5 -3
- data/lib/elastic_record/relation/delegation.rb +8 -4
- data/lib/elastic_record/relation/finder_methods.rb +8 -0
- data/lib/elastic_record/relation/hits.rb +34 -0
- data/lib/elastic_record/relation/search_methods.rb +17 -22
- data/lib/elastic_record/relation/value_methods.rb +1 -1
- data/test/dummy/app/models/project.rb +16 -4
- data/test/dummy/app/models/warehouse.rb +5 -16
- data/test/dummy/app/models/widget.rb +23 -12
- data/test/dummy/app/models/widget_query.rb +1 -0
- data/test/dummy/db/migrate/20151211225259_create_warehouses.rb +7 -0
- data/test/dummy/db/migrate/20180215140125_create_widgets.rb +11 -0
- data/test/dummy/db/schema.rb +10 -3
- data/test/elastic_record/aggregation_response/bucket_test.rb +8 -0
- data/test/elastic_record/aggregation_response/multi_bucket_aggregation_test.rb +33 -0
- data/test/elastic_record/aggregation_response/single_bucket_aggregation_test.rb +15 -0
- data/test/elastic_record/as_document_test.rb +55 -29
- data/test/elastic_record/callbacks_test.rb +7 -11
- data/test/elastic_record/connection_test.rb +3 -16
- data/test/elastic_record/index/documents_test.rb +56 -11
- data/test/elastic_record/index/manage_test.rb +0 -7
- data/test/elastic_record/index/mapping_test.rb +18 -5
- data/test/elastic_record/index/settings_test.rb +1 -7
- data/test/elastic_record/index_test.rb +0 -4
- data/test/elastic_record/integration/active_record_test.rb +6 -9
- data/test/elastic_record/model_test.rb +5 -2
- data/test/elastic_record/percolator_model_test.rb +25 -11
- data/test/elastic_record/relation/batches_test.rb +29 -47
- data/test/elastic_record/relation/delegation_test.rb +1 -1
- data/test/elastic_record/relation/finder_methods_test.rb +17 -31
- data/test/elastic_record/relation/hits_test.rb +49 -0
- data/test/elastic_record/relation/search_methods_test.rb +20 -16
- data/test/elastic_record/relation_test.rb +19 -50
- data/test/helper.rb +7 -3
- metadata +20 -9
- data/lib/elastic_record/doctype.rb +0 -43
- data/lib/elastic_record/json.rb +0 -29
- data/lib/elastic_record/name_cache.rb +0 -23
- data/test/dummy/db/migrate/20151211225259_create_projects.rb +0 -7
- data/test/elastic_record/doctype_test.rb +0 -45
- data/test/elastic_record/name_cache_test.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bb2dad78eb2851499ca2b7099f7774d79c375b5a180001bd612113353dfba33c
|
4
|
+
data.tar.gz: ff1262c6527d45f1e9b0e8eb46e24dc881cdb10b5cb51b93e40f72f5a2f366dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1c4fab2b261935713156c78ebf2fd675a7a7b107ac5a415a25dd20c8364690492f566d82b4685e9c223818abafbaf21ef2083d89ad3ad1e2a60bb93ed150685
|
7
|
+
data.tar.gz: 8f9d7ad4d081fe9096c65872c8b0e4fd0c2d4a3fa2df79bd7a8a8a3975fd7a7055c48b664a5f47beb2b7fcea07020e542f64b4f64e188c125e66c27ee11ad70f
|
data/.travis.yml
CHANGED
@@ -2,17 +2,24 @@ rvm: 2.4.1
|
|
2
2
|
cache: bundler
|
3
3
|
sudo: false
|
4
4
|
dist: trusty
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
|
6
|
+
before_install:
|
7
|
+
- wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${ES_VERSION}.tar.gz
|
8
|
+
- tar -xzf elasticsearch-${ES_VERSION}.tar.gz
|
9
|
+
- ./elasticsearch-${ES_VERSION}/bin/elasticsearch -d
|
10
|
+
|
11
11
|
before_script:
|
12
12
|
- cp test/dummy/.env.example test/dummy/.env
|
13
|
-
-
|
13
|
+
- wget --quiet --waitretry=1 --retry-connrefused --timeout=20 -O - http://127.0.0.1:9200
|
14
14
|
- bundle exec rake app:db:setup
|
15
15
|
- bundle exec rake app:index:reset
|
16
|
+
|
17
|
+
env:
|
18
|
+
global:
|
19
|
+
- ES_VERSION=6.2.3
|
20
|
+
|
16
21
|
services:
|
17
|
-
- elasticsearch
|
18
22
|
- postgresql
|
23
|
+
|
24
|
+
addons:
|
25
|
+
postgresql: 9.6
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
[](http://travis-ci.org/data-axle/elastic_record)
|
3
3
|
[](https://codeclimate.com/github/data-axle/elastic_record)
|
4
4
|
|
5
|
-
ElasticRecord is an Elasticsearch
|
5
|
+
ElasticRecord is an Elasticsearch 6.x ORM.
|
6
6
|
|
7
7
|
## Setup ##
|
8
8
|
|
@@ -68,9 +68,6 @@ search.filter(Product.arelastic[:name].prefix("Sca").negate)
|
|
68
68
|
|
69
69
|
# Size is greater than 5
|
70
70
|
search.filter(Product.arelastic[:size].gt(5))
|
71
|
-
|
72
|
-
# Name is 'hola' or name is missing
|
73
|
-
search.filter(Product.arelastic[:name].eq("hola").or(Product.arelastic[:name].missing))
|
74
71
|
```
|
75
72
|
|
76
73
|
Helpful Arel builders can be found at https://github.com/matthuhiggins/arelastic/blob/master/lib/arelastic/builders/filter.rb.
|
@@ -113,12 +110,11 @@ Aggregations are added with the aggregate method:
|
|
113
110
|
search.aggregate('popular_colors' => {'terms' => {'field' => 'color'}})
|
114
111
|
```
|
115
112
|
|
116
|
-
|
113
|
+
Results are retrieved at query time within `aggregations`:
|
117
114
|
|
118
115
|
```ruby
|
119
116
|
search = search.aggregate('popular_colors' => {'terms' => {'field' => 'color'}})
|
120
|
-
search.aggregations
|
121
|
-
#=> {"popular_colors" => {"buckets" => ...}}
|
117
|
+
search.aggregations['popular_colors'].buckets
|
122
118
|
```
|
123
119
|
|
124
120
|
### Getting Results ###
|
@@ -180,12 +176,14 @@ Use the `percolate` method to find records with queries that match.
|
|
180
176
|
|
181
177
|
## Index Configuration
|
182
178
|
|
183
|
-
To avoid elasticsearch dynamically mapping fields, you can directly configure
|
184
|
-
and
|
179
|
+
To avoid elasticsearch dynamically mapping fields, you can directly configure `elastic_index.mapping`
|
180
|
+
and `elastic_index.settings`:
|
185
181
|
|
186
182
|
```ruby
|
187
183
|
class Product
|
188
|
-
|
184
|
+
include ElasticRecord::Model
|
185
|
+
|
186
|
+
elastic_index.mapping = {
|
189
187
|
properties: {
|
190
188
|
name: {type: "text"},
|
191
189
|
status: {type: "keyword"}
|
@@ -194,6 +192,27 @@ class Product
|
|
194
192
|
end
|
195
193
|
```
|
196
194
|
|
195
|
+
Mapping types will be removed in ElasticSearch 7.x. To rename the default mapping type (`_doc`), use `elastic_index.mapping_type`:
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
class Product
|
199
|
+
include ElasticRecord::Model
|
200
|
+
|
201
|
+
elastic_index.mapping_type = 'product'
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
### Inheritance
|
206
|
+
|
207
|
+
When one model inherits from another, ElasticRecord makes some assumptions about how the child index should be configured. By default:
|
208
|
+
|
209
|
+
* `alias_name` - Same as parent
|
210
|
+
* `mapping` - Same as parent
|
211
|
+
* `mapping_type` - Same as parent
|
212
|
+
* `settings` (including analysis configuration) - Same as parent
|
213
|
+
|
214
|
+
These can all be overridden. For instance, it might be desirable for the child documents to be in a separate index.
|
215
|
+
|
197
216
|
### Load Documents from Source
|
198
217
|
|
199
218
|
To fetch documents without an additional request to a backing ActiveRecord database you can load the documents from `_source`.
|
@@ -242,14 +261,3 @@ Product.elastic_index.reset # Delete related indexes and deploy a n
|
|
242
261
|
Product.elastic_index.refresh # Call the refresh API
|
243
262
|
Product.elastic_index.get_mapping # Get the index mapping defined by elastic search
|
244
263
|
```
|
245
|
-
|
246
|
-
## JSON Adapter ##
|
247
|
-
|
248
|
-
By default, ElasticRecord uses ActiveSupport::JSON to serialize Elasticsearch payloads. There
|
249
|
-
is optional support for using the Oj gem. To use Oj, ensure that oj is required and set:
|
250
|
-
|
251
|
-
```ruby
|
252
|
-
ElasticRecord::JSON.parser = :oj
|
253
|
-
```
|
254
|
-
|
255
|
-
To return to the default parser, set the variable to :active_support.
|
data/elastic_record.gemspec
CHANGED
data/lib/elastic_record.rb
CHANGED
@@ -3,19 +3,31 @@ require 'active_support/concern'
|
|
3
3
|
require 'active_model'
|
4
4
|
|
5
5
|
module ElasticRecord
|
6
|
-
|
7
|
-
autoload :
|
8
|
-
autoload :
|
9
|
-
autoload :
|
10
|
-
autoload :
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :Lucene
|
14
|
-
autoload :Model
|
15
|
-
autoload :
|
16
|
-
autoload :
|
17
|
-
autoload :
|
18
|
-
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
autoload :AsDocument
|
8
|
+
autoload :Callbacks
|
9
|
+
autoload :Config
|
10
|
+
autoload :Connection
|
11
|
+
autoload :Doctype
|
12
|
+
autoload :Index
|
13
|
+
autoload :Lucene
|
14
|
+
autoload :Model
|
15
|
+
autoload :PercolatorModel
|
16
|
+
autoload :Relation
|
17
|
+
autoload :Searching
|
18
|
+
|
19
|
+
module AggregationResponse
|
20
|
+
extend ActiveSupport::Autoload
|
21
|
+
|
22
|
+
autoload :Aggregation
|
23
|
+
autoload :Bucket
|
24
|
+
autoload :Builder
|
25
|
+
autoload :HasAggregations
|
26
|
+
autoload :MultiBucketAggregation
|
27
|
+
autoload :MultiValueAggregation
|
28
|
+
autoload :SingleBucketAggregation
|
29
|
+
autoload :SingleValueAggregation
|
30
|
+
end
|
19
31
|
|
20
32
|
class << self
|
21
33
|
def configure
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ElasticRecord
|
2
|
+
module AggregationResponse
|
3
|
+
class Aggregation
|
4
|
+
attr_accessor :name, :results, :meta
|
5
|
+
def initialize(name, results)
|
6
|
+
@name = name
|
7
|
+
@results = results
|
8
|
+
|
9
|
+
@results.each do |key, value|
|
10
|
+
send("#{key}=", value) if respond_to?("#{key}=")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
"#<#{self.class} #{results}>"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ElasticRecord
|
2
|
+
module AggregationResponse
|
3
|
+
class Bucket
|
4
|
+
include HasAggregations
|
5
|
+
|
6
|
+
attr_accessor :results
|
7
|
+
def initialize(results)
|
8
|
+
@results = results
|
9
|
+
end
|
10
|
+
|
11
|
+
def key
|
12
|
+
results['key']
|
13
|
+
end
|
14
|
+
|
15
|
+
def doc_count
|
16
|
+
results['doc_count']
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
"#<#{self.class} #{results}>"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ElasticRecord
|
2
|
+
module AggregationResponse
|
3
|
+
class Builder
|
4
|
+
AGGREGATION_KLASSES = {
|
5
|
+
SingleBucketAggregation => %w(
|
6
|
+
children
|
7
|
+
sampler
|
8
|
+
filter
|
9
|
+
missing
|
10
|
+
nested
|
11
|
+
reverse_nested
|
12
|
+
global
|
13
|
+
),
|
14
|
+
MultiBucketAggregation => %w(
|
15
|
+
composite
|
16
|
+
date_histogram
|
17
|
+
filters
|
18
|
+
geohash_grid
|
19
|
+
histogram
|
20
|
+
range
|
21
|
+
dterms
|
22
|
+
lterms
|
23
|
+
sterms
|
24
|
+
),
|
25
|
+
SingleValueAggregation => %w(
|
26
|
+
avg
|
27
|
+
cardinality
|
28
|
+
max
|
29
|
+
min
|
30
|
+
value_count
|
31
|
+
),
|
32
|
+
MultiValueAggregation => %w(
|
33
|
+
stats
|
34
|
+
dpercentiles
|
35
|
+
lpercentiles
|
36
|
+
spercentiles
|
37
|
+
)
|
38
|
+
}
|
39
|
+
|
40
|
+
AGGREGATIONS_BY_TYPE = AGGREGATION_KLASSES.each_with_object({}) do |(klass, types), hash|
|
41
|
+
types.each { |type| hash[type] = klass }
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.extract(hash)
|
45
|
+
hash.each_with_object({}) do |(key, results), aggs|
|
46
|
+
next unless key.include?('#')
|
47
|
+
|
48
|
+
type, name = key.split('#')
|
49
|
+
klass = AGGREGATIONS_BY_TYPE.fetch(type)
|
50
|
+
aggs[name] = klass.new(name, results)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module ElasticRecord
|
2
2
|
module AsDocument
|
3
|
-
def as_search_document
|
4
|
-
|
5
|
-
value =
|
3
|
+
def as_search_document(mapping_properties = elastic_index.mapping[:properties])
|
4
|
+
mapping_properties.each_with_object({}) do |(field, mapping), result|
|
5
|
+
value = value_for_elastic_search field, mapping, mapping_properties
|
6
6
|
|
7
7
|
unless value.nil?
|
8
8
|
result[field] = value
|
@@ -11,31 +11,48 @@ module ElasticRecord
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def as_partial_update_document
|
14
|
-
|
14
|
+
mapping_properties = elastic_index.mapping[:properties]
|
15
|
+
changed_fields = respond_to?(:saved_changes) ? saved_changes.keys : changed
|
15
16
|
|
16
|
-
|
17
|
-
if field_mapping =
|
18
|
-
result[field] =
|
17
|
+
changed_fields.each_with_object({}) do |field, result|
|
18
|
+
if field_mapping = mapping_properties[field]
|
19
|
+
result[field] = value_for_elastic_search field, field_mapping, mapping_properties
|
19
20
|
end
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
|
-
def
|
24
|
+
def value_for_elastic_search(field, mapping, mapping_properties)
|
24
25
|
value = try field
|
25
26
|
return if value.nil?
|
26
27
|
|
27
|
-
value =
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
value =
|
29
|
+
case mapping[:type]&.to_sym
|
30
|
+
when :object
|
31
|
+
object_mapping_properties = mapping_properties.dig(field, :properties)
|
32
|
+
value_for_elastic_search_object(value, object_mapping_properties)
|
33
|
+
when :nested
|
34
|
+
object_mapping_properties = mapping_properties.dig(field, :properties)
|
35
|
+
value.map { |entry| value_for_elastic_search_object(entry, object_mapping_properties) }
|
36
|
+
when :integer_range, :float_range, :long_range, :double_range, :date_range
|
37
|
+
value_for_elastic_search_range(value)
|
38
|
+
else
|
39
|
+
value
|
40
|
+
end
|
35
41
|
|
36
42
|
if value.present? || value == false
|
37
43
|
value
|
38
44
|
end
|
39
45
|
end
|
46
|
+
|
47
|
+
def value_for_elastic_search_object(object, nested_mapping)
|
48
|
+
object.respond_to?(:as_search_document) ? object.as_search_document(nested_mapping) : object
|
49
|
+
end
|
50
|
+
|
51
|
+
def value_for_elastic_search_range(range)
|
52
|
+
gte = range.begin unless range.begin == -Float::INFINITY
|
53
|
+
lte = range.end unless range.end == Float::INFINITY
|
54
|
+
|
55
|
+
{'gte' => gte, 'lte' => lte}
|
56
|
+
end
|
40
57
|
end
|
41
58
|
end
|
@@ -5,7 +5,7 @@ module ElasticRecord
|
|
5
5
|
|
6
6
|
base.class_eval do
|
7
7
|
after_create :create_index_document
|
8
|
-
after_update :update_index_document, if: :changed?
|
8
|
+
after_update :update_index_document, if: -> { respond_to?(:saved_changes?) ? saved_changes? : changed? }
|
9
9
|
after_destroy :delete_index_document
|
10
10
|
end
|
11
11
|
end
|